Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions

View File

@ -0,0 +1,53 @@
#include "main.h"
#include "Process.h"
int ProcessReplayGain::Open(int _mode)
{
mode=_mode;
if (mode != RG_INDIVIDUAL_TRACKS
&& mode != RG_ALBUM)
return RG_MODE_NOT_SUPPORTED;
context=CreateRG();
if (!context)
return RG_FAILURE;
StartRG(context);
return RG_SUCCESS;
}
int ProcessReplayGain::ProcessTrack(const wchar_t *filename)
{
int killSwitch=0;
RGWorkFile workFile(filename);
CalculateRG(context, workFile.filename, workFile.track_gain, workFile.track_peak, 0, &killSwitch, albumPeak);
queue.push_back(workFile);
return RG_SUCCESS;
}
int ProcessReplayGain::Write()
{
if (mode == RG_ALBUM)
{
wchar_t album_gain[64]=L"", album_peak[64]=L"";
CalculateAlbumRG(context, album_gain, album_peak, albumPeak);
CopyAlbumData(queue, album_gain, album_peak);
}
WriteAlbum(queue);
return RG_SUCCESS;
}
void ProcessReplayGain::Close()
{
DestroyRG(context);
}
#define CBCLASS ProcessReplayGain
START_DISPATCH;
CB(OBJ_REPLAYGAIN_OPEN, Open)
CB(OBJ_REPLAYGAIN_PROCESSTRACK, ProcessTrack)
CB(OBJ_REPLAYGAIN_WRITE, Write)
VCB(OBJ_REPLAYGAIN_CLOSE,Close)
END_DISPATCH;

View File

@ -0,0 +1,25 @@
#ifndef NULLSOFT_ML_RG_PROCESS_H
#define NULLSOFT_ML_RG_PROCESS_H
#include "obj_replaygain.h"
//this class is meant for use as a service
class ProcessReplayGain : public obj_replaygain
{
public:
ProcessReplayGain() : context(0), albumPeak(0), mode(RG_INDIVIDUAL_TRACKS) {}
int Open(int mode);
int ProcessTrack(const wchar_t *filename);
int Write();
void Close();
protected:
RECVS_DISPATCH;
void *context;
int mode;
float albumPeak;
WorkQueue::RGWorkQueue queue;
};
#endif

View File

@ -0,0 +1,261 @@
#include "main.h"
#include "resource.h"
#include"api__ml_rg.h"
#include <strsafe.h>
struct Progress
{
Progress()
{
processedFiles = 0;
currentBytes = 0;
totalBytes = 0;
activeHWND = 0;
threadHandle = 0;
openDialogs = 0;
done = false;
killSwitch = 0;
}
size_t processedFiles;
uint64_t currentBytes;
uint32_t totalBytes;
WorkQueue activeQueue;
HWND activeHWND;
HANDLE threadHandle;
size_t openDialogs;
bool done;
int killSwitch;
};
DWORD WINAPI ThreadProc(void *param)
{
Progress *progress = (Progress *)param;
ProgressCallback callback(progress->activeHWND);
progress->activeQueue.Calculate(&callback, &progress->killSwitch);
PostMessage(progress->activeHWND, WM_USER + 2, 0, 0);
return 0;
}
void getViewport(RECT *r, HWND wnd, int full, RECT *sr)
{
POINT *p = NULL;
if (p || sr || wnd)
{
HMONITOR hm = NULL;
if (sr)
hm = MonitorFromRect(sr, MONITOR_DEFAULTTONEAREST);
else if (wnd)
hm = MonitorFromWindow(wnd, MONITOR_DEFAULTTONEAREST);
else if (p)
hm = MonitorFromPoint(*p, MONITOR_DEFAULTTONEAREST);
if (hm)
{
MONITORINFOEXW mi;
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(hm, &mi))
{
if (!full)
*r = mi.rcWork;
else
*r = mi.rcMonitor;
return ;
}
}
}
if (full)
{ // this might be borked =)
r->top = r->left = 0;
r->right = GetSystemMetrics(SM_CXSCREEN);
r->bottom = GetSystemMetrics(SM_CYSCREEN);
}
else
{
SystemParametersInfoW(SPI_GETWORKAREA, 0, r, 0);
}
}
BOOL windowOffScreen(HWND hwnd, POINT pt)
{
RECT r = {0}, wnd = {0}, sr = {0};
GetWindowRect(hwnd, &wnd);
sr.left = pt.x;
sr.top = pt.y;
sr.right = sr.left + (wnd.right - wnd.left);
sr.bottom = sr.top + (wnd.bottom - wnd.top);
getViewport(&r, hwnd, 0, &sr);
return !PtInRect(&r, pt);
}
void SaveWindowPos(HWND hwnd)
{
RECT rect = {0};
GetWindowRect(hwnd, &rect);
char buf[16] = {0};
StringCchPrintfA(buf, 16, "%d", rect.left);
WritePrivateProfileStringA("ml_rg", "prog_x", buf, iniFile);
StringCchPrintfA(buf, 16, "%d", rect.top);
WritePrivateProfileStringA("ml_rg", "prog_y", buf, iniFile);
}
INT_PTR WINAPI ReplayGainProgressProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
Progress *progress = (Progress *)lParam;
progress->killSwitch = 0;
progress->done = false;
progress->openDialogs = 0;
progress->processedFiles = 0;
progress->activeHWND = hwndDlg;
wchar_t dummy[64] = {0};
StringCchPrintfW(dummy, 64, WASABI_API_LNGSTRINGW(IDS_1_OF_X_FILES), progress->activeQueue.totalFiles);
SetDlgItemTextW(hwndDlg, IDC_PROGRESS_FILES, dummy);
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)progress);
DWORD threadId;
progress->threadHandle = CreateThread(NULL, 0, ThreadProc, (void *)progress, CREATE_SUSPENDED, &threadId);
SetThreadPriority(progress->threadHandle, THREAD_PRIORITY_IDLE);
ResumeThread(progress->threadHandle);
POINT pt = {(LONG)GetPrivateProfileIntA("ml_rg", "prog_x", -1, iniFile),
(LONG)GetPrivateProfileIntA("ml_rg", "prog_y", -1, iniFile)};
if (!windowOffScreen(hwndDlg, pt))
SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
else
ShowWindow(hwndDlg, SW_SHOW);
}
break;
case WM_DESTROY:
{
SaveWindowPos(hwndDlg);
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
CloseHandle(progress->threadHandle);
progress->activeHWND = 0;
delete progress;
}
break;
case WM_USER: // file finished
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
progress->processedFiles++;
if (progress->processedFiles + 1 > progress->activeQueue.totalFiles)
SetDlgItemTextW(hwndDlg, IDC_PROGRESS_FILES, WASABI_API_LNGSTRINGW(IDS_FINISHED));
else
{
wchar_t dummy[64] = {0};
StringCchPrintfW(dummy, 64,
WASABI_API_LNGSTRINGW(IDS_X_OF_X_FILES),
progress->processedFiles + 1, progress->activeQueue.totalFiles);
SetDlgItemTextW(hwndDlg, IDC_PROGRESS_FILES, dummy);
}
}
break;
case WM_USER + 1: // album done
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
WorkQueue::RGWorkQueue *queue = (WorkQueue::RGWorkQueue *)lParam;
SaveWindowPos(hwndDlg);
if (config_ask && config_ask_each_album)
{
progress->openDialogs++;
DoResults(*queue);
progress->openDialogs--;
if (!progress->openDialogs && progress->done)
DestroyWindow(hwndDlg);
}
else if (config_ask == 0)
{
WriteAlbum(*queue);
}
}
break;
case WM_USER + 2: // all tracks done
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
ShowWindow(hwndDlg, SW_HIDE);
SaveWindowPos(hwndDlg);
if (config_ask && config_ask_each_album == 0)
{
DoResults(progress->activeQueue);
}
progress->killSwitch = 1;
WaitForSingleObject(progress->threadHandle, INFINITE);
progress->done = true;
if (!progress->openDialogs)
DestroyWindow(hwndDlg);
}
break;
case WM_USER + 3: // total bytes of current file
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
progress->currentBytes = 0;
progress->totalBytes = (uint32_t)lParam;
if (progress->totalBytes == 0)
{
SetDlgItemTextW(hwndDlg, IDC_FILE_PROGRESS, WASABI_API_LNGSTRINGW(IDS_PROCESSING));
}
else
{
wchar_t dummy[64] = {0};
StringCchPrintfW(dummy, 64, L"%u%%", (progress->currentBytes * 100) / progress->totalBytes);
SetDlgItemTextW(hwndDlg, IDC_FILE_PROGRESS, dummy);
}
}
break;
case WM_USER + 4: // more bytes read
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
progress->currentBytes += lParam;
if (progress->totalBytes == 0)
{
SetDlgItemTextW(hwndDlg, IDC_FILE_PROGRESS, WASABI_API_LNGSTRINGW(IDS_PROCESSING));
}
else
{
wchar_t dummy[64] = {0};
StringCchPrintfW(dummy, 64, L"%u%%", (progress->currentBytes * 100) / progress->totalBytes);
SetDlgItemTextW(hwndDlg, IDC_FILE_PROGRESS, dummy);
}
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
{
Progress *progress = (Progress *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
progress->killSwitch = 1;
break;
}
}
break;
}
return 0;
}
void DoProgress(WorkQueue &workQueue)
{
Progress *progress = new Progress;
progress->activeQueue = workQueue; // this is a huge slow copy, but I don't care at the moment
WASABI_API_CREATEDIALOGPARAMW(IDD_PROGRESS, GetDialogBoxParent(), ReplayGainProgressProc, (LPARAM)progress);
}
HWND GetDialogBoxParent()
{
HWND parent = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
if (!parent || parent == (HWND)1)
return plugin.hwndWinampParent;
return parent;
}

View File

@ -0,0 +1,67 @@
#include "main.h"
#include "RGFactory.h"
#include "Process.h"
static const char serviceName[] = "Replay Gain Processor";
FOURCC RGFactory::GetServiceType()
{
return WaSvc::OBJECT;
}
const char *RGFactory::GetServiceName()
{
return serviceName;
}
GUID RGFactory::GetGUID()
{
return RGGUID;
}
void *RGFactory::GetInterface(int global_lock)
{
obj_replaygain *ifc=new ProcessReplayGain;
// if (global_lock)
// plugin.service->service_lock(this, (void *)ifc);
return ifc;
}
int RGFactory::SupportNonLockingInterface()
{
return 1;
}
int RGFactory::ReleaseInterface(void *ifc)
{
//plugin.service->service_unlock(ifc);
obj_replaygain *api_ = static_cast<obj_replaygain *>(ifc);
ProcessReplayGain *svc_ = static_cast<ProcessReplayGain *>(api_);
delete svc_;
return 1;
}
const char *RGFactory::GetTestString()
{
return 0;
}
int RGFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS RGFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;

View File

@ -0,0 +1,24 @@
#ifndef NULLSOFT_RG_FACTORY_H
#define NULLSOFT_RG_FACTORY_H
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class RGFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
const char *GetServiceName();
GUID GetGUID();
void *GetInterface(int global_lock);
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
protected:
RECVS_DISPATCH;
};
#endif

View File

@ -0,0 +1,172 @@
#include "main.h"
#include "resource.h"
#include "../nu/listview.h"
#include "api__ml_rg.h"
#include <shlwapi.h>
#include <strsafe.h>
// this isn't nice but it localises the values for display as they're saved in "C" locale
enum { GAIN_MODE=0, PEAK_MODE };
wchar_t* LocaliseNumericText(wchar_t str[64], int mode){
static wchar_t tmp[64];
double value;
tmp[0]=0;
value = _wtof_l(str,WASABI_API_LNG->Get_C_NumericLocale());
StringCchPrintfW(tmp,64,(mode==GAIN_MODE?L"%-+.2f dB":L"%-.9f"),value);
return tmp;
}
static void AddQueueToListView(W_ListView *listView, WorkQueue::RGWorkQueue *queue)
{
int i=listView->GetCount();
for(WorkQueue::RGWorkQueue::iterator itr = queue->begin(); itr!= queue->end(); itr++)
{
listView->InsertItem(i, PathFindFileNameW(itr->filename), (int)&*itr);
listView->SetItemText(i, 1, LocaliseNumericText(itr->track_gain,GAIN_MODE));
listView->SetItemText(i, 2, LocaliseNumericText(itr->track_peak,PEAK_MODE));
listView->SetItemText(i, 3, LocaliseNumericText(itr->album_gain,GAIN_MODE));
listView->SetItemText(i, 4, LocaliseNumericText(itr->album_peak,PEAK_MODE));
i++;
}
}
INT_PTR WINAPI ReplayGainDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
{
W_ListView listView(GetDlgItem(hwndDlg, IDC_RGLIST));
listView.setwnd(GetDlgItem(hwndDlg, IDC_RGLIST));
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_FILENAME), 200);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_TRACK_GAIN), 65);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_TRACK_PEAK), 80);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_ALBUM_GAIN), 65);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_ALBUM_PEAK), 80);
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
WorkQueue::RGWorkQueue *queue = (WorkQueue::RGWorkQueue *)lParam;
AddQueueToListView(&listView, queue);
POINT pt = {(LONG)GetPrivateProfileIntA("ml_rg", "res_x", -1, iniFile),
(LONG)GetPrivateProfileIntA("ml_rg", "res_y", -1, iniFile)};
if (!windowOffScreen(hwndDlg, pt))
SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
{
WorkQueue::RGWorkQueue *queue = (WorkQueue::RGWorkQueue *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
WriteAlbum(*queue);
}
case IDCANCEL:
{
RECT rect = {0};
GetWindowRect(hwndDlg, &rect);
char buf[16] = {0};
StringCchPrintfA(buf, 16, "%d", rect.left);
WritePrivateProfileStringA("ml_rg", "res_x", buf, iniFile);
StringCchPrintfA(buf, 16, "%d", rect.top);
WritePrivateProfileStringA("ml_rg", "res_y", buf, iniFile);
EndDialog(hwndDlg, 0);
}
break;
case IDC_SAVETRACK:
{
WorkQueue::RGWorkQueue *queue = (WorkQueue::RGWorkQueue *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
WriteTracks(*queue);
EndDialog(hwndDlg, 0);
}
break;
}
}
return 0;
}
INT_PTR WINAPI ReplayGainDialogProcAll(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
{
W_ListView listView(GetDlgItem(hwndDlg, IDC_RGLIST));
listView.setwnd(GetDlgItem(hwndDlg, IDC_RGLIST));
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_FILENAME), 200);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_TRACK_GAIN), 65);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_TRACK_PEAK), 80);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_ALBUM_GAIN), 65);
listView.AddCol(WASABI_API_LNGSTRINGW(IDS_COL_ALBUM_PEAK), 80);
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
WorkQueue *queue = (WorkQueue *)lParam;
AddQueueToListView(&listView, &queue->unclassified);
for (WorkQueue::AlbumMap::iterator mapItr=queue->albums.begin();mapItr!=queue->albums.end();mapItr++)
{
AddQueueToListView(&listView, &mapItr->second);
}
POINT pt = {(LONG)GetPrivateProfileIntA("ml_rg", "res_x", -1, iniFile),
(LONG)GetPrivateProfileIntA("ml_rg", "res_y", -1, iniFile)};
if (!windowOffScreen(hwndDlg, pt))
SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
{
WorkQueue *queue = (WorkQueue *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
WriteAlbum(queue->unclassified);
for (WorkQueue::AlbumMap::iterator mapItr=queue->albums.begin();mapItr!=queue->albums.end();mapItr++)
{
WriteAlbum(mapItr->second);
}
}
case IDCANCEL:
{
RECT rect = {0};
GetWindowRect(hwndDlg, &rect);
char buf[16] = {0};
StringCchPrintfA(buf, 16, "%d", rect.left);
WritePrivateProfileStringA("ml_rg", "res_x", buf, iniFile);
StringCchPrintfA(buf, 16, "%d", rect.top);
WritePrivateProfileStringA("ml_rg", "res_y", buf, iniFile);
EndDialog(hwndDlg, 0);
}
break;
case IDC_SAVETRACK:
{
WorkQueue *queue = (WorkQueue *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
WriteTracks(queue->unclassified);
for (WorkQueue::AlbumMap::iterator mapItr=queue->albums.begin();mapItr!=queue->albums.end();mapItr++)
{
WriteTracks(mapItr->second);
}
EndDialog(hwndDlg, 0);
}
break;
}
}
return 0;
}
void DoResults(WorkQueue::RGWorkQueue &queue)
{
if (!queue.empty())
WASABI_API_DIALOGBOXPARAM(IDD_RESULTS, GetDialogBoxParent(), ReplayGainDialogProc, (LPARAM)&queue);
}
void DoResults(WorkQueue &queue)
{
WASABI_API_DIALOGBOXPARAM(IDD_RESULTS, GetDialogBoxParent(), ReplayGainDialogProcAll, (LPARAM)&queue);
}

View File

@ -0,0 +1,24 @@
#ifndef NULLSOFT_ML_RG_API_H
#define NULLSOFT_ML_RG_API_H
#include "../Winamp/api_decodefile.h"
extern api_decodefile *decodeFile;
#define AGAVE_API_DECODE decodeFile
#include "api/application/api_application.h"
extern api_application *applicationApi;
#define WASABI_API_APP applicationApi
#include "../playlist/api_playlistmanager.h"
extern api_playlistmanager *playlistManager;
#define AGAVE_API_PLAYLISTMANAGER playlistManager
#include "../Agave/Language/api_language.h"
#include "../Winamp/api_stats.h"
extern api_stats *statsApi;
#define AGAVE_API_STATS statsApi
#include <api/service/waservicefactory.h>
#endif

View File

@ -0,0 +1,52 @@
#include "main.h"
#include "resource.h"
int config_ask=1;
int config_ask_each_album=1;
int config_ignore_gained_album=0;
void DoButtons(HWND hwndDlg)
{
config_ask = IsDlgButtonChecked(hwndDlg, IDC_ASK);
config_ask_each_album = IsDlgButtonChecked(hwndDlg, IDC_ALBUM);
EnableWindow(GetDlgItem(hwndDlg, IDC_ALBUM), config_ask);
EnableWindow(GetDlgItem(hwndDlg, IDC_ALL), config_ask);
}
INT_PTR WINAPI RGConfig(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
CheckDlgButton(hwndDlg, IDC_ASK, config_ask);
if (config_ask_each_album)
CheckDlgButton(hwndDlg, IDC_ALBUM, BST_CHECKED);
else
CheckDlgButton(hwndDlg, IDC_ALL, BST_CHECKED);
DoButtons(hwndDlg);
break;
case WM_DESTROY:
{
config_ask = IsDlgButtonChecked(hwndDlg, IDC_ASK);
config_ask_each_album = IsDlgButtonChecked(hwndDlg, IDC_ALBUM);
WritePrivateProfileStringA("ml_rg", "config_ask", config_ask ? "1" : "0", iniFile);
WritePrivateProfileStringA("ml_rg", "config_ask_each_album", config_ask_each_album ? "1" : "0", iniFile);
break;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, 0);
break;
case IDC_ASK:
case IDC_ALBUM:
case IDC_ALL:
DoButtons(hwndDlg);
break;
}
break;
}
return 0;
}

View File

@ -0,0 +1,146 @@
#ifndef NULLSOFT_ML_RG_MAIN_H
#define NULLSOFT_ML_RG_MAIN_H
#include <windows.h>
#include "../../General/gen_ml/ml.h"
#include <windowsx.h>
#include "../winamp/wa_ipc.h"
#include "../../General/gen_ml/ml.h"
#include "resource.h"
#include <string>
#include <vector>
#include <map>
extern winampMediaLibraryPlugin plugin;
extern char *iniFile;
LRESULT SetFileInfo(const wchar_t *filename, const wchar_t *metadata, const wchar_t *data);
int GetFileInfo(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, int len);
void WriteFileInfo();
void TagUpdated(const wchar_t *filename);
struct RGWorkFile
{
RGWorkFile(const wchar_t *_filename=0)
{
if (_filename)
lstrcpynW(filename, _filename, MAX_PATH);
else
filename[0]=0;
track_gain[0]=0;
track_peak[0]=0;
album_gain[0]=0;
album_peak[0]=0;
}
wchar_t filename[MAX_PATH];
wchar_t track_gain[64];
wchar_t track_peak[64];
wchar_t album_gain[64];
wchar_t album_peak[64];
};
class ProgressCallback;
class WorkQueue
{
public:
WorkQueue() : totalFiles(0){}
void Add(const wchar_t *filename);
void Calculate(ProgressCallback *callback, int *killSwitch);
typedef std::vector<RGWorkFile> RGWorkQueue;
typedef std::map<std::wstring, RGWorkQueue> AlbumMap;
AlbumMap albums;
RGWorkQueue unclassified;
size_t totalFiles;
};
constexpr auto TIME_SPAN_MS = 10;
class ProgressCallback
{
public:
ProgressCallback(HWND _c)
: callback(_c),
totalReceived(0)
{
ticks = GetTickCount64();
}
void InformSize(size_t bytes)
{
if (!PostMessage(callback, WM_USER + 3, 0, bytes))
{
// LOG the error
DWORD e = GetLastError();
}
}
/// <summary>
/// This function may fire an "ERROR_NOT_ENOUGH_QUOTA" 1816 (0x718) error when the limit is hit!
/// Put some throttle here, post message every 10 ms, not each time we receive a progress.
/// </summary>
/// <param name="bytes"></param>
void Progress(size_t bytes)
{
totalReceived += bytes;
ULONGLONG currentTicks = GetTickCount64();
if (currentTicks - ticks >= TIME_SPAN_MS)
{
ticks = currentTicks;
if (!PostMessage(callback, WM_USER + 4, 0, totalReceived))
{
// LOG the error
DWORD e = GetLastError();
}
totalReceived = 0;
}
}
void FileFinished()
{
// notify remaining bytes
if (totalReceived)
{
PostMessage(callback, WM_USER + 4, 0, totalReceived);
totalReceived = 0;
}
if(!PostMessage(callback, WM_USER, 0, 0))
{
// LOG the error
DWORD e = GetLastError();
}
}
void AlbumFinished(WorkQueue::RGWorkQueue *album)
{
if(!PostMessage(callback, WM_USER + 1, 0, (LPARAM)album))
{
// LOG the error
DWORD e = GetLastError();
}
}
HWND callback;
ULONGLONG ticks;
size_t totalReceived;
};
void CopyAlbumData(WorkQueue::RGWorkQueue &workQueue, const wchar_t *album_gain, const wchar_t *album_peak);
void WriteAlbum(WorkQueue::RGWorkQueue &workQueue);
void WriteTracks(WorkQueue::RGWorkQueue &workQueue);
void DoResults(WorkQueue::RGWorkQueue &queue);
void DoResults(WorkQueue &queue);
void DoProgress(WorkQueue &workQueue);
void DestroyRG(void *context);
void *CreateRG();
void CalculateAlbumRG(void *context, wchar_t album_gain[64], wchar_t album_peak[64], float &albumPeak);
void StartRG(void *context);
void CalculateRG(void *context, const wchar_t *filename, wchar_t track_gain[64], wchar_t track_peak[64], ProgressCallback *callback, int *killSwitch, float &albumPeak);
HWND GetDialogBoxParent();
BOOL windowOffScreen(HWND hwnd, POINT pt);
extern int config_ask, config_ask_each_album, config_ignore_gained_album;
INT_PTR WINAPI RGConfig(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
#endif

View File

@ -0,0 +1,28 @@
#include "main.h"
LRESULT SetFileInfo(const wchar_t *filename, const wchar_t *metadata, const wchar_t *data)
{
extendedFileInfoStructW efis = {
filename,
metadata,
data ? data : L"",
data ? (size_t)lstrlenW(data) : 0,
};
return SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_SET_EXTENDED_FILE_INFOW);
}
void WriteFileInfo()
{
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITE_EXTENDED_FILE_INFO);
}
int GetFileInfo(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, int len)
{
extendedFileInfoStructW efis = { filename, metadata, dest, (size_t)len, };
return (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE); //will return 1 if wa2 supports this IPC call
}
void TagUpdated(const wchar_t *filename)
{
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)filename, IPC_FILE_TAG_MAY_HAVE_UPDATEDW);
}

View File

@ -0,0 +1,409 @@
#include "Main.h"
#include "../nu/AutoWideFn.h"
#include "api__ml_rg.h"
//#include <api/service/waservicefactory.h>
#include "RGFactory.h"
#include "../playlist/ifc_playlistloadercallback.h"
#include <strsafe.h>
// wasabi based services for localisation support
api_language *WASABI_API_LNG = 0;
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
int uninstalling = 0;
RGFactory rgFactory;
static DWORD ml_rg_config_ipc;
static BOOL ml_rg_open_prefs;
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if (plugin.service)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
api_t = reinterpret_cast<api_T *>( factory->getInterface() );
}
}
template <class api_T>
void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
{
if (plugin.service && api_t)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
factory->releaseInterface(api_t);
}
api_t = NULL;
}
static int Init();
static void Quit();
static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
#define PLUG_VER L"1.29"
extern "C" winampMediaLibraryPlugin plugin =
{
MLHDR_VER,
"nullsoft(ml_rg.dll)",
Init,
Quit,
PluginMessageProc,
0,
0,
0,
};
api_decodefile *AGAVE_API_DECODE = 0;
api_application *WASABI_API_APP = 0;
api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0;
api_stats *AGAVE_API_STATS = 0;
char *iniFile = 0;
int Init()
{
waServiceFactory *sf = 0;
ServiceBuild( AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID );
ServiceBuild( AGAVE_API_DECODE, decodeFileGUID );
ServiceBuild( WASABI_API_APP, applicationApiServiceGuid );
ServiceBuild( AGAVE_API_STATS, AnonymousStatsGUID );
plugin.service->service_register( &rgFactory );
// loader so that we can get the localisation service api for use
ServiceBuild( WASABI_API_LNG, languageApiGUID );
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG( plugin.hDllInstance, MlReplayGainLangGUID );
static wchar_t szDescription[ 256 ];
StringCchPrintfW( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_NULLSOFT_REPLAY_GAIN_ANALYZER ), PLUG_VER );
plugin.description = (char *)szDescription;
ml_rg_config_ipc = (DWORD)SendMessageA( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "ml_rg_config", IPC_REGISTER_WINAMP_IPCMESSAGE );
iniFile = (char *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETINIFILE );
config_ask = GetPrivateProfileIntA( "ml_rg", "config_ask", config_ask, iniFile );
config_ask_each_album = GetPrivateProfileIntA( "ml_rg", "config_ask_each_album", config_ask_each_album, iniFile );
return ML_INIT_SUCCESS;
}
void Quit()
{
ServiceRelease(decodeFile, decodeFileGUID);
ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
ServiceRelease(WASABI_API_LNG, languageApiGUID);
ServiceRelease(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
ServiceRelease(AGAVE_API_STATS, AnonymousStatsGUID);
plugin.service->service_deregister(&rgFactory);
}
void WorkQueue::Add(const wchar_t *filename)
{
wchar_t album[512] = L"";
// if the user wants to ignore tracks already scanned, check and skip appropriately
if (config_ignore_gained_album && GetFileInfo(filename, L"replaygain_album_gain", album, 256) && album[0] != 0)
return;
GetFileInfo(filename, L"album", album, 256);
if (album[0])
{
RGWorkFile workFile;
lstrcpynW(workFile.filename, filename, MAX_PATH);
albums[album].push_back(workFile);
}
else
{
RGWorkFile workFile;
lstrcpynW(workFile.filename, filename, MAX_PATH);
unclassified.push_back(workFile);
}
totalFiles++;
}
void WriteAlbum(WorkQueue::RGWorkQueue &workQueue)
{
for (WorkQueue::RGWorkQueue::iterator itr = workQueue.begin();itr != workQueue.end();itr++)
{
if (itr->track_gain[0])
SetFileInfo(itr->filename, L"replaygain_track_gain", itr->track_gain);
if (itr->track_peak[0])
SetFileInfo(itr->filename, L"replaygain_track_peak", itr->track_peak);
if (itr->album_gain[0])
SetFileInfo(itr->filename, L"replaygain_album_gain", itr->album_gain);
if (itr->album_peak[0])
SetFileInfo(itr->filename, L"replaygain_album_peak", itr->album_peak);
WriteFileInfo();
if (AGAVE_API_STATS)
AGAVE_API_STATS->IncrementStat(api_stats::REPLAYGAIN_COUNT);
TagUpdated(itr->filename);
}
}
void WriteTracks(WorkQueue::RGWorkQueue &workQueue)
{
for (WorkQueue::RGWorkQueue::iterator itr = workQueue.begin();itr != workQueue.end();itr++)
{
if (itr->track_gain[0])
SetFileInfo(itr->filename, L"replaygain_track_gain", itr->track_gain);
if (itr->track_peak[0])
SetFileInfo(itr->filename, L"replaygain_track_peak", itr->track_peak);
WriteFileInfo();
if (AGAVE_API_STATS)
AGAVE_API_STATS->IncrementStat(api_stats::REPLAYGAIN_COUNT);
TagUpdated(itr->filename);
}
}
void CopyAlbumData(WorkQueue::RGWorkQueue &workQueue, const wchar_t *album_gain, const wchar_t *album_peak)
{
for (WorkQueue::RGWorkQueue::iterator itr = workQueue.begin();itr != workQueue.end();itr++)
{
if (itr->track_gain && itr->track_gain[0]) // if there's no track gain, it's because there was an error!
{
if (album_gain && album_gain[0])
lstrcpynW(itr->album_gain, album_gain, 64);
if (album_peak && album_peak[0])
lstrcpynW(itr->album_peak, album_peak, 64);
}
}
}
void WorkQueue::Calculate(ProgressCallback *callback, int *killSwitch)
{
void *context = CreateRG();
StartRG(context);
float albumPeak = 0;
for (RGWorkQueue::iterator itr = unclassified.begin();itr != unclassified.end();itr++)
{
if (*killSwitch) {DestroyRG(context); return ;}
CalculateRG(context, itr->filename, itr->track_gain, itr->track_peak, callback, killSwitch, albumPeak);
callback->FileFinished();
}
if (*killSwitch) {DestroyRG(context); return ;}
callback->AlbumFinished(&unclassified);
for (AlbumMap::iterator mapItr = albums.begin();mapItr != albums.end();mapItr++)
{
albumPeak = 0;
StartRG(context);
for (RGWorkQueue::iterator itr = mapItr->second.begin();itr != mapItr->second.end();itr++)
{
if (*killSwitch) {DestroyRG(context); return ;}
CalculateRG(context, itr->filename, itr->track_gain, itr->track_peak, callback, killSwitch, albumPeak);
callback->FileFinished();
}
wchar_t album_gain[64] = L"", album_peak[64] = L"";
CalculateAlbumRG(context, album_gain, album_peak, albumPeak);
CopyAlbumData(mapItr->second, album_gain, album_peak);
if (*killSwitch) {DestroyRG(context); return ;}
callback->AlbumFinished(&(mapItr->second));
}
DestroyRG(context);
}
class WorkQueuePlaylistLoader : public ifc_playlistloadercallback
{
public:
WorkQueuePlaylistLoader(WorkQueue *_queue);
void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
protected:
WorkQueue *queue;
RECVS_DISPATCH;
};
WorkQueuePlaylistLoader::WorkQueuePlaylistLoader(WorkQueue *_queue)
{
queue = _queue;
}
void WorkQueuePlaylistLoader::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info)
{
queue->Add(filename);
}
#define CBCLASS WorkQueuePlaylistLoader
START_DISPATCH;
VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
END_DISPATCH;
#undef CBCLASS
INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
{
if (message_type == ML_MSG_ONSENDTOBUILD)
{
if (param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_ITEMRECORDLIST ||
param1 == ML_TYPE_FILENAMES || param1 == ML_TYPE_STREAMNAMES ||
param1 == ML_TYPE_FILENAMESW || param1 == ML_TYPE_STREAMNAMESW ||
(AGAVE_API_PLAYLISTMANAGER && (param1 == ML_TYPE_PLAYLIST || param1 == ML_TYPE_PLAYLISTS)))
{
wchar_t description[512] = {0};
WASABI_API_LNGSTRINGW_BUF(IDS_CALCULATE_REPLAY_GAIN, description, 512);
mlAddToSendToStructW s = {0};
s.context = param2;
s.desc = description;
s.user32 = (INT_PTR)PluginMessageProc;
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&s, ML_IPC_ADDTOSENDTOW);
}
}
else if (message_type == ML_MSG_ONSENDTOSELECT)
{
if (param3 != (INT_PTR)PluginMessageProc) return 0;
INT_PTR type = param1;
INT_PTR data = param2;
if (data)
{
WorkQueue workQueue;
if (type == ML_TYPE_ITEMRECORDLIST)
{
itemRecordList *p = (itemRecordList*)data;
for (int x = 0; x < p->Size; x ++)
{
workQueue.Add(AutoWideFn(p->Items[x].filename));
}
DoProgress(workQueue);
return 1;
}
else if (type == ML_TYPE_ITEMRECORDLISTW)
{
itemRecordListW *p = (itemRecordListW*)data;
for (int x = 0; x < p->Size; x ++)
{
workQueue.Add(p->Items[x].filename);
}
DoProgress(workQueue);
return 1;
}
else if (type == ML_TYPE_FILENAMES || type == ML_TYPE_STREAMNAMES)
{
char *p = (char*)data;
while (p && *p)
{
workQueue.Add(AutoWideFn(p));
p += strlen(p) + 1;
}
DoProgress(workQueue);
return 1;
}
else if (type == ML_TYPE_FILENAMESW || type == ML_TYPE_STREAMNAMESW)
{
wchar_t *p = (wchar_t*)data;
while (p && *p)
{
workQueue.Add(p);
p += wcslen(p) + 1;
}
DoProgress(workQueue);
return 1;
}
else if (type == ML_TYPE_PLAYLIST)
{
mlPlaylist *playlist = (mlPlaylist *)param2;
WorkQueuePlaylistLoader loader(&workQueue);
AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
DoProgress(workQueue);
return 1;
}
else if (type == ML_TYPE_PLAYLISTS)
{
mlPlaylist **playlists = (mlPlaylist **)param2;
WorkQueuePlaylistLoader loader(&workQueue);
while (playlists && *playlists)
{
mlPlaylist *playlist = *playlists;
AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
playlists++;
}
DoProgress(workQueue);
return 1;
}
}
}
else if (message_type == ML_MSG_CONFIG)
{
ml_rg_open_prefs = TRUE;
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 42, IPC_OPENPREFSTOPAGE);
ml_rg_open_prefs = FALSE;
return 1;
}
// this will be sent if we've opened the playback->replay gain prefs page
// so that we can enable the embedded controls and return the RGConfig proc
else if (message_type == ml_rg_config_ipc)
{
// sanity check by winamp.exe to make sure that we're valid
if(!param1)
{
return 1;
}
// return the config dialog proceedure
else if(param1 == 1)
{
return (INT_PTR)RGConfig;
}
// queried when the playback prefs page is opened to see if we [ml_rg] caused it
else if(param1 == 2)
{
if(ml_rg_open_prefs)
{
return TRUE;
}
}
}
return 0;
}
extern "C" {
__declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
{
return &plugin;
}
__declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
uninstalling = 1;
// prompt to remove our settings with default as no (just incase)
if(MessageBoxW(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS),
(wchar_t*)plugin.description,MB_YESNO|MB_DEFBUTTON2) == IDYES)
{
WritePrivateProfileStringA("ml_rg", 0, 0, iniFile);
}
// also attempt to remove the ReplayGainAnalysis.dll so everything is kept cleaner
wchar_t path[MAX_PATH] = {0};
PathCombineW(path, (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETSHAREDDLLDIRECTORYW), L"ReplayGainAnalysis.dll");
// if we get a handle then try to lower the handle count so we can delete
HINSTANCE rgLib = GetModuleHandleW(path);
if(rgLib) {
FreeLibrary(rgLib);
}
DeleteFileW(path);
// allow an on-the-fly removal (since we've got to be with a compatible client build)
return ML_PLUGIN_UNINSTALL_NOW;
}
};

View File

@ -0,0 +1,152 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_RESULTS DIALOGEX 0, 0, 356, 170
STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
CAPTION "Replay Gain Results"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_RGLIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,4,7,348,141
DEFPUSHBUTTON "Save as Album",IDOK,116,153,76,13
PUSHBUTTON "Save Track data",IDC_SAVETRACK,196,153,76,13
PUSHBUTTON "Cancel",IDCANCEL,276,153,76,13
END
IDD_PROGRESS DIALOGEX 0, 0, 186, 63
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Calculating Replay Gain"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "File Progress:",IDC_STATIC,7,7,44,8
LTEXT "Calculating...",IDC_FILE_PROGRESS,63,7,116,8
LTEXT "Total Progress:",IDC_STATIC,7,23,50,8
LTEXT "Calculating...",IDC_PROGRESS_FILES,63,23,116,8
PUSHBUTTON "Abort",IDCANCEL,129,41,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_RESULTS, DIALOG
BEGIN
LEFTMARGIN, 4
RIGHTMARGIN, 352
TOPMARGIN, 7
BOTTOMMARGIN, 166
END
IDD_PROGRESS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 56
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_NULLSOFT_REPLAY_GAIN_ANALYZER "Nullsoft Replay Gain Analyzer v%s"
65535 "{5F633543-148D-48cc-B683-DA82F592CF28}"
END
STRINGTABLE
BEGIN
IDS_CALCULATE_REPLAY_GAIN "Calculate Replay Gain"
IDS_1_OF_X_FILES "1 of %u files"
IDS_FINISHED "Finished."
IDS_X_OF_X_FILES "%u of %u files"
IDS_PROCESSING "Processing..."
IDS_TOO_MANY_CHANNELS "Too many channels, can't deal with this yet"
IDS_REPLAYGAIN "ReplayGain"
IDS_NOT_ABLE_TO_OPEN_RG_DLL "Not able to open ReplayGainAnalysis.dll"
IDS_COL_FILENAME "Filename"
IDS_COL_TRACK_GAIN "Track Gain"
IDS_COL_TRACK_PEAK "Track Peak"
IDS_COL_ALBUM_GAIN "Album Gain"
IDS_COL_ALBUM_PEAK "Album Peak"
IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS
"Do you also want to remove the saved settings for this plug-in?"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,57 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29424.173
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ml_rg", "ml_rg.vcxproj", "{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}"
ProjectSection(ProjectDependencies) = postProject
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D} = {8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReplayGainAnalysis", "..\ReplayGainAnalysis\ReplayGainAnalysis.vcxproj", "{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}"
ProjectSection(ProjectDependencies) = postProject
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Debug|Win32.ActiveCfg = Debug|Win32
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Debug|Win32.Build.0 = Debug|Win32
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Debug|x64.ActiveCfg = Debug|x64
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Debug|x64.Build.0 = Debug|x64
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Release|Win32.ActiveCfg = Release|Win32
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Release|Win32.Build.0 = Release|Win32
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Release|x64.ActiveCfg = Release|x64
{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}.Release|x64.Build.0 = Release|x64
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Debug|Win32.ActiveCfg = Debug|Win32
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Debug|Win32.Build.0 = Debug|Win32
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Debug|x64.ActiveCfg = Debug|x64
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Debug|x64.Build.0 = Debug|x64
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Release|Win32.ActiveCfg = Release|Win32
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Release|Win32.Build.0 = Release|Win32
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Release|x64.ActiveCfg = Release|x64
{8155E1C4-B6F8-4A1D-96A3-E4FF0FE9192D}.Release|x64.Build.0 = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,310 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{F42B3AC8-E719-4AA6-B9EC-1F9BFC799861}</ProjectGuid>
<RootNamespace>ml_rg</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
<EmbedManifest>true</EmbedManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<EmbedManifest>true</EmbedManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
<EmbedManifest>true</EmbedManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<EmbedManifest>true</EmbedManifest>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>false</VcpkgEnableManifest>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_RG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>true</BufferSecurityCheck>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
<ResourceCompile>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Manifest>
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_RG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4311;4302;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<BufferSecurityCheck>true</BufferSecurityCheck>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
<ResourceCompile>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Manifest>
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_RG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
</Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
<ResourceCompile>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Manifest>
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_RG_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<DisableSpecificWarnings>4311;4302;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
</Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
<ResourceCompile>
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Manifest>
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="api__ml_rg.h" />
<ClInclude Include="main.h" />
<ClInclude Include="obj_replaygain.h" />
<ClInclude Include="Process.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="RGFactory.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\nu\listview.cpp" />
<ClCompile Include="config.cpp" />
<ClCompile Include="metadata.cpp" />
<ClCompile Include="ml_rg.cpp" />
<ClCompile Include="Process.cpp" />
<ClCompile Include="Progress.cpp" />
<ClCompile Include="replaygain.cpp" />
<ClCompile Include="Results.cpp" />
<ClCompile Include="RGFactory.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ml_rg.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="metadata.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Process.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Progress.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="replaygain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Results.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RGFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ml_rg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\nu\listview.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="api__ml_rg.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="obj_replaygain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Process.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RGFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{20ba2df7-10e3-42e6-896b-4c0a795e542f}</UniqueIdentifier>
</Filter>
<Filter Include="Ressource Files">
<UniqueIdentifier>{018c7bf8-fe6c-4705-aa4d-c641ffd71994}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{916716df-cad8-4fa2-9a6f-2203f1fbade7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ml_rg.rc">
<Filter>Ressource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,62 @@
#ifndef NULLSOFT_ML_RG_OBJ_REPLAYGAIN_H
#define NULLSOFT_ML_RG_OBJ_REPLAYGAIN_H
#include <bfc/dispatch.h>
enum
{
RG_SUCCESS = 0,
RG_FAILURE = 1,
RG_MODE_NOT_SUPPORTED=2,
RG_INDIVIDUAL_TRACKS = 0, // use this mode to calculate each track sent individually
RG_ALBUM = 1, // use this mode to treat all tracks sent as belonging to the same album
RG_AUTO = 2, // retrieve tags from the files to determine album info
};
class obj_replaygain : public Dispatchable
{
protected:
obj_replaygain() {}
~obj_replaygain() {}
public:
int Open(int mode);
int ProcessTrack(const wchar_t *filename);
int Write();
void Close();
DISPATCH_CODES
{
OBJ_REPLAYGAIN_OPEN = 10,
OBJ_REPLAYGAIN_PROCESSTRACK = 20,
OBJ_REPLAYGAIN_WRITE = 30,
OBJ_REPLAYGAIN_CLOSE = 40,
};
};
inline int obj_replaygain::Open(int mode)
{
return _call(OBJ_REPLAYGAIN_OPEN, (int)RG_FAILURE, mode);
}
inline int obj_replaygain::ProcessTrack(const wchar_t *filename)
{
return _call(OBJ_REPLAYGAIN_PROCESSTRACK, (int)RG_FAILURE, filename);
}
inline int obj_replaygain::Write()
{
return _call(OBJ_REPLAYGAIN_WRITE, (int)RG_FAILURE);
}
inline void obj_replaygain::Close()
{
_voidcall(OBJ_REPLAYGAIN_CLOSE);
}
// {3A398A1B-D316-4094-993E-27EAEA553D19}
static const GUID RGGUID =
{ 0x3a398a1b, 0xd316, 0x4094, { 0x99, 0x3e, 0x27, 0xea, 0xea, 0x55, 0x3d, 0x19 } };
#endif

View File

@ -0,0 +1,370 @@
#include "main.h"
#include <math.h>
#include "../ReplayGainAnalysis/gain_analysis.h"
#include "api__ml_rg.h"
#include <shlwapi.h>
#include <strsafe.h>
#include <locale.h>
#pragma intrinsic(fabs)
static inline float fastmax(float x, float a)
{
x -= a;
x += (float)fabs(x);
x *= 0.5f;
x += a;
return (x);
}
static HMODULE rgLib = 0;
typedef int(*INITGAINANALYSIS)(void *context, long samplefreq);
static INITGAINANALYSIS InitGainAnalysis = 0;
typedef int(*ANALYZESAMPLES)(void *context, const float * left_samples, const float * right_samples, size_t num_samples, int num_channels);
static ANALYZESAMPLES AnalyzeSamples = 0;
typedef int(*RESETSAMPLEFREQUENCY)(void *context, long samplefreq);
static RESETSAMPLEFREQUENCY ResetSampleFrequency = 0;
typedef float(*GETTITLEGAIN)(void *context);
static GETTITLEGAIN GetTitleGain = 0;
typedef float(*GETALBUMGAIN)(void *context);
static GETALBUMGAIN GetAlbumGain = 0;
typedef void *(* CREATERGCONTEXT)();
static CREATERGCONTEXT CreateRGContext = 0;
typedef void(*FREERGCONTEXT)(void *context);
static FREERGCONTEXT FreeRGContext = 0;
void LoadRG()
{
if (rgLib)
return ;
wchar_t path[MAX_PATH] = {0};
PathCombineW(path, (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETSHAREDDLLDIRECTORYW), L"ReplayGainAnalysis.dll");
rgLib = LoadLibraryW(path);
if (rgLib)
{
InitGainAnalysis = (INITGAINANALYSIS)GetProcAddress(rgLib, "WAInitGainAnalysis");
AnalyzeSamples = (ANALYZESAMPLES)GetProcAddress(rgLib, "WAAnalyzeSamples");
GetTitleGain = (GETTITLEGAIN)GetProcAddress(rgLib, "WAGetTitleGain");
ResetSampleFrequency = (RESETSAMPLEFREQUENCY)GetProcAddress(rgLib, "WAResetSampleFrequency");
GetAlbumGain = (GETALBUMGAIN)GetProcAddress(rgLib, "WAGetAlbumGain");
CreateRGContext = (CREATERGCONTEXT)GetProcAddress(rgLib, "WACreateRGContext");
FreeRGContext = (FREERGCONTEXT)GetProcAddress(rgLib, "WAFreeRGContext");
}
}
void *CreateRG()
{
LoadRG();
return CreateRGContext();
}
void DestroyRG(void *context)
{
FreeRGContext(context);
}
#define CHUNKSIZE 16384
static void CalculateRG_float(void *context, ifc_audiostream *decoder, AudioParameters *parameters, wchar_t track_gain[64], wchar_t track_peak[64], ProgressCallback *callback, int *killSwitch, float &albumPeak)
{
float data[2*CHUNKSIZE] = {0};
float right[CHUNKSIZE] = {0};
float peak = 0;
if (parameters->channels > 2)
{
char titleStr[32] = {0};
MessageBoxA(GetDialogBoxParent(),
WASABI_API_LNGSTRING(IDS_TOO_MANY_CHANNELS),
WASABI_API_LNGSTRING_BUF(IDS_REPLAYGAIN,titleStr,32),
MB_OK);
decodeFile->CloseAudio(decoder);
return ;
}
ResetSampleFrequency(context, parameters->sampleRate);
if (callback) callback->InformSize((parameters->sizeBytes == -1) ? 0 : parameters->sizeBytes);
while (1)
{
if (*killSwitch)
{
decodeFile->CloseAudio(decoder);
return ;
}
int error=0;
size_t bytesRead = decoder->ReadAudio((void *)data, sizeof(data), killSwitch, &error);
if (*killSwitch)
{
decodeFile->CloseAudio(decoder);
return ;
}
else if (error)
{
break;
}
if (callback) callback->Progress(bytesRead);
size_t samples = bytesRead / sizeof(*data);
if (!samples)
break;
for (size_t i = 0;i != samples;i++)
{
peak = fastmax(peak, (float)fabs(data[i]));
data[i] *= 32768.0f;
}
albumPeak = fastmax(peak, albumPeak);
if (parameters->channels == 1)
AnalyzeSamples(context, data, NULL, samples, 1);
else
{
size_t samples2 = samples / 2;
for (size_t i = 0;i != samples2;i++)
{
data[i] = data[i * 2];
right[i] = data[i * 2 + 1];
}
AnalyzeSamples(context, data, right, samples2, 2);
}
}
decodeFile->CloseAudio(decoder);
float gain = GetTitleGain(context);
if (gain != GAIN_NOT_ENOUGH_SAMPLES)
{
_locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
_snwprintf_l(track_gain, 64, L"%-+.2f dB", C_locale, gain);
_snwprintf_l(track_peak, 64, L"%-.9f", C_locale, peak);
}
}
static void FillFloat(float *left, float *right, void *samples, size_t bps, size_t numSamples, size_t numChannels, float &peak, float &albumPeak, float gain)
{
switch (bps)
{
case 8:
{
unsigned __int8 *samples8 = (unsigned __int8 *)samples;
size_t t = 0;
for (size_t x = 0; x != numSamples; x ++)
{
left[x] = (float)(samples8[t++] - 128) * 256.0f * gain;
if (numChannels == 2)
{
right[x] = (float)(samples8[t++] - 128) * 256.0f* gain;
}
else
right[x] = left[x];
peak = fastmax(peak, (float)fabs(left[x]));
peak = fastmax(peak, (float)fabs(right[x]));
albumPeak=fastmax(albumPeak, peak);
}
}
break;
case 16:
{
short *samples16 = (short *)samples;
size_t t = 0;
if (numChannels == 1)
{
for (size_t x = 0; x != numSamples; x ++)
{
left[x] = (float)samples16[t++] * gain;
right[x] = left[x];
peak = fastmax(peak, (float)fabs(left[x]));
albumPeak=fastmax(albumPeak, peak);
}
}
else if (numChannels == 2)
{
for (size_t x = 0; x != numSamples; x ++)
{
left[x] = (float)samples16[t++] * gain ;
right[x] = (float)samples16[t++] * gain;
peak = fastmax(peak, (float)fabs(left[x]));
peak = fastmax(peak, (float)fabs(right[x]));
albumPeak=fastmax(albumPeak, peak);
}
}
}
break;
case 24:
{
unsigned __int8 *samples8 = (unsigned __int8 *)samples;
for (size_t x = 0; x != numSamples; x ++)
{
long temp = (((long)samples8[0]) << 8);
temp = temp | (((long)samples8[1]) << 16);
temp = temp | (((long)samples8[2]) << 24);
left[x] = (float)temp* gain / 65536.0f;
samples8 += 3;
if (numChannels == 2)
{
temp = (((long)samples8[0]) << 8);
temp = temp | (((long)samples8[1]) << 16);
temp = temp | (((long)samples8[2]) << 24);
right[x] = (float)temp* gain / 65536.0f;
samples8 += 3;
}
else
right[x] = left[x];
peak = fastmax(peak, (float)fabs(left[x]));
peak = fastmax(peak, (float)fabs(right[x]));
albumPeak=fastmax(albumPeak, peak);
}
}
break;
}
}
#undef CHUNKSIZE
#define CHUNKSIZE 4096
static void CalculateRG_pcm(void *context, ifc_audiostream *decoder, AudioParameters *parameters, wchar_t track_gain[64], wchar_t track_peak[64], ProgressCallback *callback, int *killSwitch, float &albumPeak)
{
char data[4*2*CHUNKSIZE] = {0};
float left[CHUNKSIZE] = {0};
float right[CHUNKSIZE] = {0};
float peak = 0;
if (parameters->channels > 2)
{
char titleStr[32];
MessageBoxA(GetDialogBoxParent(),
WASABI_API_LNGSTRING(IDS_TOO_MANY_CHANNELS),
WASABI_API_LNGSTRING_BUF(IDS_REPLAYGAIN,titleStr,32),
MB_OK);
decodeFile->CloseAudio(decoder);
return ;
}
int padded_bits = (parameters->bitsPerSample + 7) & (~7);
albumPeak *= 32768.0f;
ResetSampleFrequency(context, parameters->sampleRate);
if (callback) callback->InformSize((parameters->sizeBytes == -1) ? 0 : parameters->sizeBytes);
while (1)
{
if (*killSwitch)
{
decodeFile->CloseAudio(decoder);
return ;
}
int error=0;
size_t bytesRead = decoder->ReadAudio((void *)data, 4096 * parameters->channels * (padded_bits / 8), killSwitch, &error);
if (*killSwitch)
{
decodeFile->CloseAudio(decoder);
return ;
}
else if (error)
{
break;
}
if (callback) callback->Progress(bytesRead);
size_t samples = bytesRead / (padded_bits / 8);
if (!samples)
break;
FillFloat(left, right, data, padded_bits, samples / parameters->channels, parameters->channels, peak, albumPeak, (float)pow(2., (double)(padded_bits - parameters->bitsPerSample)));
size_t samples2 = samples / 2;
AnalyzeSamples(context, left, right, samples2, 2);
}
decodeFile->CloseAudio(decoder);
float gain = GetTitleGain(context);
if (gain != GAIN_NOT_ENOUGH_SAMPLES)
{
StringCchPrintfW(track_gain, 64, L"%-+.2f dB", gain);
StringCchPrintfW(track_peak, 64, L"%-.9f", peak / 32768.0f);
}
albumPeak /= 32768.0f;
}
void CalculateRG(void *context, const wchar_t *filename, wchar_t track_gain[64], wchar_t track_peak[64], ProgressCallback *callback, int *killSwitch, float &albumPeak)
{
LoadRG();
if (!rgLib)
{
char titleStr[32] = {0};
MessageBoxA(GetDialogBoxParent(),
WASABI_API_LNGSTRING(IDS_NOT_ABLE_TO_OPEN_RG_DLL),
WASABI_API_LNGSTRING_BUF(IDS_REPLAYGAIN,titleStr,32),
MB_OK);
return ;
}
wchar_t dummy[64] = {0};
if (!GetFileInfo(filename, L"replaygain_track_gain", dummy, 64)) // check if the plugin even supports replaygain
return ;
/*
TODO: want to do something like this, but have to do it on the main thread (ugh)
if (!_wcsnicmp(dummy, "-24601", 6))
{
SetFileInfo(itr->filename, L"replaygain_track_gain", L"");
SetFileInfo(itr->filename, L"replaygain_track_peak", L"");
SetFileInfo(itr->filename, L"replaygain_album_gain", L"");
SetFileInfo(itr->filename, L"replaygain_album_peak", L"");
WriteFileInfo();
}
*/
AudioParameters parameters;
parameters.flags = AUDIOPARAMETERS_FLOAT | AUDIOPARAMETERS_MAXCHANNELS | AUDIOPARAMETERS_MAXSAMPLERATE;
parameters.channels = 2;
parameters.sampleRate = 192000;
ifc_audiostream *decoder = decodeFile->OpenAudioBackground(filename, &parameters);
if (decoder)
CalculateRG_float(context, decoder, &parameters, track_gain, track_peak, callback, killSwitch, albumPeak);
else
{
// try PCM
memset(&parameters, 0, sizeof(AudioParameters));
parameters.flags = AUDIOPARAMETERS_MAXCHANNELS | AUDIOPARAMETERS_MAXSAMPLERATE;
parameters.channels = 2;
parameters.sampleRate = 192000;
ifc_audiostream *decoder = decodeFile->OpenAudioBackground(filename, &parameters);
if (decoder)
CalculateRG_pcm(context, decoder, &parameters, track_gain, track_peak, callback, killSwitch, albumPeak);
}
}
void CalculateAlbumRG(void *context, wchar_t album_gain[64], wchar_t album_peak[64], float &albumPeak)
{
float gain = GetAlbumGain(context);
if (gain != GAIN_NOT_ENOUGH_SAMPLES)
{
/*StringCchPrintfW(album_gain, 64, L"%-+.2f dB", gain);
StringCchPrintfW(album_peak, 64, L"%-.9f", albumPeak);*/
_locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
_snwprintf_l(album_gain, 64, L"%-+.2f dB", C_locale, gain);
_snwprintf_l(album_peak, 64, L"%-.9f", C_locale, albumPeak);
}
}
void StartRG(void *context)
{
LoadRG();
if (!rgLib)
{
char titleStr[32] = {0};
MessageBoxA(GetDialogBoxParent(),
WASABI_API_LNGSTRING(IDS_NOT_ABLE_TO_OPEN_RG_DLL),
WASABI_API_LNGSTRING_BUF(IDS_REPLAYGAIN,titleStr,32),
MB_OK);
return ;
}
InitGainAnalysis(context, 44100); // since this is most common. We'll reset it before doing a real calculation anyway
}

View File

@ -0,0 +1,40 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ml_rg.rc
//
#define IDS_CALCULATE_REPLAY_GAIN 1
#define IDS_1_OF_X_FILES 2
#define IDS_FINISHED 3
#define IDS_X_OF_X_FILES 4
#define IDS_PROCESSING 5
#define IDS_TOO_MANY_CHANNELS 6
#define IDS_REPLAYGAIN 7
#define IDS_NOT_ABLE_TO_OPEN_RG_DLL 8
#define IDS_COL_FILENAME 9
#define IDS_COL_TRACK_GAIN 10
#define IDS_COL_TRACK_PEAK 11
#define IDS_COL_ALBUM_GAIN 12
#define IDS_COL_ALBUM_PEAK 13
#define IDS_STRING14 14
#define IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS 14
#define IDD_RESULTS 101
#define IDD_PROGRESS 102
#define IDC_RGLIST 1001
#define IDC_SAVETRACK 1002
#define IDC_PROGRESS_FILES 1003
#define IDC_FILE_PROGRESS 1004
#define IDC_ASK 1005
#define IDC_ALBUM 1006
#define IDC_ALL 1007
#define IDS_NULLSOFT_REPLAY_GAIN_ANALYZER 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 107
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1008
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#include "../../../Winamp/buildType.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,29,0,0
PRODUCTVERSION WINAMP_PRODUCTVER
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Winamp SA"
VALUE "FileDescription", "Winamp Media Library Plug-in"
VALUE "FileVersion", "1,29,0,0"
VALUE "InternalName", "Nullsoft Replay Gain Analyzer"
VALUE "LegalCopyright", "Copyright <20> 2006-2023 Winamp SA"
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
VALUE "OriginalFilename", "ml_rg.dll"
VALUE "ProductName", "Winamp"
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END