diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Output/out_ds/wa2.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Output/out_ds/wa2.cpp')
-rw-r--r-- | Src/Plugins/Output/out_ds/wa2.cpp | 1005 |
1 files changed, 1005 insertions, 0 deletions
diff --git a/Src/Plugins/Output/out_ds/wa2.cpp b/Src/Plugins/Output/out_ds/wa2.cpp new file mode 100644 index 00000000..b492c62c --- /dev/null +++ b/Src/Plugins/Output/out_ds/wa2.cpp @@ -0,0 +1,1005 @@ +//#define USE_LOG + +#include "out_ds.h" +#include "ds2.h" +#include <dsound.h> +#include <math.h> +#include "ds_ipc.h" +#include "../winamp/wa_ipc.h" +#include "res_wa2/resource.h" +#include <shlwapi.h> + +extern Out_Module mod; + +// wasabi based services for localisation support +api_service *WASABI_API_SVC = 0; +api_application *WASABI_API_APP = 0; +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; +HINSTANCE cfg_orig_dll = 0; +static wchar_t szDescription[256]; + +class FORMATSPEC +{ +public: + UINT freq, nch, bps; + FORMATSPEC(UINT f, UINT n, UINT b) {freq = f;nch = n;bps = b;} + FORMATSPEC() {freq = 0;nch = 0;bps = 0;} + bool operator==(FORMATSPEC & foo) { return foo.freq == freq && foo.nch == nch && foo.bps == bps;} + bool operator!=(FORMATSPEC & foo) { return !(*this == foo);} + FORMATSPEC & operator=(FORMATSPEC &foo) {freq = foo.freq;bps = foo.bps;nch = foo.nch; return *this;} + UINT Size() { return nch*(bps >> 3);} + // long B2T(long b) {return MulDiv(b,1000,freq*Size());} + // long T2B(long t) {return MulDiv(t,freq*Size(),1000);} +}; + +static FORMATSPEC dataspec; + +cfg_struct_t<GUID> cfg_dev2("cfg_dev2", 0); + +cfg_int cfg_buf_ms("cfg_buf_ms", 2000); +cfg_int cfg_prebuf2("cfg_prebuf2", 500); +cfg_int cfg_sil_db("cfg_sil_db", 400); +cfg_int cfg_trackhack("cfg_trackhack", 500); +cfg_int cfg_oldpause("cfg_oldpause", 0); +cfg_int cfg_killsil("cfg_killsil", 0); +cfg_int cfg_wait("cfg_wait", 1); +cfg_int cfg_createprimary("cfg_createprimary", (GetVersion()&0x80000000) ? 1 : 0); +cfg_int cfg_volume("cfg_volume", 1); +cfg_int cfg_fadevol("cfg_fadevol", 1); +cfg_int cfg_autocpu("cfg_autocpu", 0); +cfg_int cfg_volmode("cfg_volmode", 0); +cfg_int cfg_logvol_min("cfg_logvol_min", 100); +cfg_int cfg_logfades("cfg_logfades", 0); +cfg_struct_t<__int64> cfg_total_time("cfg_total_time", 0); +cfg_int cfg_hw_mix("cfg_hw_mix", 1); +cfg_int cfg_override("cfg_override", 0); +cfg_int cfg_override_freq("cfg_override_freq", 44100); +cfg_int cfg_override_bps("cfg_override_bps", 16); +cfg_int cfg_override_nch("cfg_override_nch", 2); +cfg_int cfg_refresh("cfg_refresh", 10); +cfg_int cfg_cur_tab("cfg_cur_tab", 0); + +void preCreateIPC(); +void createIPC(); +void destroyIPC(); + +static int hack_canwrite_count; + +static bool is_playing = 0; + +#ifdef HAVE_SSRC + +cfg_int cfg_use_resample("cfg_use_resample", 0); + +#include "../ssrc/ssrc.h" + +static Resampler_base* pSSRC; + + +cfg_int cfg_dither("cfg_dither", 1); +cfg_int cfg_resample_freq("cfg_resample_freq", 48000); +cfg_int cfg_resample_bps("cfg_resample_bps2", 16); + +cfg_int cfg_fast("cfg_fast", 1); +cfg_int cfg_pdf("cfg_pdf", 1); + +static FORMATSPEC resampled; + +#define KILL_SSRC {if (pSSRC) {delete pSSRC;pSSRC=0;}} + +static bool finished, use_finish; + +static void CREATE_SSRC(FORMATSPEC & out) +{ + //todo: freq/bps range checks ? + if (pSSRC) {delete pSSRC;pSSRC = 0;} + if (out != dataspec) pSSRC = SSRC_create(dataspec.freq, out.freq, dataspec.bps, out.bps, dataspec.nch, cfg_dither, cfg_pdf, cfg_fast, 0); + if (!pSSRC) + { + resampled = dataspec; + } + else + { + if (&resampled != &out) resampled = out; + finished = 0; + use_finish = cfg_trackhack == 0 ? 1 : 0; + } +} + + +#else + +#define KILL_SSRC +#define CREATE_SSRC(X) + +#endif + +#ifdef HAVE_JOY +void wa2_hack_joy_update(); +void wa2_hack_joy_init(); +void wa2_hack_joy_deinit(); +#endif + +static CriticalSection sync; //class from ds2.h +#define SYNC_IN sync.Enter(); +#define SYNC_OUT sync.Leave(); + +#ifdef USE_LOG +#include <iostream> +static void log_write(char* msg) +{ + /* + char tmp[512]; + SYSTEMTIME st; + GetSystemTime(&st); + wsprintf(tmp, "wa2: %u:%02u:%02u.%03u %s\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, msg); + OutputDebugString(tmp); + */ + std::cout << msg << std::endl; +} + +#else + +#define log_write(x) + +#endif + + +static UINT fadetimehack; + +static int wa2_hint; +enum +{ + HINT_NONE, HINT_EOF, HINT_EOF_GAPLESS +}; + + +void Config(HWND w); + +int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message) +{ + MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0}; + msgbx.lpszText = message; + msgbx.lpszCaption = title; + msgbx.lpszIcon = MAKEINTRESOURCEW(102); + msgbx.hInstance = GetModuleHandle(0); + msgbx.dwStyle = MB_USERICON; + msgbx.hwndOwner = parent; + return MessageBoxIndirectW(&msgbx); +} + +void About(HWND hwndParent) +{ + wchar_t message[1024], text[1024]; + WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DS_OUTPUT_OLD,text,1024); + wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT), + szDescription, __DATE__); + DoAboutMessageBox(hwndParent,text,message); +} + +static DS2* pDS2; + +static char INI_FILE[MAX_PATH]; +static char APP_NAME[MAX_PATH]; +void Init() +{ + if (!IsWindow(mod.hMainWindow)) + return; + + // loader so that we can get the localisation service api for use + WASABI_API_SVC = (api_service*)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE); + if (!WASABI_API_SVC || WASABI_API_SVC == (api_service *)1) + return; + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface()); + + sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(mod.hDllInstance,OutDSLangGUID); + cfg_orig_dll = mod.hDllInstance; + + swprintf(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_DS_OUTPUT), DS2_ENGINE_VER); + mod.description = (char*)szDescription; + + log_write("init"); + SYNC_IN; + char *p; + if ((p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE)) + && p!= (char *)1) + { + lstrcpynA(INI_FILE, p, MAX_PATH); + } + else + { + GetModuleFileNameA(NULL, INI_FILE, sizeof(INI_FILE)); + p = INI_FILE + strlen(INI_FILE); + while (p >= INI_FILE && *p != '.') p--; + lstrcpyA(++p, "ini"); + } + + char temp[MAX_PATH]; + GetModuleFileNameA(mod.hDllInstance, temp, sizeof(temp)); + p = temp +strlen(temp); + while (p && *p != '\\' && p >= temp) + { + if (*p == '.') + *p = 0; + p = CharPrevA(temp, p); + } + if (p != nullptr) + { + p = CharNextA(p); + lstrcpyA(APP_NAME, p); + } + + cfg_var::config_read(INI_FILE, APP_NAME); + DS2::SetTotalTime(cfg_total_time); + preCreateIPC(); + SYNC_OUT; +} + +void Quit() +{ + log_write("quit"); + SYNC_IN; + destroyIPC(); + if (pDS2) + { + pDS2->Release(); + pDS2 = 0; + } + KILL_SSRC; + + if (cfg_wait) + { + while (DS2::InstanceCount() > 0) Sleep(1); + } + + cfg_total_time = DS2::GetTotalTime(); + + DS2::Quit(); + + cfg_var::config_write(INI_FILE,APP_NAME/* "out_ds"*/); + + SYNC_OUT; +#ifdef HAVE_JOY + wa2_hack_joy_deinit(); +#endif +} + +int Pause(int); + +static int volume = 255, pan=0; +static __int64 pos_delta; +static __int64 samples_written; + +static int paused; + +void setup_config(DS2config * cfg) +{ +#ifdef HAVE_SSRC + cfg->SetPCM(resampled.freq, resampled.bps, resampled.nch); +#else + cfg->SetPCM(dataspec.freq, dataspec.bps, dataspec.nch); +#endif + cfg->SetCreatePrimary(!!cfg_createprimary); + cfg->SetWindow(mod.hMainWindow); + cfg->SetDeviceGUID(cfg_dev2); + int crossfadetime = cfg_fade_stop.usedef ? cfg_def_fade : cfg_fade_stop.time; + int buffersize = cfg_fade_stop.on ? (crossfadetime > cfg_buf_ms ? crossfadetime : cfg_buf_ms) : cfg_buf_ms; + cfg->SetBuffer(buffersize, cfg_prebuf2); + if (cfg_killsil) cfg->SetSilence((float)cfg_sil_db*(float)0.1); + cfg->SetVolMode(cfg_volmode, cfg_logvol_min, !!cfg_logfades); + cfg->SetMixing(cfg_hw_mix ? 0 : 2); + if (cfg_override) + { + cfg->SetPrimaryOverride(1); + cfg->SetPrimaryOverrideFormat(cfg_override_freq, cfg_override_bps, cfg_override_nch); + } + cfg->SetCpuManagement(!!cfg_autocpu); + cfg->SetRefresh(cfg_refresh); + // cfg->SetCoop(0); +#ifdef HAVE_JOY + cfg->SetHavePitch(1); +#endif +} + +__int64 get_written_time(); + +static void do_ssrc_write(char * buf, int len); + +int CanResample(int sfrq, int dfrq); + +int Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms) +{ //messy + + log_write("open"); + SYNC_IN; +#ifdef HAVE_JOY + wa2_hack_joy_init(); +#endif + + is_playing = 0; + + FORMATSPEC newformat(samplerate, numchannels, bitspersamp); +#ifdef HAVE_SSRC + FORMATSPEC newresampled(cfg_resample_freq, numchannels, cfg_resample_bps); + if (!cfg_use_resample) newresampled = newformat; +#endif + + DS2 * wait = 0; + bool nofadein = pDS2 ? 1 : 0; + bool nosetvol = nofadein; + + if (pDS2) + { + pDS2->SetCloseOnStop(0); + if (pDS2->IsClosed()) + { + pDS2->Release();pDS2 = 0; + KILL_SSRC; + } + else + { + log_write("got ds2"); +#ifdef HAVE_SSRC + if (dataspec != newformat + && cfg_fade_stop <= 0 && cfg_fade_start <= 0 + && resampled == newresampled + && CanResample(newformat.freq, newresampled.freq) + ) + { //reinit ssrc, dont reinit output + if (pSSRC) + { + use_finish = 1; + do_ssrc_write(0, 0); + delete pSSRC; + pSSRC = 0; + } + + dataspec = newformat; + CREATE_SSRC(newresampled); //resampled spec doesn't change, canresample was checked, this cant fail + } + else +#endif + if (dataspec != newformat +#ifdef HAVE_SSRC + || resampled != newresampled +#endif + || cfg_fade_stop > 0 || cfg_fade_start > 0 + ) + { +#ifdef HAVE_SSRC + if (pSSRC) + { + use_finish = 1; + do_ssrc_write(0, 0); + delete pSSRC; + pSSRC = 0; + } +#endif + log_write("using wait"); + wait = pDS2; + pDS2 = 0; + } + } + } + + if (!pDS2) + { + nosetvol = 0; + log_write("doing new ds2 instance"); + dataspec = newformat; +#ifdef HAVE_SSRC + CREATE_SSRC(newresampled); +#endif + + DS2config cfg; + setup_config(&cfg); + pDS2 = DS2::Create(&cfg); + if (!pDS2) + { + log_write("bork bork"); + if (wait) wait->Release(); + const TCHAR* moo = cfg.GetError(); + if (moo) + { + TCHAR errStr[128]; + wsprintf(errStr,WASABI_API_LNGSTRINGW(IDS_ERROR),mod.description); + MessageBox(0, moo, errStr, MB_ICONERROR); + } + KILL_SSRC; + SYNC_OUT; + return -1; + } + } + else + { //reusing old DS2 +#ifdef HAVE_SSRC + if (pSSRC) + { + if (finished) + { + // KILL_SSRC; + CREATE_SSRC(resampled); + } + else use_finish = cfg_trackhack == 0 ? 1 : 0; + } +#endif + pDS2->StartNewStream(); + pos_delta -= get_written_time(); + } + + if (!cfg_volume) volume = 255; + pDS2->SetPan_Int(pan); + UINT ft = DS2::InstanceCount() > 1 ? cfg_fade_start : cfg_fade_firststart; + if (ft && !nofadein) + { + log_write("fadein"); + pDS2->SetVolume_Int(0); + pDS2->Fade_Int(ft, volume); + } + else if (!nosetvol) pDS2->SetVolume_Int(volume); + + if (wait) pDS2->WaitFor(wait, 0); + + pos_delta = 0; + samples_written = 0; + paused = 0; + log_write("done opening"); + wa2_hint = HINT_NONE; + hack_canwrite_count = 0; + is_playing = 1; + +#ifdef HAVE_JOY + wa2_hack_joy_update(); +#endif + + int crossfadetime = cfg_fade_stop.usedef ? cfg_def_fade : cfg_fade_stop.time; + int buffersize = cfg_fade_stop.on ? (crossfadetime > cfg_buf_ms ? crossfadetime : cfg_buf_ms) : cfg_buf_ms; + int rv = buffersize; + SYNC_OUT; + log_write("~open"); + return rv; +} + +void Close() +{ + log_write("close"); + SYNC_IN; + if (pDS2) + { + log_write("got ds2"); + pDS2->KillEndGap(); + switch (wa2_hint) + { + case HINT_NONE: + pDS2->FadeAndForget(cfg_fade_pause); + pDS2 = 0; + KILL_SSRC; + break; + case HINT_EOF: + pDS2->FadeAndForget(cfg_fade_stop); + pDS2 = 0; + KILL_SSRC; + break; + case HINT_EOF_GAPLESS: + if (pDS2->GetLatency() > 0) pDS2->SetCloseOnStop(1); + else {pDS2->Release();pDS2 = 0;} + break; + } + } + is_playing = 0; + SYNC_OUT; + log_write("done closing"); +} + +static void make_new_ds2() +{ +#ifdef HAVE_SSRC + // KILL_SSRC; + CREATE_SSRC(resampled); +#endif + + DS2config cfg; + setup_config(&cfg); + pDS2 = DS2::Create(&cfg); + + if (pDS2) + { + pDS2->SetPan_Int(pan); + pDS2->SetVolume_Int(0); + pDS2->Fade_Int(fadetimehack, volume); + fadetimehack = 0; + } +} + +#ifdef HAVE_SSRC + +static void do_ssrc_write(char * buf, int len) +{ + if (!finished && pSSRC) + { + UINT nsiz; + if (len > 0) pSSRC->Write(buf, (UINT)len); + else if (use_finish) + { + finished = 1; + pSSRC->Finish(); + } + + char * data = (char*)pSSRC->GetBuffer(&nsiz); + if (nsiz) pDS2->ForceWriteData(data, nsiz); + pSSRC->Read(nsiz); + } +} +#endif + + +int Write(char *buf, int len) +{ + log_write("write"); + SYNC_IN; + hack_canwrite_count = 0; + wa2_hint = 0; + if (paused) + { + SYNC_OUT; + return 1; + } + if (!pDS2) + { + log_write("write: need new object"); + make_new_ds2(); + if (!pDS2 || !buf || !len) + { + SYNC_OUT; + return 0; + } + } + samples_written += len / dataspec.Size(); + int rv = 0; + if (buf && len > 0) + { + +#ifdef HAVE_SSRC + if (pSSRC) do_ssrc_write(buf, len); + else +#endif + rv = !pDS2->ForceWriteData(buf, len); //flood warning + } + SYNC_OUT; + return rv; +} + +int CanWrite() +{ + log_write("canwrite"); + int rv = 0; + SYNC_IN; + if (!paused) + { + if (!pDS2) + { + make_new_ds2(); + hack_canwrite_count = -1; + } + if (pDS2) + { +#ifdef HAVE_SSRC + if (pSSRC) + { + rv = MulDiv(pDS2->CanWrite() - resampled.Size(), dataspec.bps * dataspec.freq, resampled.bps * resampled.freq) - pSSRC->GetDataInInbuf(); + } + else +#endif + rv = pDS2->CanWrite(); + if (rv < 0) rv = 0; + if (++hack_canwrite_count > 2 && pDS2->BufferStatusPercent() > 50) pDS2->ForcePlay(); //big prebuffer hack + } + } + SYNC_OUT; + return rv; +} + +int IsPlaying() +{ + log_write("isplaying"); + int rv = 0; + SYNC_IN; + if (pDS2) + { + int foo = cfg_fade_stop; + pDS2->KillEndGap(); + pDS2->ForcePlay(); + int lat = pDS2->GetLatency(); + wa2_hint = HINT_EOF; + if (foo > 0) + { + rv = lat > foo; + } + else if (lat > (int)cfg_trackhack) + { + rv = 1; + } + else + { + wa2_hint = HINT_EOF_GAPLESS; + rv = 0; + } + } + SYNC_OUT; + return rv; +} + +int Pause(int new_state) +{ + log_write("pause"); + SYNC_IN; + int rv = paused; + paused = new_state; + if (new_state) + { + if (pDS2) + { + UINT ft = cfg_fade_pause; + if (!ft) + { + pDS2->Pause(1); + } + else if (cfg_oldpause) + { + pDS2->FadeAndForget(ft); + pDS2 = 0; + KILL_SSRC; + fadetimehack = ft; + } + else + { + pDS2->FadePause(ft); + } + } + } + else + { + if (pDS2) pDS2->Pause(0); + } + SYNC_OUT; + return rv; +} + +void SetVolume(int _volume) // volume is 0-255 +{ + log_write("setvolume"); + SYNC_IN; + if (_volume != -666 && cfg_volume) + { + volume = _volume; + if (pDS2) + { + if (cfg_fadevol) pDS2->FadeX_Int(150, _volume); + else pDS2->SetVolume_Int(_volume); + } + } + SYNC_OUT; +} + +void SetPan(int _pan) // pan is -128 to 128 +{ + log_write("setpan"); + SYNC_IN; + if (cfg_volume) + { + pan = _pan; + if (pDS2) pDS2->SetPan_Int(pan); + } + SYNC_OUT; +} + +void Flush(int t) +{ + log_write("flush"); + SYNC_IN; + if (pDS2) + { + UINT t = cfg_fade_seek; + pDS2->FadeAndForget(t); + pDS2 = 0; + fadetimehack = t; + } +#ifdef HAVE_SSRC + // KILL_SSRC; + CREATE_SSRC(resampled); +#endif + samples_written = 0; + pos_delta = t; + SYNC_OUT; +} + +__int64 get_written_time() +{ + return dataspec.freq ? samples_written*1000 / (__int64)dataspec.freq : 0; +} + +static int GetWrittenTime() +{ + log_write("getwrittentime"); + int rv; + SYNC_IN; + rv = is_playing ? (int)(pos_delta + get_written_time()) : 0; + SYNC_OUT; + log_write("~getwrittentime"); + return rv; +} + +static __int64 GetOutputTime64() +{ + if (!is_playing) return 0; + __int64 rv = get_written_time(); + if (pDS2) rv -= pDS2->GetLatency(); +#ifdef HAVE_SSRC + if (pSSRC) rv -= pSSRC->GetLatency(); +#endif + if (rv < 0) rv = 0; + return rv; +} + +static int GetOutputTime() +{ + log_write("getoutputtime"); + SYNC_IN; + int rv = (int)(pos_delta + GetOutputTime64()); + SYNC_OUT; + log_write("!getoutputtime"); + return rv; +} + + + +Out_Module mod = +{ + OUT_VER_U, + 0 + /*NAME +#ifdef HAVE_SSRC + " SSRC" +#endif +#ifdef HAVE_JOY + " JOY" +#endif*/ + , + 203968848, + 0, 0, + Config, + About, + + Init, + Quit, + Open, + + Close, + + Write, + + CanWrite, + + IsPlaying, + + Pause, + + SetVolume, + SetPan, + + Flush, + + GetOutputTime, + GetWrittenTime, +}; + +HMODULE thisMod=0; + +static HMODULE inWMDLL = 0; +BOOL APIENTRY DllMain(HANDLE hMod, DWORD r, void*) +{ + if (r == DLL_PROCESS_ATTACH) + { + thisMod=(HMODULE)hMod; + DisableThreadLibraryCalls((HMODULE)hMod); + } + + if (r == DLL_PROCESS_DETACH) + { + if (inWMDLL) + { + FreeLibrary(inWMDLL); // potentially unsafe, we'll see ... + inWMDLL = 0; + } + } + + return TRUE; +} + +extern "C" +{ + __declspec(dllexport) Out_Module * winampGetOutModule() + { + HMODULE in_wm = GetModuleHandleW(L"in_wm.dll"); + if (in_wm) + { + Out_Module *(*dsGetter)(HINSTANCE) = (Out_Module * (*)(HINSTANCE))GetProcAddress(in_wm, "GetDS"); + if (dsGetter) { + Out_Module *in_wm_ds = dsGetter(thisMod); + if (in_wm_ds) { + inWMDLL = in_wm; + return in_wm_ds; + } + } + } + return &mod; + } +} + +bool wa2_GetRealtimeStat(DS2_REALTIME_STAT * stat) //for config +{ + bool rv = 0; + SYNC_IN; + if (pDS2 && !pDS2->IsClosed()) + { + rv = 1; + pDS2->GetRealtimeStat(stat); + } + SYNC_OUT; + return rv; +} + +#ifdef HAVE_SSRC +bool wa2_IsResampling(RESAMPLING_STATUS *foo) +{ + bool rv; + SYNC_IN; + if (pSSRC) + { + foo->src_freq = dataspec.freq; + foo->src_bps = dataspec.bps; + foo->dst_freq = resampled.freq; + foo->dst_bps = resampled.bps; + rv = 1; + } + else rv = 0; + SYNC_OUT; + return rv; +} +#endif + +#ifdef HAVE_JOY +void wa2_hack_setpitch(double d) +{ + SYNC_IN; + if (pDS2) pDS2->SetPitch(d); + SYNC_OUT; +} +#endif + +void wa2_sync_in() {SYNC_IN;} +void wa2_sync_out() {SYNC_OUT;} + +HWND ipcWnd = NULL; + +extern void set_buffer(HWND wnd, UINT b); +extern void update_buf(HWND wnd); +extern HWND buffer_config_wnd; +extern HWND fades_config_wnd; +extern UINT cur_buffer; +extern void update_prebuf_range(HWND wnd); + +typedef struct +{ + const wchar_t * name; + int on, usedef; + int time; +} +FadeCfgCopy; + +extern void format_fade(wchar_t * txt, FadeCfgCopy * c, int idx); + +LRESULT CALLBACK ipcProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DS_IPC: + switch (lParam) + { + case DS_IPC_CB_CFGREFRESH: + // trap me ! + return 0; + case DS_IPC_CB_ONSHUTDOWN: + // trap me ! + return 0; + case DS_IPC_SET_CROSSFADE: + wa2_sync_in(); + cfg_fade_stop.on = (int)wParam; + // update the config wnd if it is showing the fades page + if (fades_config_wnd) + { + HWND list = GetDlgItem(fades_config_wnd, IDC_LIST); + int cursel = (int)SendMessage(list, LB_GETCURSEL, 0, 0); + FadeCfgCopy * c = (FadeCfgCopy*)SendMessage(list, LB_GETITEMDATA, 2, 0); + c->on = (int)wParam; + c->usedef = cfg_fade_stop.usedef; + c->time = cfg_fade_stop.time; + wchar_t txt[256]; + format_fade(txt, c, 2); + SendMessage(list, LB_DELETESTRING, 2, 0); + SendMessage(list, LB_INSERTSTRING, 2, (LPARAM)txt); + SendMessage(list, LB_SETITEMDATA, 2, (LPARAM)c); + if (cursel == 2) + { + CheckDlgButton(fades_config_wnd, IDC_FADE_ENABLED, c->on); + CheckDlgButton(fades_config_wnd, IDC_USE_CUSTOM_FADE, !c->usedef); + SetDlgItemInt(fades_config_wnd, IDC_CUSTOM_FADE, c->time, 0); + } + SendMessage(list, LB_SETCURSEL, cursel, 0); + } + wa2_sync_out(); + return 0; + case DS_IPC_SET_CROSSFADE_TIME: + wa2_sync_in(); + cfg_fade_stop.usedef = 0; + cfg_fade_stop.time = (int)wParam; + wa2_sync_out(); + return 0; + case DS_IPC_GET_CROSSFADE: + return cfg_fade_stop.on; + case DS_IPC_GET_CROSSFADE_TIME: + if (cfg_fade_stop.usedef) return cfg_def_fade; + return cfg_fade_stop.time; + } + return 0; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +VOID CALLBACK preCreateIPCTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(NULL, idEvent); + createIPC(); +} + + +void preCreateIPC() +{ + SetTimer(NULL, 1, 1, preCreateIPCTimerProc); +} + +void createIPC() +{ + WNDCLASSA wc; + if ( !GetClassInfoA( mod.hDllInstance, DS_IPC_CLASSNAME, &wc ) ) + { + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = ipcProc; + wc.hInstance = mod.hDllInstance; + wc.lpszClassName = DS_IPC_CLASSNAME; + wc.style = 0; + ATOM atom = RegisterClassA( &wc ); + } + + ipcWnd = CreateWindowA(DS_IPC_CLASSNAME, NULL, WS_CHILD, 0, 0, 1, 1, mod.hMainWindow, NULL, mod.hDllInstance, NULL); + PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_CB_OUTPUTCHANGED); +} + +void destroyIPC() +{ + if (ipcWnd) + { + if (IsWindow(mod.hMainWindow)) + DestroyWindow(ipcWnd); ipcWnd = NULL; + } + // this is disabled because otherwise win98 can fail the next registerclass, + // so at creation, we just check if the class exists or not + // UnregisterClass(DS_IPC_CLASSNAME, mod.hDllInstance); +}
\ No newline at end of file |