1
0

wa2.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. //#define USE_LOG
  2. #include "out_ds.h"
  3. #include "ds2.h"
  4. #include <dsound.h>
  5. #include <math.h>
  6. #include "ds_ipc.h"
  7. #include "../winamp/wa_ipc.h"
  8. #include "res_wa2/resource.h"
  9. #include <shlwapi.h>
  10. extern Out_Module mod;
  11. // wasabi based services for localisation support
  12. api_service *WASABI_API_SVC = 0;
  13. api_application *WASABI_API_APP = 0;
  14. api_language *WASABI_API_LNG = 0;
  15. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  16. HINSTANCE cfg_orig_dll = 0;
  17. static wchar_t szDescription[256];
  18. class FORMATSPEC
  19. {
  20. public:
  21. UINT freq, nch, bps;
  22. FORMATSPEC(UINT f, UINT n, UINT b) {freq = f;nch = n;bps = b;}
  23. FORMATSPEC() {freq = 0;nch = 0;bps = 0;}
  24. bool operator==(FORMATSPEC & foo) { return foo.freq == freq && foo.nch == nch && foo.bps == bps;}
  25. bool operator!=(FORMATSPEC & foo) { return !(*this == foo);}
  26. FORMATSPEC & operator=(FORMATSPEC &foo) {freq = foo.freq;bps = foo.bps;nch = foo.nch; return *this;}
  27. UINT Size() { return nch*(bps >> 3);}
  28. // long B2T(long b) {return MulDiv(b,1000,freq*Size());}
  29. // long T2B(long t) {return MulDiv(t,freq*Size(),1000);}
  30. };
  31. static FORMATSPEC dataspec;
  32. cfg_struct_t<GUID> cfg_dev2("cfg_dev2", 0);
  33. cfg_int cfg_buf_ms("cfg_buf_ms", 2000);
  34. cfg_int cfg_prebuf2("cfg_prebuf2", 500);
  35. cfg_int cfg_sil_db("cfg_sil_db", 400);
  36. cfg_int cfg_trackhack("cfg_trackhack", 500);
  37. cfg_int cfg_oldpause("cfg_oldpause", 0);
  38. cfg_int cfg_killsil("cfg_killsil", 0);
  39. cfg_int cfg_wait("cfg_wait", 1);
  40. cfg_int cfg_createprimary("cfg_createprimary", (GetVersion()&0x80000000) ? 1 : 0);
  41. cfg_int cfg_volume("cfg_volume", 1);
  42. cfg_int cfg_fadevol("cfg_fadevol", 1);
  43. cfg_int cfg_autocpu("cfg_autocpu", 0);
  44. cfg_int cfg_volmode("cfg_volmode", 0);
  45. cfg_int cfg_logvol_min("cfg_logvol_min", 100);
  46. cfg_int cfg_logfades("cfg_logfades", 0);
  47. cfg_struct_t<__int64> cfg_total_time("cfg_total_time", 0);
  48. cfg_int cfg_hw_mix("cfg_hw_mix", 1);
  49. cfg_int cfg_override("cfg_override", 0);
  50. cfg_int cfg_override_freq("cfg_override_freq", 44100);
  51. cfg_int cfg_override_bps("cfg_override_bps", 16);
  52. cfg_int cfg_override_nch("cfg_override_nch", 2);
  53. cfg_int cfg_refresh("cfg_refresh", 10);
  54. cfg_int cfg_cur_tab("cfg_cur_tab", 0);
  55. void preCreateIPC();
  56. void createIPC();
  57. void destroyIPC();
  58. static int hack_canwrite_count;
  59. static bool is_playing = 0;
  60. #ifdef HAVE_SSRC
  61. cfg_int cfg_use_resample("cfg_use_resample", 0);
  62. #include "../ssrc/ssrc.h"
  63. static Resampler_base* pSSRC;
  64. cfg_int cfg_dither("cfg_dither", 1);
  65. cfg_int cfg_resample_freq("cfg_resample_freq", 48000);
  66. cfg_int cfg_resample_bps("cfg_resample_bps2", 16);
  67. cfg_int cfg_fast("cfg_fast", 1);
  68. cfg_int cfg_pdf("cfg_pdf", 1);
  69. static FORMATSPEC resampled;
  70. #define KILL_SSRC {if (pSSRC) {delete pSSRC;pSSRC=0;}}
  71. static bool finished, use_finish;
  72. static void CREATE_SSRC(FORMATSPEC & out)
  73. {
  74. //todo: freq/bps range checks ?
  75. if (pSSRC) {delete pSSRC;pSSRC = 0;}
  76. if (out != dataspec) pSSRC = SSRC_create(dataspec.freq, out.freq, dataspec.bps, out.bps, dataspec.nch, cfg_dither, cfg_pdf, cfg_fast, 0);
  77. if (!pSSRC)
  78. {
  79. resampled = dataspec;
  80. }
  81. else
  82. {
  83. if (&resampled != &out) resampled = out;
  84. finished = 0;
  85. use_finish = cfg_trackhack == 0 ? 1 : 0;
  86. }
  87. }
  88. #else
  89. #define KILL_SSRC
  90. #define CREATE_SSRC(X)
  91. #endif
  92. #ifdef HAVE_JOY
  93. void wa2_hack_joy_update();
  94. void wa2_hack_joy_init();
  95. void wa2_hack_joy_deinit();
  96. #endif
  97. static CriticalSection sync; //class from ds2.h
  98. #define SYNC_IN sync.Enter();
  99. #define SYNC_OUT sync.Leave();
  100. #ifdef USE_LOG
  101. #include <iostream>
  102. static void log_write(char* msg)
  103. {
  104. /*
  105. char tmp[512];
  106. SYSTEMTIME st;
  107. GetSystemTime(&st);
  108. wsprintf(tmp, "wa2: %u:%02u:%02u.%03u %s\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, msg);
  109. OutputDebugString(tmp);
  110. */
  111. std::cout << msg << std::endl;
  112. }
  113. #else
  114. #define log_write(x)
  115. #endif
  116. static UINT fadetimehack;
  117. static int wa2_hint;
  118. enum
  119. {
  120. HINT_NONE, HINT_EOF, HINT_EOF_GAPLESS
  121. };
  122. void Config(HWND w);
  123. int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
  124. {
  125. MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
  126. msgbx.lpszText = message;
  127. msgbx.lpszCaption = title;
  128. msgbx.lpszIcon = MAKEINTRESOURCEW(102);
  129. msgbx.hInstance = GetModuleHandle(0);
  130. msgbx.dwStyle = MB_USERICON;
  131. msgbx.hwndOwner = parent;
  132. return MessageBoxIndirectW(&msgbx);
  133. }
  134. void About(HWND hwndParent)
  135. {
  136. wchar_t message[1024], text[1024];
  137. WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DS_OUTPUT_OLD,text,1024);
  138. wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
  139. szDescription, __DATE__);
  140. DoAboutMessageBox(hwndParent,text,message);
  141. }
  142. static DS2* pDS2;
  143. static char INI_FILE[MAX_PATH];
  144. static char APP_NAME[MAX_PATH];
  145. void Init()
  146. {
  147. if (!IsWindow(mod.hMainWindow))
  148. return;
  149. // loader so that we can get the localisation service api for use
  150. WASABI_API_SVC = (api_service*)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
  151. if (!WASABI_API_SVC || WASABI_API_SVC == (api_service *)1)
  152. return;
  153. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
  154. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  155. sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid);
  156. if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
  157. // need to have this initialised before we try to do anything with localisation features
  158. WASABI_API_START_LANG(mod.hDllInstance,OutDSLangGUID);
  159. cfg_orig_dll = mod.hDllInstance;
  160. swprintf(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_DS_OUTPUT), DS2_ENGINE_VER);
  161. mod.description = (char*)szDescription;
  162. log_write("init");
  163. SYNC_IN;
  164. char *p;
  165. if ((p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
  166. && p!= (char *)1)
  167. {
  168. lstrcpynA(INI_FILE, p, MAX_PATH);
  169. }
  170. else
  171. {
  172. GetModuleFileNameA(NULL, INI_FILE, sizeof(INI_FILE));
  173. p = INI_FILE + strlen(INI_FILE);
  174. while (p >= INI_FILE && *p != '.') p--;
  175. lstrcpyA(++p, "ini");
  176. }
  177. char temp[MAX_PATH];
  178. GetModuleFileNameA(mod.hDllInstance, temp, sizeof(temp));
  179. p = temp +strlen(temp);
  180. while (p && *p != '\\' && p >= temp)
  181. {
  182. if (*p == '.')
  183. *p = 0;
  184. p = CharPrevA(temp, p);
  185. }
  186. if (p != nullptr)
  187. {
  188. p = CharNextA(p);
  189. lstrcpyA(APP_NAME, p);
  190. }
  191. cfg_var::config_read(INI_FILE, APP_NAME);
  192. DS2::SetTotalTime(cfg_total_time);
  193. preCreateIPC();
  194. SYNC_OUT;
  195. }
  196. void Quit()
  197. {
  198. log_write("quit");
  199. SYNC_IN;
  200. destroyIPC();
  201. if (pDS2)
  202. {
  203. pDS2->Release();
  204. pDS2 = 0;
  205. }
  206. KILL_SSRC;
  207. if (cfg_wait)
  208. {
  209. while (DS2::InstanceCount() > 0) Sleep(1);
  210. }
  211. cfg_total_time = DS2::GetTotalTime();
  212. DS2::Quit();
  213. cfg_var::config_write(INI_FILE,APP_NAME/* "out_ds"*/);
  214. SYNC_OUT;
  215. #ifdef HAVE_JOY
  216. wa2_hack_joy_deinit();
  217. #endif
  218. }
  219. int Pause(int);
  220. static int volume = 255, pan=0;
  221. static __int64 pos_delta;
  222. static __int64 samples_written;
  223. static int paused;
  224. void setup_config(DS2config * cfg)
  225. {
  226. #ifdef HAVE_SSRC
  227. cfg->SetPCM(resampled.freq, resampled.bps, resampled.nch);
  228. #else
  229. cfg->SetPCM(dataspec.freq, dataspec.bps, dataspec.nch);
  230. #endif
  231. cfg->SetCreatePrimary(!!cfg_createprimary);
  232. cfg->SetWindow(mod.hMainWindow);
  233. cfg->SetDeviceGUID(cfg_dev2);
  234. int crossfadetime = cfg_fade_stop.usedef ? cfg_def_fade : cfg_fade_stop.time;
  235. int buffersize = cfg_fade_stop.on ? (crossfadetime > cfg_buf_ms ? crossfadetime : cfg_buf_ms) : cfg_buf_ms;
  236. cfg->SetBuffer(buffersize, cfg_prebuf2);
  237. if (cfg_killsil) cfg->SetSilence((float)cfg_sil_db*(float)0.1);
  238. cfg->SetVolMode(cfg_volmode, cfg_logvol_min, !!cfg_logfades);
  239. cfg->SetMixing(cfg_hw_mix ? 0 : 2);
  240. if (cfg_override)
  241. {
  242. cfg->SetPrimaryOverride(1);
  243. cfg->SetPrimaryOverrideFormat(cfg_override_freq, cfg_override_bps, cfg_override_nch);
  244. }
  245. cfg->SetCpuManagement(!!cfg_autocpu);
  246. cfg->SetRefresh(cfg_refresh);
  247. // cfg->SetCoop(0);
  248. #ifdef HAVE_JOY
  249. cfg->SetHavePitch(1);
  250. #endif
  251. }
  252. __int64 get_written_time();
  253. static void do_ssrc_write(char * buf, int len);
  254. int CanResample(int sfrq, int dfrq);
  255. int Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
  256. { //messy
  257. log_write("open");
  258. SYNC_IN;
  259. #ifdef HAVE_JOY
  260. wa2_hack_joy_init();
  261. #endif
  262. is_playing = 0;
  263. FORMATSPEC newformat(samplerate, numchannels, bitspersamp);
  264. #ifdef HAVE_SSRC
  265. FORMATSPEC newresampled(cfg_resample_freq, numchannels, cfg_resample_bps);
  266. if (!cfg_use_resample) newresampled = newformat;
  267. #endif
  268. DS2 * wait = 0;
  269. bool nofadein = pDS2 ? 1 : 0;
  270. bool nosetvol = nofadein;
  271. if (pDS2)
  272. {
  273. pDS2->SetCloseOnStop(0);
  274. if (pDS2->IsClosed())
  275. {
  276. pDS2->Release();pDS2 = 0;
  277. KILL_SSRC;
  278. }
  279. else
  280. {
  281. log_write("got ds2");
  282. #ifdef HAVE_SSRC
  283. if (dataspec != newformat
  284. && cfg_fade_stop <= 0 && cfg_fade_start <= 0
  285. && resampled == newresampled
  286. && CanResample(newformat.freq, newresampled.freq)
  287. )
  288. { //reinit ssrc, dont reinit output
  289. if (pSSRC)
  290. {
  291. use_finish = 1;
  292. do_ssrc_write(0, 0);
  293. delete pSSRC;
  294. pSSRC = 0;
  295. }
  296. dataspec = newformat;
  297. CREATE_SSRC(newresampled); //resampled spec doesn't change, canresample was checked, this cant fail
  298. }
  299. else
  300. #endif
  301. if (dataspec != newformat
  302. #ifdef HAVE_SSRC
  303. || resampled != newresampled
  304. #endif
  305. || cfg_fade_stop > 0 || cfg_fade_start > 0
  306. )
  307. {
  308. #ifdef HAVE_SSRC
  309. if (pSSRC)
  310. {
  311. use_finish = 1;
  312. do_ssrc_write(0, 0);
  313. delete pSSRC;
  314. pSSRC = 0;
  315. }
  316. #endif
  317. log_write("using wait");
  318. wait = pDS2;
  319. pDS2 = 0;
  320. }
  321. }
  322. }
  323. if (!pDS2)
  324. {
  325. nosetvol = 0;
  326. log_write("doing new ds2 instance");
  327. dataspec = newformat;
  328. #ifdef HAVE_SSRC
  329. CREATE_SSRC(newresampled);
  330. #endif
  331. DS2config cfg;
  332. setup_config(&cfg);
  333. pDS2 = DS2::Create(&cfg);
  334. if (!pDS2)
  335. {
  336. log_write("bork bork");
  337. if (wait) wait->Release();
  338. const TCHAR* moo = cfg.GetError();
  339. if (moo)
  340. {
  341. TCHAR errStr[128];
  342. wsprintf(errStr,WASABI_API_LNGSTRINGW(IDS_ERROR),mod.description);
  343. MessageBox(0, moo, errStr, MB_ICONERROR);
  344. }
  345. KILL_SSRC;
  346. SYNC_OUT;
  347. return -1;
  348. }
  349. }
  350. else
  351. { //reusing old DS2
  352. #ifdef HAVE_SSRC
  353. if (pSSRC)
  354. {
  355. if (finished)
  356. {
  357. // KILL_SSRC;
  358. CREATE_SSRC(resampled);
  359. }
  360. else use_finish = cfg_trackhack == 0 ? 1 : 0;
  361. }
  362. #endif
  363. pDS2->StartNewStream();
  364. pos_delta -= get_written_time();
  365. }
  366. if (!cfg_volume) volume = 255;
  367. pDS2->SetPan_Int(pan);
  368. UINT ft = DS2::InstanceCount() > 1 ? cfg_fade_start : cfg_fade_firststart;
  369. if (ft && !nofadein)
  370. {
  371. log_write("fadein");
  372. pDS2->SetVolume_Int(0);
  373. pDS2->Fade_Int(ft, volume);
  374. }
  375. else if (!nosetvol) pDS2->SetVolume_Int(volume);
  376. if (wait) pDS2->WaitFor(wait, 0);
  377. pos_delta = 0;
  378. samples_written = 0;
  379. paused = 0;
  380. log_write("done opening");
  381. wa2_hint = HINT_NONE;
  382. hack_canwrite_count = 0;
  383. is_playing = 1;
  384. #ifdef HAVE_JOY
  385. wa2_hack_joy_update();
  386. #endif
  387. int crossfadetime = cfg_fade_stop.usedef ? cfg_def_fade : cfg_fade_stop.time;
  388. int buffersize = cfg_fade_stop.on ? (crossfadetime > cfg_buf_ms ? crossfadetime : cfg_buf_ms) : cfg_buf_ms;
  389. int rv = buffersize;
  390. SYNC_OUT;
  391. log_write("~open");
  392. return rv;
  393. }
  394. void Close()
  395. {
  396. log_write("close");
  397. SYNC_IN;
  398. if (pDS2)
  399. {
  400. log_write("got ds2");
  401. pDS2->KillEndGap();
  402. switch (wa2_hint)
  403. {
  404. case HINT_NONE:
  405. pDS2->FadeAndForget(cfg_fade_pause);
  406. pDS2 = 0;
  407. KILL_SSRC;
  408. break;
  409. case HINT_EOF:
  410. pDS2->FadeAndForget(cfg_fade_stop);
  411. pDS2 = 0;
  412. KILL_SSRC;
  413. break;
  414. case HINT_EOF_GAPLESS:
  415. if (pDS2->GetLatency() > 0) pDS2->SetCloseOnStop(1);
  416. else {pDS2->Release();pDS2 = 0;}
  417. break;
  418. }
  419. }
  420. is_playing = 0;
  421. SYNC_OUT;
  422. log_write("done closing");
  423. }
  424. static void make_new_ds2()
  425. {
  426. #ifdef HAVE_SSRC
  427. // KILL_SSRC;
  428. CREATE_SSRC(resampled);
  429. #endif
  430. DS2config cfg;
  431. setup_config(&cfg);
  432. pDS2 = DS2::Create(&cfg);
  433. if (pDS2)
  434. {
  435. pDS2->SetPan_Int(pan);
  436. pDS2->SetVolume_Int(0);
  437. pDS2->Fade_Int(fadetimehack, volume);
  438. fadetimehack = 0;
  439. }
  440. }
  441. #ifdef HAVE_SSRC
  442. static void do_ssrc_write(char * buf, int len)
  443. {
  444. if (!finished && pSSRC)
  445. {
  446. UINT nsiz;
  447. if (len > 0) pSSRC->Write(buf, (UINT)len);
  448. else if (use_finish)
  449. {
  450. finished = 1;
  451. pSSRC->Finish();
  452. }
  453. char * data = (char*)pSSRC->GetBuffer(&nsiz);
  454. if (nsiz) pDS2->ForceWriteData(data, nsiz);
  455. pSSRC->Read(nsiz);
  456. }
  457. }
  458. #endif
  459. int Write(char *buf, int len)
  460. {
  461. log_write("write");
  462. SYNC_IN;
  463. hack_canwrite_count = 0;
  464. wa2_hint = 0;
  465. if (paused)
  466. {
  467. SYNC_OUT;
  468. return 1;
  469. }
  470. if (!pDS2)
  471. {
  472. log_write("write: need new object");
  473. make_new_ds2();
  474. if (!pDS2 || !buf || !len)
  475. {
  476. SYNC_OUT;
  477. return 0;
  478. }
  479. }
  480. samples_written += len / dataspec.Size();
  481. int rv = 0;
  482. if (buf && len > 0)
  483. {
  484. #ifdef HAVE_SSRC
  485. if (pSSRC) do_ssrc_write(buf, len);
  486. else
  487. #endif
  488. rv = !pDS2->ForceWriteData(buf, len); //flood warning
  489. }
  490. SYNC_OUT;
  491. return rv;
  492. }
  493. int CanWrite()
  494. {
  495. log_write("canwrite");
  496. int rv = 0;
  497. SYNC_IN;
  498. if (!paused)
  499. {
  500. if (!pDS2)
  501. {
  502. make_new_ds2();
  503. hack_canwrite_count = -1;
  504. }
  505. if (pDS2)
  506. {
  507. #ifdef HAVE_SSRC
  508. if (pSSRC)
  509. {
  510. rv = MulDiv(pDS2->CanWrite() - resampled.Size(), dataspec.bps * dataspec.freq, resampled.bps * resampled.freq) - pSSRC->GetDataInInbuf();
  511. }
  512. else
  513. #endif
  514. rv = pDS2->CanWrite();
  515. if (rv < 0) rv = 0;
  516. if (++hack_canwrite_count > 2 && pDS2->BufferStatusPercent() > 50) pDS2->ForcePlay(); //big prebuffer hack
  517. }
  518. }
  519. SYNC_OUT;
  520. return rv;
  521. }
  522. int IsPlaying()
  523. {
  524. log_write("isplaying");
  525. int rv = 0;
  526. SYNC_IN;
  527. if (pDS2)
  528. {
  529. int foo = cfg_fade_stop;
  530. pDS2->KillEndGap();
  531. pDS2->ForcePlay();
  532. int lat = pDS2->GetLatency();
  533. wa2_hint = HINT_EOF;
  534. if (foo > 0)
  535. {
  536. rv = lat > foo;
  537. }
  538. else if (lat > (int)cfg_trackhack)
  539. {
  540. rv = 1;
  541. }
  542. else
  543. {
  544. wa2_hint = HINT_EOF_GAPLESS;
  545. rv = 0;
  546. }
  547. }
  548. SYNC_OUT;
  549. return rv;
  550. }
  551. int Pause(int new_state)
  552. {
  553. log_write("pause");
  554. SYNC_IN;
  555. int rv = paused;
  556. paused = new_state;
  557. if (new_state)
  558. {
  559. if (pDS2)
  560. {
  561. UINT ft = cfg_fade_pause;
  562. if (!ft)
  563. {
  564. pDS2->Pause(1);
  565. }
  566. else if (cfg_oldpause)
  567. {
  568. pDS2->FadeAndForget(ft);
  569. pDS2 = 0;
  570. KILL_SSRC;
  571. fadetimehack = ft;
  572. }
  573. else
  574. {
  575. pDS2->FadePause(ft);
  576. }
  577. }
  578. }
  579. else
  580. {
  581. if (pDS2) pDS2->Pause(0);
  582. }
  583. SYNC_OUT;
  584. return rv;
  585. }
  586. void SetVolume(int _volume) // volume is 0-255
  587. {
  588. log_write("setvolume");
  589. SYNC_IN;
  590. if (_volume != -666 && cfg_volume)
  591. {
  592. volume = _volume;
  593. if (pDS2)
  594. {
  595. if (cfg_fadevol) pDS2->FadeX_Int(150, _volume);
  596. else pDS2->SetVolume_Int(_volume);
  597. }
  598. }
  599. SYNC_OUT;
  600. }
  601. void SetPan(int _pan) // pan is -128 to 128
  602. {
  603. log_write("setpan");
  604. SYNC_IN;
  605. if (cfg_volume)
  606. {
  607. pan = _pan;
  608. if (pDS2) pDS2->SetPan_Int(pan);
  609. }
  610. SYNC_OUT;
  611. }
  612. void Flush(int t)
  613. {
  614. log_write("flush");
  615. SYNC_IN;
  616. if (pDS2)
  617. {
  618. UINT t = cfg_fade_seek;
  619. pDS2->FadeAndForget(t);
  620. pDS2 = 0;
  621. fadetimehack = t;
  622. }
  623. #ifdef HAVE_SSRC
  624. // KILL_SSRC;
  625. CREATE_SSRC(resampled);
  626. #endif
  627. samples_written = 0;
  628. pos_delta = t;
  629. SYNC_OUT;
  630. }
  631. __int64 get_written_time()
  632. {
  633. return dataspec.freq ? samples_written*1000 / (__int64)dataspec.freq : 0;
  634. }
  635. static int GetWrittenTime()
  636. {
  637. log_write("getwrittentime");
  638. int rv;
  639. SYNC_IN;
  640. rv = is_playing ? (int)(pos_delta + get_written_time()) : 0;
  641. SYNC_OUT;
  642. log_write("~getwrittentime");
  643. return rv;
  644. }
  645. static __int64 GetOutputTime64()
  646. {
  647. if (!is_playing) return 0;
  648. __int64 rv = get_written_time();
  649. if (pDS2) rv -= pDS2->GetLatency();
  650. #ifdef HAVE_SSRC
  651. if (pSSRC) rv -= pSSRC->GetLatency();
  652. #endif
  653. if (rv < 0) rv = 0;
  654. return rv;
  655. }
  656. static int GetOutputTime()
  657. {
  658. log_write("getoutputtime");
  659. SYNC_IN;
  660. int rv = (int)(pos_delta + GetOutputTime64());
  661. SYNC_OUT;
  662. log_write("!getoutputtime");
  663. return rv;
  664. }
  665. Out_Module mod =
  666. {
  667. OUT_VER_U,
  668. 0
  669. /*NAME
  670. #ifdef HAVE_SSRC
  671. " SSRC"
  672. #endif
  673. #ifdef HAVE_JOY
  674. " JOY"
  675. #endif*/
  676. ,
  677. 203968848,
  678. 0, 0,
  679. Config,
  680. About,
  681. Init,
  682. Quit,
  683. Open,
  684. Close,
  685. Write,
  686. CanWrite,
  687. IsPlaying,
  688. Pause,
  689. SetVolume,
  690. SetPan,
  691. Flush,
  692. GetOutputTime,
  693. GetWrittenTime,
  694. };
  695. HMODULE thisMod=0;
  696. static HMODULE inWMDLL = 0;
  697. BOOL APIENTRY DllMain(HANDLE hMod, DWORD r, void*)
  698. {
  699. if (r == DLL_PROCESS_ATTACH)
  700. {
  701. thisMod=(HMODULE)hMod;
  702. DisableThreadLibraryCalls((HMODULE)hMod);
  703. }
  704. if (r == DLL_PROCESS_DETACH)
  705. {
  706. if (inWMDLL)
  707. {
  708. FreeLibrary(inWMDLL); // potentially unsafe, we'll see ...
  709. inWMDLL = 0;
  710. }
  711. }
  712. return TRUE;
  713. }
  714. extern "C"
  715. {
  716. __declspec(dllexport) Out_Module * winampGetOutModule()
  717. {
  718. HMODULE in_wm = GetModuleHandleW(L"in_wm.dll");
  719. if (in_wm)
  720. {
  721. Out_Module *(*dsGetter)(HINSTANCE) = (Out_Module * (*)(HINSTANCE))GetProcAddress(in_wm, "GetDS");
  722. if (dsGetter) {
  723. Out_Module *in_wm_ds = dsGetter(thisMod);
  724. if (in_wm_ds) {
  725. inWMDLL = in_wm;
  726. return in_wm_ds;
  727. }
  728. }
  729. }
  730. return &mod;
  731. }
  732. }
  733. bool wa2_GetRealtimeStat(DS2_REALTIME_STAT * stat) //for config
  734. {
  735. bool rv = 0;
  736. SYNC_IN;
  737. if (pDS2 && !pDS2->IsClosed())
  738. {
  739. rv = 1;
  740. pDS2->GetRealtimeStat(stat);
  741. }
  742. SYNC_OUT;
  743. return rv;
  744. }
  745. #ifdef HAVE_SSRC
  746. bool wa2_IsResampling(RESAMPLING_STATUS *foo)
  747. {
  748. bool rv;
  749. SYNC_IN;
  750. if (pSSRC)
  751. {
  752. foo->src_freq = dataspec.freq;
  753. foo->src_bps = dataspec.bps;
  754. foo->dst_freq = resampled.freq;
  755. foo->dst_bps = resampled.bps;
  756. rv = 1;
  757. }
  758. else rv = 0;
  759. SYNC_OUT;
  760. return rv;
  761. }
  762. #endif
  763. #ifdef HAVE_JOY
  764. void wa2_hack_setpitch(double d)
  765. {
  766. SYNC_IN;
  767. if (pDS2) pDS2->SetPitch(d);
  768. SYNC_OUT;
  769. }
  770. #endif
  771. void wa2_sync_in() {SYNC_IN;}
  772. void wa2_sync_out() {SYNC_OUT;}
  773. HWND ipcWnd = NULL;
  774. extern void set_buffer(HWND wnd, UINT b);
  775. extern void update_buf(HWND wnd);
  776. extern HWND buffer_config_wnd;
  777. extern HWND fades_config_wnd;
  778. extern UINT cur_buffer;
  779. extern void update_prebuf_range(HWND wnd);
  780. typedef struct
  781. {
  782. const wchar_t * name;
  783. int on, usedef;
  784. int time;
  785. }
  786. FadeCfgCopy;
  787. extern void format_fade(wchar_t * txt, FadeCfgCopy * c, int idx);
  788. LRESULT CALLBACK ipcProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  789. {
  790. switch (uMsg)
  791. {
  792. case WM_DS_IPC:
  793. switch (lParam)
  794. {
  795. case DS_IPC_CB_CFGREFRESH:
  796. // trap me !
  797. return 0;
  798. case DS_IPC_CB_ONSHUTDOWN:
  799. // trap me !
  800. return 0;
  801. case DS_IPC_SET_CROSSFADE:
  802. wa2_sync_in();
  803. cfg_fade_stop.on = (int)wParam;
  804. // update the config wnd if it is showing the fades page
  805. if (fades_config_wnd)
  806. {
  807. HWND list = GetDlgItem(fades_config_wnd, IDC_LIST);
  808. int cursel = (int)SendMessage(list, LB_GETCURSEL, 0, 0);
  809. FadeCfgCopy * c = (FadeCfgCopy*)SendMessage(list, LB_GETITEMDATA, 2, 0);
  810. c->on = (int)wParam;
  811. c->usedef = cfg_fade_stop.usedef;
  812. c->time = cfg_fade_stop.time;
  813. wchar_t txt[256];
  814. format_fade(txt, c, 2);
  815. SendMessage(list, LB_DELETESTRING, 2, 0);
  816. SendMessage(list, LB_INSERTSTRING, 2, (LPARAM)txt);
  817. SendMessage(list, LB_SETITEMDATA, 2, (LPARAM)c);
  818. if (cursel == 2)
  819. {
  820. CheckDlgButton(fades_config_wnd, IDC_FADE_ENABLED, c->on);
  821. CheckDlgButton(fades_config_wnd, IDC_USE_CUSTOM_FADE, !c->usedef);
  822. SetDlgItemInt(fades_config_wnd, IDC_CUSTOM_FADE, c->time, 0);
  823. }
  824. SendMessage(list, LB_SETCURSEL, cursel, 0);
  825. }
  826. wa2_sync_out();
  827. return 0;
  828. case DS_IPC_SET_CROSSFADE_TIME:
  829. wa2_sync_in();
  830. cfg_fade_stop.usedef = 0;
  831. cfg_fade_stop.time = (int)wParam;
  832. wa2_sync_out();
  833. return 0;
  834. case DS_IPC_GET_CROSSFADE:
  835. return cfg_fade_stop.on;
  836. case DS_IPC_GET_CROSSFADE_TIME:
  837. if (cfg_fade_stop.usedef) return cfg_def_fade;
  838. return cfg_fade_stop.time;
  839. }
  840. return 0;
  841. }
  842. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  843. }
  844. VOID CALLBACK preCreateIPCTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  845. {
  846. KillTimer(NULL, idEvent);
  847. createIPC();
  848. }
  849. void preCreateIPC()
  850. {
  851. SetTimer(NULL, 1, 1, preCreateIPCTimerProc);
  852. }
  853. void createIPC()
  854. {
  855. WNDCLASSA wc;
  856. if ( !GetClassInfoA( mod.hDllInstance, DS_IPC_CLASSNAME, &wc ) )
  857. {
  858. memset(&wc, 0, sizeof(wc));
  859. wc.lpfnWndProc = ipcProc;
  860. wc.hInstance = mod.hDllInstance;
  861. wc.lpszClassName = DS_IPC_CLASSNAME;
  862. wc.style = 0;
  863. ATOM atom = RegisterClassA( &wc );
  864. }
  865. ipcWnd = CreateWindowA(DS_IPC_CLASSNAME, NULL, WS_CHILD, 0, 0, 1, 1, mod.hMainWindow, NULL, mod.hDllInstance, NULL);
  866. PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_CB_OUTPUTCHANGED);
  867. }
  868. void destroyIPC()
  869. {
  870. if (ipcWnd)
  871. {
  872. if (IsWindow(mod.hMainWindow))
  873. DestroyWindow(ipcWnd); ipcWnd = NULL;
  874. }
  875. // this is disabled because otherwise win98 can fail the next registerclass,
  876. // so at creation, we just check if the class exists or not
  877. // UnregisterClass(DS_IPC_CLASSNAME, mod.hDllInstance);
  878. }