123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- #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, ¶meters);
- if (decoder)
- CalculateRG_float(context, decoder, ¶meters, track_gain, track_peak, callback, killSwitch, albumPeak);
- else
- {
- // try PCM
- memset(¶meters, 0, sizeof(AudioParameters));
- parameters.flags = AUDIOPARAMETERS_MAXCHANNELS | AUDIOPARAMETERS_MAXSAMPLERATE;
- parameters.channels = 2;
- parameters.sampleRate = 192000;
- ifc_audiostream *decoder = decodeFile->OpenAudioBackground(filename, ¶meters);
- if (decoder)
- CalculateRG_pcm(context, decoder, ¶meters, 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
- }
|