#include "Main.h" #include "resource.h" #include #include "api.h" //#define PROFILE_PLUGINS_LOAD_TIME #include "timing.h" #include "../nu/AutoWide.h" #include "../nu/AutoChar.h" #include "../nu/ns_wc.h" #include "WinampAttributes.h" #include "eq10dsp.h" #include "../nsutil/pcm.h" int filter_srate = 0, filter_enabled = 1, filter_top = 0, filter_top2 = 10; static In_Module* dsp_init_mod = 0; static int dsp_in_init = 0; std::vector in_modules; In_Module* in_mod = 0; float preamp_val = 1.0f; eq10_t* eq = 0; extern "C" volatile int sa_override; static void setinfo(int bitrate, int srate, int stereo, int synched); static void vissa_init(int maxlatency_in_ms, int srate); static void vissa_deinit(); static int sa_getmode(); static int eq_dosamples_4front(short* samples, int numsamples, int bps, int nch, int srate); static int eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate); int benskiQ_eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate); static int eq_isactive(); static int myisourfile(const char* filename) // mjf bullshit { return 0; } typedef struct _PLUGINORDER { LPCWSTR name; bool found; } PLUGINORDER; static PLUGINORDER preload[] = { // the one plug-in to rule all { L"in_mp3.dll", false }, // no extension configuration { L"in_avi.dll", false }, { L"in_cdda.dll", false }, { L"in_linein.dll", false }, { L"in_mkv.dll", false }, { L"in_nsv.dll", false }, { L"in_swf.dll", false }, { L"in_vorbis.dll", false }, // extension configuration { L"in_mp4.dll", false }, { L"in_dshow.dll", false }, // load after in_avi and in_mkv as often those extensions are associated with this one as well { L"in_flac.dll", false }, { L"in_flv.dll", false }, { L"in_wm.dll", false }, // tend to have a lot of extensions so do later { L"in_wave.dll", false }, { L"in_midi.dll", false }, { L"in_mod.dll", false } }; static void LoadInputPlugin(const wchar_t* filename) { wchar_t file[MAX_PATH] = { 0 }; PathCombineW(file, PLUGINDIR, filename); HINSTANCE hLib = LoadLibraryW(file); if ( hLib == NULL ) return; In_Module* (*pr)(); pr = (In_Module * (__cdecl*)(void)) GetProcAddress(hLib, "winampGetInModule2"); if ( pr == NULL ) return; In_Module* mod = pr(); if ( mod == NULL ) { FreeModule(hLib); return; } int ver = ((mod->version & ~IN_UNICODE) & ~IN_INIT_RET); if ( !(ver == IN_VER || ver == IN_VER_OLD) ) { FreeModule(hLib); return; } if ( g_safeMode ) { char desc[128] = { 0 }; lstrcpynA(desc, mod->description, sizeof(desc)); if ( desc[0] && !memcmp(desc, "nullsoft(", 9) ) { char* p = strrchr(desc, ')'); if ( p ) { *p = 0; if ( _wcsicmp(filename, AutoWide(desc + 9)) ) { FreeModule(hLib); return; } } } else { FreeModule(hLib); return; } } mod->hDllInstance = hLib; mod->dsp_dosamples = eq_dosamples; mod->dsp_isactive = eq_isactive; mod->SAGetMode = sa_getmode; mod->SAAdd = (int(__cdecl*)(void*, int, int))sa_add; mod->SAVSAInit = vissa_init; mod->SAVSADeInit = vissa_deinit; mod->VSASetInfo = vis_setinfo; mod->VSAAdd = vsa_add; mod->VSAGetMode = vsa_getmode; mod->SAAddPCMData = sa_addpcmdata; mod->VSAAddPCMData = vsa_addpcmdata; mod->hMainWindow = hMainWindow; mod->SetInfo = NULL; mod->UsesOutputPlug &= ~(2 | 4 | 8 | 16); if ( !_wcsicmp(filename, L"in_mjf.dll") ) { mod->IsOurFile = myisourfile; } // add 5.66+ to do better error handling on issues, etc if ( mod->version & IN_INIT_RET ) { mod->service = WASABI_API_SVC; } int ret = mod->Init(); if ( (mod->version & IN_INIT_RET) && (ret == IN_INIT_FAILURE) ) { FreeModule(hLib); return; } in_modules.push_back(mod); if ( mod->SetInfo ) { char* p = (char*)mod->SetInfo; if ( p && *p ) { StringCchCatA(metric_plugin_list, 512, ":"); StringCchCatA(metric_plugin_list, 512, p); } } mod->SetInfo = setinfo; if ( !g_has_video_plugin ) { int (*gefiW)(const wchar_t* fn, const char* data, wchar_t* dest, int destlen); gefiW = (int(__cdecl*)(const wchar_t*, const char*, wchar_t*, int))GetProcAddress(hLib, "winampGetExtendedFileInfoW"); if ( gefiW ) { wchar_t dest[16] = { 0 }; gefiW(L"", "type", dest, 16); if ( _wtoi(dest) == 1 ) g_has_video_plugin = 1; } int (*gefi)(const char* fn, const char* data, char* dest, int destlen); gefi = (int(__cdecl*)(const char*, const char*, char*, int))GetProcAddress(hLib, "winampGetExtendedFileInfo"); if ( gefi ) { char dest[16] = { 0 }; gefi("", "type", dest, 16); if ( atoi(dest) == 1 ) g_has_video_plugin = 1; } } } int in_init() { // input plugins require the main window, at least for IPC calls if ( !CreateMainWindow() ) return FALSE; int i = 0, count = sizeof(preload) / sizeof(PLUGINORDER); for ( ; i < count; i++ ) LoadInputPlugin(preload[i].name); WIN32_FIND_DATAW d = { 0 }; wchar_t dirstr[MAX_PATH] = { 0 }; PathCombineW(dirstr, PLUGINDIR, L"IN_*.DLL"); HANDLE h = FindFirstFileW(dirstr, &d); if ( h != INVALID_HANDLE_VALUE ) { do { for ( i = 0; i < count && (preload[i].found || lstrcmpiW(preload[i].name, d.cFileName)); i++ ); if ( i == count ) LoadInputPlugin(d.cFileName); else preload[i].found = true; } while ( FindNextFileW(h, &d) ); FindClose(h); } if ( (g_no_video_loaded = _r_i("no_video", 0)) ) g_has_video_plugin = 0; return TRUE; } In_Module* g_in_infobox = 0; void in_deinit() { size_t x = in_modules.size(); while ( x-- ) { In_Module*& mod = in_modules[x]; // make sure there's something valid due to the dynamic unload changes in 5.5+ if ( mod != g_in_infobox && mod ) { //HINSTANCE hLib = mod->hDllInstance; mod->Quit(); //FreeLibrary(hLib); // benski> we're just going to let it leak because it might be subclassing mod = 0; } } in_modules.clear(); } In_Module* in_setmod_noplay(const wchar_t* filename, int* start_offs) { size_t x; char ext[128] = { 0 }; extension_ex(AutoChar(filename), ext, sizeof(ext)); for ( x = start_offs ? *start_offs : 0; x < in_modules.size(); x++ ) { if ( InW_IsOurFile(in_modules[x], filename) ) { if ( start_offs ) *start_offs = (int)x; if ( !in_modules[x]->hMainWindow ) in_modules[x]->hMainWindow = hMainWindow; return in_modules[x]; } } for ( x = start_offs ? *start_offs : 0; x < in_modules.size(); x++ ) { if ( in_modules[x] ) { char* allExtension = in_modules[x]->FileExtensions; while ( allExtension && *allExtension ) { char* splitterBuffer = allExtension; char* extensionBuffer; do { // string split on ';' char currentExtension[20] = { 0 }; lstrcpynA(currentExtension, splitterBuffer, 20); if ( (extensionBuffer = strstr(splitterBuffer, ";")) ) { if ( (extensionBuffer - splitterBuffer) < 15 ) currentExtension[extensionBuffer - splitterBuffer] = 0; } //else //d[lstrlen(splitterBuffer)] = 0; if ( !lstrcmpiA(ext, currentExtension) ) { if ( start_offs ) *start_offs = (int)x; if ( !in_modules[x]->hMainWindow ) in_modules[x]->hMainWindow = hMainWindow; return in_modules[x]; } splitterBuffer = extensionBuffer + 1; } while ( extensionBuffer ); allExtension += lstrlenA(allExtension) + 1; if ( !*allExtension ) break; allExtension += lstrlenA(allExtension) + 1; } } } if ( start_offs ) { *start_offs = -1; return 0; } { static int r; const wchar_t* p; if ( PathFindExtensionW(filename)[0] && (p = wcsstr(filename, L"://")) && (p = wcsstr(p, L"?")) ) { wchar_t* d = _wcsdup(filename); In_Module* v; d[p - filename] = 0; v = in_setmod_noplay(d, 0); free(d); return v; } if ( !config_defext[0] || config_defext[0] == ' ' ) StringCchCopyA(config_defext, 32, "mp3"); if ( !r ) { wchar_t a[128] = L"hi."; In_Module* v; MultiByteToWideCharSZ(CP_ACP, 0, config_defext, -1, a + 3, 120); r = 1; v = in_setmod_noplay(a, 0); r = 0; return v; } else return 0; } } In_Module* in_setmod(const wchar_t* filename) { In_Module* i = in_setmod_noplay(filename, 0); if ( !i ) return 0; if ( i->UsesOutputPlug & IN_MODULE_FLAG_USES_OUTPUT_PLUGIN ) { int t; for ( t = 0; out_modules[t] && _stricmp(config_outname, (char*)out_modules[t]->id); t++ ); if ( !out_modules[t] ) { for ( t = 0; out_modules[t]; t++ ) { if ( !_stricmp("out_ds.dll", (char*)out_modules[t]->id) ) { break; } else if ( !_stricmp("out_wave.dll", (char*)out_modules[t]->id) ) { break; } } if ( !out_modules[t] ) { LPMessageBox(DIALOG_PARENT(hMainWindow), IDS_NOOUTPUT, IDS_ERROR, MB_OK | MB_ICONERROR); return (In_Module*)-31337; } } // TODO only call out_changed(..) if we are different from before // though currently changing the output prefs and playing a // new track will generate a change (which is expected but // it might be assumed to be wrong so may need to document) int changed = 0; if ( !i->outMod || i->outMod && i->outMod->hDllInstance != out_modules[t]->hDllInstance ) { changed = 1; if ( i->outMod ) out_changed(i->outMod->hDllInstance, OUT_UNSET | OUT_PLAYBACK); } i->outMod = out_modules[t]; i->outMod->hMainWindow = hMainWindow; if ( changed ) out_changed(i->outMod->hDllInstance, OUT_SET | OUT_PLAYBACK); } else { if ( i->outMod ) out_changed(i->outMod->hDllInstance, OUT_UNSET | OUT_PLAYBACK); i->outMod = NULL; } return i; } void in_flush(int ms) { if ( in_mod && in_mod->outMod ) { in_mod->outMod->Flush(ms); } } int in_getouttime(void) { if ( in_mod ) return in_mod->GetOutputTime(); return 0; } int in_getlength(void) { if ( in_mod ) { int t = in_mod->GetLength() / 1000; if ( t < 1 && t != -1 ) t = 1; return t; } return -1; } void in_pause(int p) { if ( in_mod ) { if ( p ) in_mod->Pause(); else in_mod->UnPause(); } } void in_setvol(int v) { if ( in_mod ) in_mod->SetVolume(v); if ( config_eq_ws && config_eq_open ) draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1)); PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VOLUME, IPC_CB_MISC); //////CefRefPtr l_CefApp = wa_Cef_App::GetInstance(); //////if ( l_CefApp.get() != nullptr ) //////{ ////// l_CefApp.get()->setVolume( v ); //////} } void in_setpan(int p) { if ( in_mod ) in_mod->SetPan(p); if ( config_eq_ws && config_eq_open ) draw_eq_tbar(GetForegroundWindow() == hEQWindow ? 1 : (config_hilite ? 0 : 1)); PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VOLUME, IPC_CB_MISC); } int in_seek(int time_in_ms) { if ( in_mod ) in_mod->SetOutputTime(time_in_ms); return 0; } extern "C" int g_need_trusted_dsp = 0; int in_open(const wchar_t* fn) { in_mod = in_setmod(fn); if ( (int)in_mod <= 0 ) return (!in_mod ? 1 : *(int*)in_mod); sa_setthread(config_sa); in_setvol(config_volume); in_setpan(config_pan); dsp_in_init = 0; dsp_init_mod = in_mod; filter_srate = 0; int r = InW_Play(in_mod, fn); return r; } void in_close(void) { if ( in_mod ) in_mod->Stop(); if ( NULL != eq ) { free(eq); eq = NULL; } timingPrint(); } enum FileInfoMode { FILEINFO_MODE_0, FILEINFO_MODE_1, }; int ModernInfoBox(In_Module* in, FileInfoMode mode, const wchar_t* filename, HWND parent); typedef int(__cdecl* UseUnifiedFileInfoDlg)(const wchar_t* fn); int in_infobox(HWND hwnd, const wchar_t* fn) { const wchar_t* p = wcsstr(fn, L"aol.com/uvox"); if ( p ) return 0; if ( g_in_infobox ) return 0; In_Module* mod = in_setmod_noplay(fn, 0); if ( !mod ) return 0; g_in_infobox = mod; UseUnifiedFileInfoDlg uufid = (UseUnifiedFileInfoDlg)GetProcAddress(mod->hDllInstance, "winampUseUnifiedFileInfoDlg"); // focus often gets reverted back to the main window after this dialog // so we will remember what window used to have focus HWND oldFocus = GetFocus(); int a = 0; int ret = 0; if ( uufid ) { ret = uufid(fn); if ( ret == 1 ) { a = ModernInfoBox(mod, FILEINFO_MODE_0, fn, hwnd); } else if ( ret == 2 ) a = ModernInfoBox(mod, FILEINFO_MODE_1, fn, hwnd); } if ( ret == 0 ) { // added 5.66 so plug-ins can get a hint that something may change... SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)fn, IPC_FILE_TAG_MAY_UPDATEW); a = InW_InfoBox(mod, fn, hwnd); } SetFocus(oldFocus); if ( !a ) { SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)fn, IPC_FILE_TAG_MAY_HAVE_UPDATEDW); } g_in_infobox = 0; return a; } static void AddFilterString(char* p, size_t size, const char* a) { while ( a && *a ) { char* t = 0; StringCchCatExA(p, size, ";*.", &t, &size, 0); t = p + lstrlenA(p); while ( a && *a && *a != ';' ) *t++ = *a++; *t = 0; if ( a ) a++; if ( a && a[-1] ) continue; if ( !*a ) break; if ( a ) a += lstrlenA(a) + 1; } } char* in_getfltstr() { int in_mod = -1; int in_wave = -1; size_t size = 256 * 1024; char* buf = (char*)GlobalAlloc(GPTR, size); // this is gay, should have a growing buffer or somethin. char* p = buf; size_t x; getString(IDS_ALLTYPES, p, size); p = p + lstrlenA(p) + 1; wchar_t playlistString[1024] = { 0 }; playlistManager->GetFilterList(playlistString, 1024); WideCharToMultiByteSZ(CP_ACP, 0, playlistString, -1, p, (int)size, 0, 0); for ( x = 0; x < in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; if ( a && *a ) { /* we want to skip in_mod and in_wave because they have TOO MANY extensions and we are limited to MAX_PATH (260) we'll tack them at the end just in case we have enough room for 'em */ if ( in_mod < 0 && !strncmp(a, "mod;", 4) ) in_mod = (int)x; else if ( in_wave < 0 && strstr(a, "aiff") ) // detection for in_wave. not the best but should work in_wave = (int)x; else AddFilterString(p, size, a); } } /* add in_wave and in_mod last */ if ( in_wave >= 0 ) AddFilterString(p, size, in_modules[in_wave]->FileExtensions); if ( in_mod >= 0 ) // fuck you in_mod :) AddFilterString(p, size, in_modules[in_mod]->FileExtensions); p = p + lstrlenA(p) + 1; getString(IDS_PLAYLISTSTRING, p, size - (p - buf)); p += lstrlenA(p) + 1; playlistManager->GetFilterList(playlistString, 1024); WideCharToMultiByteSZ(CP_ACP, 0, playlistString, -1, p, (int)size, 0, 0); p += lstrlenA(p) + 1; for ( x = 0; x < in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; while ( a && *a ) { char* b = a; a += lstrlenA(a) + 1; if ( !*a ) break; StringCchCopyExA(p, size, a, &p, &size, 0); p++; { do { char* c; StringCchCopyA(p, size, "*."); StringCchCatA(p, size, b); if ( (b = strstr(b, ";")) ) b++; if ( (c = strstr(p, ";")) ) c[1] = 0; p += lstrlenA(p); } while ( b ); p++; a += lstrlenA(a) + 1; } } } StringCchCopyExA(p, size, getString(IDS_OFD_ALL_FILES, NULL, 0), &p, &size, 0); p++; size--; lstrcpynA(p, "*.*", (int)size); p += 3; *p = 0; { char* newbuf; size = p + 5 - buf; newbuf = (char*)GlobalAlloc(GPTR, size); memcpy(newbuf, buf, size); GlobalFree(buf); return newbuf; } } static void AddFilterStringW(wchar_t* p, size_t& size, const char* a, BOOL skip) { while ( a && *a ) { wchar_t* t = 0; StringCchCatExW(p, size, ((*p) ? L";*." : L"*."), &t, &size, 0); size_t extsize = 0; while ( a[extsize] && a[extsize] != ';' ) extsize++; *(t += MultiByteToWideCharSZ(CP_ACP, 0, a, (int)extsize, t, (int)size) - 1); a += extsize + 1; if ( a[-1] ) continue; if ( !*a ) break; a += lstrlenA(a) + 1; // limit the length of the filter to fit into MAX_PATH otherwise // if things go past this then mainly for the all supported type // it can sometimes act like *.* due to where the filter is cut if ( !skip && lstrlenW(p) >= MAX_PATH ) { // if we end with a . then need to fake things to act like a new // filter since windows will interpret the . as a *.* which is bad if ( *(p + MAX_PATH) == L'.' ) { *(p + MAX_PATH - 1) = 0; *(p + MAX_PATH) = 0; } } } } static wchar_t* inc(wchar_t* p, size_t& size, int extra = 0) { int len = lstrlenW(p) + extra; size -= len; p += len; return p; } wchar_t* in_getfltstrW(BOOL skip) { int in_mod = -1; int in_wave = -1; size_t size = 256 * 1024; wchar_t* buf = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t)); // this is gay, should have a growing buffer or somethin. wchar_t* p = buf, * ps; *p = 0; size_t x = 0; { int cnt = lstrlenW(getStringW(IDS_ALLTYPES, buf, size)) + 1; p += cnt; size -= cnt; if ( playlistManager ) { playlistManager->GetExtensionList(p, size); size -= lstrlenW(p); } } ps = p; for ( x = 0; x < in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; if ( a && *a ) { /* we want to skip in_mod and in_wave because they have TOO MANY extensions and we are limited to MAX_PATH (260) we'll tack them at the end just in case we have enough room for 'em */ if ( in_mod < 0 && !strncmp(a, "mod;", 4) ) in_mod = (int)x; else if ( in_wave < 0 && strstr(a, "aiff") ) // detection for in_wave. not the best but should work in_wave = (int)x; else AddFilterStringW(p, size, a, skip); } } /* add in_wave and in_mod last */ if ( in_wave >= 0 ) AddFilterStringW(p, size, in_modules[in_wave]->FileExtensions, skip); if ( in_mod >= 0 ) // fuck you in_mod :) AddFilterStringW(p, size, in_modules[in_mod]->FileExtensions, skip); if ( *p ) p += lstrlenW(p) + 1; // don't decrement size here cause it was done already // uppercase the extensions so is consistent as can be CharUpperBuffW(ps, 256 * 1024 - (p - ps)); if ( playlistManager ) { wchar_t ext[512] = { 0 }; playlistManager->GetExtensionList(ext, 512); StringCchPrintfW(p, size, getStringW(IDS_PLAYLISTSTRING_NEW, NULL, 0), ext); int cnt = lstrlenW(p) + 1; p += cnt; size -= cnt; StringCchCatW(p, size, ext); p = inc(p, size, 1); } for ( x = 0; x < in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; while ( a && *a ) { char* b = a; a += lstrlenA(a) + 1; if ( !*a ) break; // adjust down by 1 so that we have the actual string length exluding null termination int cnt = MultiByteToWideCharSZ(CP_ACP, 0, a, -1, p, (int)size) - 1; p += cnt; size -= cnt; { do { wchar_t* c = 0; StringCchCopyW(p, size, L"*."); StringCchCatW(p, size, AutoWide(b)); if ( (b = strstr(b, ";")) ) b++; if ( (c = wcsstr(p, L";")) ) c[1] = 0; p = inc(p, size); } while ( b ); p++; size--; a += lstrlenA(a) + 1; } } } StringCchCopyExW(p, size, getStringW(IDS_OFD_ALL_FILES, NULL, 0), &p, &size, 0); p++; size--; lstrcpynW(p, L"*.*", (int)size); p += 3; *p = 0; { wchar_t* newbuf = 0; size = p + 5 - buf; newbuf = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t)); memcpy(newbuf, buf, size * sizeof(wchar_t)); GlobalFree(buf); return newbuf; } } char* in_getextlist() { size_t x; char* mem = NULL, * p; int size = 1024; std::vector exts; for ( x = 0; x != in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; while ( a && *a ) { char* b = a, * c = 0; do { c = strstr(b, ";"); if ( c ) { char temp[32] = { 0 }; lstrcpynA(temp, b, c - b + 1); int count = CharUpperBuffA(temp, ARRAYSIZE(temp)); bool skip = false; for ( size_t i = 0; i < exts.size(); i++ ) { if ( !stricmp(exts[i], temp) ) { skip = true; break; } } if ( !skip ) { exts.push_back(_strdup(temp)); size += count + 2; } } else { char temp[32] = { 0 }; lstrcpynA(temp, b, c - b + 1); int count = CharUpperBuffA(temp, ARRAYSIZE(temp)); bool skip = false; for ( size_t i = 0; i < exts.size(); i++ ) { if ( !stricmp(exts[i], temp) ) { skip = true; break; } } if ( !skip ) { exts.push_back(_strdup(temp)); size += count + 2; } } b = c + 1; } while ( c && *c ); a += lstrlenA(a) + 1; if ( !*a ) break; a += lstrlenA(a) + 1; } } if ( size > 0 ) { p = mem = (char*)GlobalAlloc(GPTR, size); for ( x = 0; x != exts.size(); x++ ) { char* e = exts[x]; if ( e && *e ) { lstrcpynA(p, e, 32); p += lstrlenA(p) + 1; free(e); } } *p = 0; } return mem; } wchar_t* in_getextlistW() { size_t x = 0; wchar_t* mem = NULL, * p = 0; int size = 0; std::vector exts; for ( x = 0; x != in_modules.size(); x++ ) { char* a = in_modules[x]->FileExtensions; while ( a && *a ) { char* b = a, * c; do { wchar_t temp[32] = { 0 }; c = strstr(b, ";"); if ( c ) { int count = MultiByteToWideChar(CP_ACP, 0, b, c - b, 0, 0); MultiByteToWideChar(CP_ACP, 0, b, c - b, temp, count); CharUpperBuffW(temp, ARRAYSIZE(temp)); bool skip = false; for ( size_t i = 0; i < exts.size(); i++ ) { if ( !wcsicmp(exts[i], temp) ) { skip = true; break; } } if ( !skip ) { exts.push_back(_wcsdup(temp)); size += count + 2; } } else { int count = MultiByteToWideChar(CP_ACP, 0, b, -1, 0, 0); MultiByteToWideChar(CP_ACP, 0, b, -1, temp, count); CharUpperBuffW(temp, ARRAYSIZE(temp)); bool skip = false; for ( size_t i = 0; i < exts.size(); i++ ) { if ( !wcsicmp(exts[i], temp) ) { skip = true; break; } } if ( !skip ) { exts.push_back(_wcsdup(temp)); size += count + 2; } } b = c + 1; } while ( c && *c ); a += lstrlenA(a) + 1; if ( !*a ) break; a += lstrlenA(a) + 1; } } if ( size > 0 ) { p = mem = (wchar_t*)GlobalAlloc(GPTR, size * sizeof(wchar_t)); for ( x = 0; x != exts.size(); x++ ) { wchar_t* e = exts[x]; if ( e && *e ) { lstrcpynW(p, e, 32); p += lstrlenW(p) + 1; free(e); } } *p = 0; } return mem; } static void vissa_init(int maxlatency_in_ms, int srate) { g_srate_exact = srate; int nf = MulDiv(maxlatency_in_ms * 4, srate, 450000); //int nf = maxlatency_in_ms/5; sa_init(nf); vsa_init(nf); vu_init(nf, srate); } static void vissa_deinit() { sa_deinit(); vsa_deinit(); vu_deinit(); } static void setinfo(int bitrate, int srate, int stereo, int synched) { int last_brate = g_brate, last_srate = g_srate, last_nch = g_nch; if ( stereo != -1 ) { g_nch = stereo; // dynamic channels if ( g_nch > 0 ) { if ( NULL != eq ) { free(eq); eq = NULL; } eq = (eq10_t*)calloc(g_nch, sizeof(eq10_t)); if ( NULL == eq ) { // bad. Need to handle this. g_nch = 0; } eq_set(config_use_eq, (char*)eq_tab, config_preamp); } } if ( bitrate != -1 && srate != -1 ) { g_need_titleupd = 1; } if ( bitrate != -1 ) g_brate = bitrate; if ( srate != -1 ) { g_srate = srate; switch ( srate ) { case 11: g_srate_exact = 11025; break; case 22: g_srate_exact = 22050; break; case 44: g_srate_exact = 44100; break; case 88: g_srate_exact = 88200; break; default: g_srate_exact = srate * 1000; break; } } if ( bitrate != -1 || srate != -1 || stereo != -1 ) { static unsigned int last_t; unsigned int now = GetTickCount(); //detect wrap with the first one if ( now < last_t || now > last_t + 500 || last_brate != g_brate || last_srate != g_srate || last_nch != g_nch ) { last_t = now; PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC); } } if ( synched != -1 || stereo != -1 ) { g_need_infoupd = synched | (stereo != -1 ? 8 : 4) | (g_need_infoupd & 8); } } static int sa_getmode() { if ( sa_override ) return 3; if ( sa_curmode == 4 && !config_mw_open && config_pe_open ) return 1; return sa_curmode; } static int eq_isactive() { int r = dsp_isactive(); if ( r ) return 1; if ( in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() && (config_replaygain_non_rg_gain.GetFloat() != 0) ) return 1; if ( in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() && (config_replaygain_preamp.GetFloat() != 0) ) return 1; if ( filter_enabled ) return 2; return 0; } static float eq_lookup1[64] = { 4.000000f, 3.610166f, 3.320019f, 3.088821f, 2.896617f, 2.732131f, 2.588368f, 2.460685f, 2.345845f, 2.241498f, 2.145887f, 2.057660f, 1.975760f, 1.899338f, 1.827707f, 1.760303f, 1.696653f, 1.636363f, 1.579094f, 1.524558f, 1.472507f, 1.422724f, 1.375019f, 1.329225f, 1.285197f, 1.242801f, 1.201923f, 1.162456f, 1.124306f, 1.087389f, 1.051628f, 1.000000f, 0.983296f, 0.950604f, 0.918821f, 0.887898f, 0.857789f, 0.828454f, 0.799853f, 0.771950f, 0.744712f, 0.718108f, 0.692110f, 0.666689f, 0.641822f, 0.617485f, 0.593655f, 0.570311f, 0.547435f, 0.525008f, 0.503013f, 0.481433f, 0.460253f, 0.439458f, 0.419035f, 0.398970f, 0.379252f, 0.359868f, 0.340807f, 0.322060f, 0.303614f, 0.285462f, 0.267593f, 0.250000f }; ///////////////// EQ CODE ///////////////////////// static int __inline float_to_int(double a) { a += ((((65536.0 * 65536.0 * 16) + (65536.0 * 0.5)) * 65536.0)); return ((*(int*)&a) - 0x80000000); } float* splbuf = 0; int splbuf_alloc = 0; float eqt[10] = { 0 }; static void FillFloat(float* floatBuf, void* samples, size_t bps, size_t numSamples, size_t numChannels, float preamp) { nsutil_pcm_IntToFloat_Interleaved_Gain(floatBuf, samples, (int)bps, numSamples * numChannels, preamp); } static void FillSamples(void* samples, float* floatBuf, size_t bps, size_t numSamples, size_t numChannels) { nsutil_pcm_FloatToInt_Interleaved(samples, floatBuf, (int)bps, numSamples * numChannels); } static float NonReplayGainAdjust() { if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() ) return pow(10.0f, (float)config_replaygain_non_rg_gain / 20.0f); else return 1.0f; } static float ReplayGainPreamp() { if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() ) return pow(10.0f, (float)config_replaygain_preamp / 20.0f); else return 1.0f; } static int eq_dosamples_4front(short* samples, int numsamples, int bps, int nch, int srate) { g_srate_exact = srate; //char *csamples = (char *)samples; short* oldsamples = samples; if ( filter_enabled && in_mod && !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_EQ) ) { if ( !eq || filter_srate != srate ) { if ( !eq ) eq = (eq10_t*)calloc(nch, sizeof(eq10_t)); eq10_setup(eq, nch, (float)srate); // initialize for ( int x = 0; x < 10; x++ ) eq10_setgain(eq, nch, x, eqt[x]); filter_srate = srate; } if ( splbuf_alloc < numsamples * nch ) { int new_splbuf_alloc = numsamples * nch; float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc); if ( new_splbuf ) { splbuf_alloc = new_splbuf_alloc; splbuf = new_splbuf; } } if ( splbuf && eq ) { int y = nch * numsamples; FillFloat(splbuf, samples, bps, numsamples, nch, preamp_val * NonReplayGainAdjust() * ReplayGainPreamp()); for ( int x = 0; x < nch; x++ ) { eq10_processf(eq + x, splbuf, splbuf + y, numsamples, x, nch); } FillSamples(samples, splbuf + y, bps, numsamples, nch); } } else if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN) && config_replaygain.GetBool() && (config_replaygain_non_rg_gain.GetFloat() != 0) ) { if ( splbuf_alloc < numsamples * nch ) { int new_splbuf_alloc = numsamples * nch; float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc); if ( new_splbuf ) { splbuf_alloc = new_splbuf_alloc; splbuf = new_splbuf; } } if ( splbuf ) { FillFloat(splbuf, samples, bps, numsamples, nch, NonReplayGainAdjust() * ReplayGainPreamp()); FillSamples(samples, splbuf, bps, numsamples, nch); } } else if ( !(in_mod->UsesOutputPlug & IN_MODULE_FLAG_REPLAYGAIN_PREAMP) && config_replaygain.GetBool() && (config_replaygain_preamp.GetFloat() != 0) ) { if ( splbuf_alloc < numsamples * nch ) { int new_splbuf_alloc = numsamples * nch; float* new_splbuf = (float*)realloc(splbuf, 2 * sizeof(float) * new_splbuf_alloc); if ( new_splbuf ) { splbuf_alloc = new_splbuf_alloc; splbuf = new_splbuf; } } if ( splbuf ) { FillFloat(splbuf, samples, bps, numsamples, nch, ReplayGainPreamp()); FillSamples(samples, splbuf, bps, numsamples, nch); } } else filter_srate = 0; return dsp_dosamples(oldsamples, numsamples, bps, nch, srate); } static __inline double VALTODB(int v) { v -= 31; if ( v < -31 ) v = -31; if ( v > 32 ) v = 32; if ( v > 0 ) return -12.0 * (v / 32.0); else if ( v < 0 ) { return -12.0 * (v / 31.0); } return 0.0f; } static void eq_set_4front(char data[10]) { if ( !eq ) return; for ( int x = 0; x < 10; x++ ) { eqt[x] = (float)VALTODB(data[x]); if ( filter_srate ) eq10_setgain(eq, g_nch, x, eqt[x]); } } static bool eq_do_first = true; static int startup_config_eq_type = EQ_TYPE_4FRONT; void benskiQ_eq_set(char data[10]); void eq_set(int on, char data[10], int preamp) { if ( eq_do_first ) { startup_config_eq_type = config_eq_type; eq_do_first = false; } int x; if ( in_mod && in_mod->EQSet ) in_mod->EQSet(on, data, preamp); for ( x = 9; x >= 0 && data[x] == 31; x++ ); if ( x >= 0 ) filter_top2 = x; for ( x = 0; x < 10 && data[x] == 31; x++ ); if ( !on || (preamp == 31 && x == 10) ) { filter_enabled = 0; } else filter_enabled = 1; preamp_val = (float)eq_lookup1[preamp]; if ( startup_config_eq_type == EQ_TYPE_4FRONT ) eq_set_4front(data); if ( startup_config_eq_type == EQ_TYPE_CONSTANT_Q ) benskiQ_eq_set(data); } static int eq_dosamples(short* samples, int numsamples, int bps, int nch, int srate) { if ( eq_do_first ) { startup_config_eq_type = config_eq_type; eq_do_first = false; } if ( startup_config_eq_type == EQ_TYPE_4FRONT ) return eq_dosamples_4front(samples, numsamples, bps, nch, srate); else return benskiQ_eq_dosamples(samples, numsamples, bps, nch, srate); }