cnv_ds2.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. #include "cnv_ds2.h"
  2. #include "ds2.h"
  3. #include "../studio/services/svc_textfeed.h"
  4. #include "../studio/services/svc_action.h"
  5. #include "../common/nsguid.h"
  6. #include "../bfc/timerclient.h"
  7. #include "../bfc/textfeed.h"
  8. static WACNAME wac;
  9. WAComponentClient *the = &wac;
  10. // {F6FE7F49-B017-4bcc-842C-2FFA842FB033}
  11. static const GUID guid =
  12. { 0xf6fe7f49, 0xb017, 0x4bcc, { 0x84, 0x2c, 0x2f, 0xfa, 0x84, 0x2f, 0xb0, 0x33 } };
  13. GUID WACNAME::getGUID() {
  14. return guid;
  15. }
  16. class _int_limited : public _int
  17. {
  18. private:
  19. int min,max;
  20. public:
  21. // void setMinMax(int _min,int _max) {min=_min;max=_max;}
  22. _int_limited(const char * name,int defval,int _min,int _max) : _int(name,defval) {min=_min;max=_max;}
  23. friend class fooViewer;
  24. int operator =(int newval) { return setValueAsInt(newval) ? newval : getValueAsInt(); }
  25. };
  26. class fooViewer : public DependentViewerT<_int_limited>
  27. {
  28. protected:
  29. //took me some time to notice when bas borked it last time
  30. //virtual int viewer_onItemDataChange(_int_limited *item, int hint1, int hint2)
  31. virtual int viewer_onEvent(_int_limited *item, int event, int param2, void *ptr, int ptrlen)
  32. {
  33. int i = (int)(*item);
  34. if (i>item->max) (*item)=item->max;
  35. else if (i<item->min) (*item)=item->min;
  36. return 1;
  37. }
  38. };
  39. static fooViewer fooviewer;
  40. #define DEVICE_DEFAULT "(default device)"
  41. _string cfg_device("Device",DEVICE_DEFAULT);
  42. _int_limited cfg_buf_ms("Buffer length (ms)",DS2config::DEFAULT_BUFFER,100,20000);
  43. _int_limited cfg_prebuf("Prebuffer (ms)",DS2config::DEFAULT_PREBUFFER,0,20000);
  44. _int_limited cfg_fade("Default fade time (ms)",333,0,20000);
  45. _bool cfg_dofades("Use fades",0);
  46. _bool cfg_oldpausefade("Old-style fade on pause",0);
  47. _bool cfg_killsil("Kill silence",0);
  48. _int_limited cfg_sil_db("Cutoff (in -dB)",40,15,200);
  49. _bool cfg_hw_mix("Allow hardware mixing",1);
  50. _bool cfg_delayed("Delayed DirectSound shutdown",1);
  51. _bool cfg_wait("Full fadeout when exiting Winamp",1);
  52. _bool cfg_fade_volume("Smooth volume changes",1);
  53. _bool cfg_create_primary("Create primary buffer",0);
  54. _bool cfg_override_primary("Override primary buffer format",0);
  55. _int_limited cfg_primary_sr("Primary buffer override sample rate",44100,8000,192000);
  56. _int_limited cfg_primary_nch("Primary buffer override number of channels",2,1,6);
  57. _int_limited cfg_primary_bps("Primary buffer override bits per sample",16,8,32);
  58. _int cfg_logvol_min("Logarithmic volume control scale",100);
  59. _bool cfg_logfades("Logarithmic fades",0);
  60. _bool cfg_pitch_enabled("Use pitch control",0);
  61. _int cfg_pitch("Pitch",100);
  62. _string cfg_volume("Volume control mode","linear");
  63. _int_limited cfg_refresh("Status display refresh",50,1,5000);
  64. class FADE_CTRL
  65. {
  66. private:
  67. _bool enabled,custom;
  68. _int_limited time;
  69. public:
  70. FADE_CTRL(const char * name,int enab)
  71. : enabled(StringPrintf("Fade on %s enabled",name),enab), custom(StringPrintf("Fade on %s use custom time",name),0), time(StringPrintf("Fade on %s custom time",name),333,0,20000)
  72. {
  73. }
  74. void registerme(CfgItemI * diz)
  75. {
  76. diz->registerAttribute(&enabled);
  77. diz->registerAttribute(&custom);
  78. diz->registerAttribute(&time);
  79. fooviewer.viewer_addViewItem(&time);
  80. }
  81. operator int()
  82. {
  83. if (!enabled || !cfg_dofades) return 0;
  84. else if (custom) return (UINT)time;
  85. else return (UINT)cfg_fade;
  86. }
  87. };
  88. static FADE_CTRL
  89. fade_start("start",0),
  90. fade_firststart("first start",0),
  91. fade_endoftrack("end of track",0),
  92. fade_pause("stop/pause",1),
  93. fade_seek("seek",1);
  94. class myCfgItemI : public CfgItemI
  95. {
  96. public:
  97. myCfgItemI(const char * n,GUID _guid=INVALID_GUID) : CfgItemI(n,_guid) {setParentGuid(guid);}
  98. };
  99. class fadeShiz : public myCfgItemI
  100. {
  101. public:
  102. void registerStuff()
  103. {
  104. registerAttribute(&cfg_dofades);
  105. registerAttribute(&cfg_fade);
  106. registerAttribute(&cfg_oldpausefade);
  107. registerAttribute(&cfg_wait);
  108. registerAttribute(&cfg_fade_volume);
  109. fade_start.registerme(this);
  110. fade_firststart.registerme(this);
  111. fade_endoftrack.registerme(this);
  112. fade_pause.registerme(this);
  113. fade_seek.registerme(this);
  114. }
  115. fadeShiz(const char *n, GUID guid) : myCfgItemI(n,guid) {}
  116. };
  117. static fadeShiz fadeshiz("Fading",nsGUID::fromChar("{4D981DA3-F75D-431a-B617-46F3E45D2A1F}"));
  118. static myCfgItemI cmpt("Compatibility",nsGUID::fromChar("{CBDF55F4-6EB6-45c1-B1DF-7A9F95C33758}"));
  119. #define FEEDID_DEVICELIST "DirectSound:DEVICES"
  120. #define FEEDID_VERSION "DirectSound:VERSION"
  121. #define FEEDID_VOLCTRL "DirectSound:VOLCTRL"
  122. #define FEEDID_STATUS "DirectSound:STATUS"
  123. #if 0
  124. class MyTextFeed : public TextFeed
  125. {
  126. public:
  127. MyTextFeed() {
  128. registerFeed(FEEDID_VOLCTRL, "linear;logarithmic;hybrid;disabled");
  129. }
  130. //CUT virtual int hasFeed(const char * name)
  131. //CUT {
  132. //CUT return !_stricmp(name,FEEDID_DEVICELIST) || !_stricmp(name,FEEDID_VERSION) || !_stricmp(name,FEEDID_VOLCTRL);
  133. //CUT }
  134. //CUT virtual void registerCallback(const char *feedid, TextFeedCallback *cb)
  135. //CUT {
  136. if (!_stricmp(feedid,FEEDID_DEVICELIST))
  137. {
  138. String devlist="";
  139. DsDevEnum e;
  140. while(e)
  141. {
  142. if (!devlist.isempty()) devlist += ";";
  143. devlist+=e.GetName();
  144. e++;
  145. }
  146. cb->textfeed_onReceiveText(devlist);
  147. if (!strcmp(cfg_device,DEVICE_DEFAULT)) cfg_device=DsDevEnumDefault().GetName();
  148. }
  149. else if (!_stricmp(feedid,FEEDID_VERSION))
  150. {
  151. cb->textfeed_onReceiveText(DS2_ENGINE_VER);
  152. }
  153. else if (!_stricmp(feedid,FEEDID_VOLCTRL))
  154. {
  155. cb->textfeed_onReceiveText("linear;logarithmic;hybrid;disabled");
  156. }
  157. }
  158. virtual void unregisterCallback(const char *feedid, TextFeedCallback *cb) {}
  159. };
  160. #endif
  161. class StatusTextFeed : public TextFeed, private TimerClientDI
  162. {
  163. public:
  164. StatusTextFeed() {
  165. cc = 0;
  166. registerFeed(FEEDID_STATUS);
  167. }
  168. int cc;
  169. virtual void onRegClient() {
  170. cc++;
  171. if (cc == 1) timerclient_setTimer(666,cfg_refresh);
  172. }
  173. virtual void onDeregClient() {
  174. cc--;
  175. if (cc == 0) timerclient_killTimer(666);
  176. }
  177. private:
  178. void UpdateStatus();
  179. //CUT PtrList<TextFeedCallback> list;
  180. virtual void timerclient_timerCallback(int id) {UpdateStatus();}
  181. static char display[1024];
  182. public:
  183. static const char * getDisplay() {return display;}
  184. static const char *getServiceName() { return "DirectSound Status Display"; }
  185. //CUT virtual int hasFeed(const char * name) {return !_stricmp(name,FEEDID_STATUS);}
  186. #if 0//CUT
  187. virtual void registerCallback(const char *feedid, TextFeedCallback *cb)
  188. {
  189. if (!_stricmp(feedid,FEEDID_STATUS))
  190. {
  191. int n=list.getNumItems();
  192. list.addItem(cb);
  193. if (n==0)
  194. {
  195. timerclient_setTimer(666,cfg_refresh);
  196. }
  197. UpdateStatus();
  198. }
  199. }
  200. virtual void unregisterCallback(const char *feedid, TextFeedCallback *cb)
  201. {
  202. list.removeItem(cb);
  203. if (list.getNumItems()==0)
  204. {
  205. timerclient_killTimer(666);
  206. }
  207. }
  208. #endif
  209. };
  210. char StatusTextFeed::display[1024];
  211. #define ACTIONID_COPY "DirectSound:COPY"
  212. class DsoundActions : public svc_actionI {
  213. public:
  214. DsoundActions() {
  215. registerAction(ACTIONID_COPY, 0);
  216. }
  217. virtual ~DsoundActions() { }
  218. virtual int onActionId(int id, const char *action, const char *param,int,int,void*,int,RootWnd*) {
  219. switch (id) {
  220. case 0:
  221. if (!_stricmp(action,ACTIONID_COPY))
  222. {
  223. const char * display = StatusTextFeed::getDisplay();
  224. if (OpenClipboard(0))
  225. {
  226. HANDLE hMem=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,strlen(display)+1);
  227. strcpy((char*)GlobalLock(hMem),display);
  228. GlobalUnlock(hMem);
  229. SetClipboardData(CF_TEXT,hMem);
  230. CloseClipboard();
  231. }
  232. }
  233. return 1;
  234. }
  235. return 0;
  236. }
  237. static const char *getServiceName() { return "DirectSound Actions Service"; }
  238. };
  239. static void FormatProgress(UINT pos,UINT max,UINT len,char * out)
  240. {
  241. UINT pos1=MulDiv(pos,len,max);
  242. UINT n;
  243. *(out++)='[';
  244. for(n=0;n<len;n++)
  245. {
  246. *(out++)= (n==pos1) ? '#' : '=';
  247. }
  248. *(out++)=']';
  249. *(out++)=0;
  250. }
  251. static void FormatTime(__int64 t,char * out)
  252. {
  253. int w,d,h,m,s,ms;
  254. w=(int)(t/(1000*60*60*24*7));
  255. d=(int)(t/(1000*60*60*24))%7;
  256. h=(int)(t/(1000*60*60))%24;
  257. m=(int)(t/(1000*60))%60;
  258. s=(int)(t/(1000))%60;
  259. ms=(int)(t)%1000;
  260. if (w)
  261. {
  262. wsprintf(out,"%iw ",w);
  263. while(*out) out++;
  264. }
  265. if (d)
  266. {
  267. wsprintf(out,"%id ",d);
  268. while(*out) out++;
  269. }
  270. if (h)
  271. {
  272. wsprintf(out,"%i:",h);
  273. while(*out) out++;
  274. }
  275. wsprintf(out,h ? "%02i:":"%i:",m);
  276. while(*out) out++;
  277. wsprintf(out,"%02i.%03i",s,ms);
  278. }
  279. void StatusTextFeed::UpdateStatus()
  280. {
  281. DS2_REALTIME_STAT stat;
  282. char total[32];
  283. __int64 time_total=DS2::GetTotalTime();
  284. FormatTime(time_total,total);
  285. if (DS2::GetRealtimeStatStatic(&stat))
  286. {
  287. char bigint1[32],bigint2[32];
  288. _i64toa(stat.bytes_written,bigint1,10);
  289. _i64toa(stat.bytes_played,bigint2,10);
  290. char time1[32],time2[32];
  291. FormatTime(stat.bytes_written/(stat.bps/8*stat.nch)*1000/stat.sr,time1);
  292. __int64 time_played=stat.bytes_played/(stat.bps/8*stat.nch)*1000/stat.sr;
  293. FormatTime(time_played,time2);
  294. char prog1[56],prog2[56];
  295. FormatProgress(stat.pos_play,stat.buf_size_bytes,48,prog1);
  296. FormatProgress(stat.pos_write,stat.buf_size_bytes,48,prog2);
  297. #define EOL "\x0d\x0a"
  298. sprintf(display,
  299. "Output format: %u Hz, %u bits per sample, %u channel%s" EOL
  300. "Active buffer size: %u ms (%u bytes)" EOL
  301. "Device: \"%s\"" EOL
  302. "Mixing: %s, primary buffer: %s%s" EOL EOL
  303. "Buffer playback cursor: %u bytes%s" EOL "%s" EOL
  304. "Buffer write cursor: %u bytes" EOL "%s" EOL
  305. EOL
  306. "Data buffered:"EOL
  307. "Total: %u ms (%u bytes)" EOL
  308. "Async buffer: %u ms (%u bytes)"EOL
  309. EOL
  310. "Buffer locks done: %u" EOL
  311. "Underruns: %u" EOL
  312. "Time played: %s (%s bytes)" EOL
  313. "Time written: %s (%s bytes)" EOL
  314. "Total time played: %s" EOL
  315. "Volume: %f dB / %f dB" EOL
  316. ,
  317. stat.sr,stat.bps,stat.nch,stat.nch>1 ? "s":"",
  318. stat.buf_size_ms,stat.buf_size_bytes,
  319. DsDevEnumGuid(stat.current_device).GetName(),
  320. (stat.dscaps_flags&DSBCAPS_LOCHARDWARE) ? "hardware" : (stat.dscaps_flags&DSBCAPS_LOCSOFTWARE) ? "software" : "unknown",
  321. stat.have_primary_buffer ? "active" : "inactive",
  322. (stat.dscaps_flags_primary&DSBCAPS_LOCHARDWARE) ? " (hardware)" : (stat.dscaps_flags_primary&DSBCAPS_LOCSOFTWARE) ? " (software)" : "",
  323. stat.pos_play,stat.paused?" (paused)":"",prog1,stat.pos_write,prog2,
  324. stat.latency_ms,stat.latency,
  325. MulDiv(stat.bytes_async,1000,stat.sr*stat.nch*(stat.bps>>3)),stat.bytes_async,
  326. stat.lock_count,stat.underruns,
  327. time2,bigint2,
  328. time1,bigint1,
  329. total,
  330. stat.vol_left,stat.vol_right
  331. );
  332. }
  333. else
  334. {
  335. wsprintf(display,"Not active." EOL EOL "Total time played: %s",total);
  336. #undef EOL
  337. }
  338. #if 0//CUT
  339. foreach(list)
  340. list.getfor()->textfeed_onReceiveText(display);
  341. endfor;
  342. #endif
  343. sendFeed(FEEDID_STATUS, display);
  344. }
  345. //static waServiceTSingle<svc_textFeed, TextFeed> g_feed;
  346. static waServiceTSingle<svc_textFeed, StatusTextFeed> g_statusfeed;
  347. static waServiceTSingle<svc_action, DsoundActions> g_actions;
  348. WACNAME::WACNAME() {
  349. #ifdef FORTIFY
  350. FortifySetName("cnv_pcmdsound.wac");
  351. FortifyEnterScope();
  352. #endif
  353. addChildItem(&fadeshiz);
  354. addChildItem(&cmpt);
  355. registerService(new waServiceFactoryT<svc_mediaConverter, cnvDS2>);
  356. registerService(&g_statusfeed);
  357. registerService(&g_actions);
  358. // registerService(&g_feed);
  359. }
  360. WACNAME::~WACNAME() {
  361. #ifdef FORTIFY
  362. FortifyLeaveScope();
  363. #endif
  364. }
  365. void WACNAME::onCreate()
  366. {
  367. {
  368. char temp[128];
  369. api->getStringPrivate("Total time", temp,127, "0");
  370. temp[127]=0;
  371. DS2::SetTotalTime(_atoi64(temp));
  372. }
  373. // {EDAA0599-3E43-4eb5-A65D-C0A0484240E7}
  374. static const GUID cfg_audio_guid =
  375. { 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } };
  376. // {689D3A8E-3DDF-4d56-8BA4-8E068CF86F2D}
  377. static const GUID cfg_fade_guid =
  378. { 0x689d3a8e, 0x3ddf, 0x4d56, { 0x8b, 0xa4, 0x8e, 0x6, 0x8c, 0xf8, 0x6f, 0x2d } };
  379. // {27D1BBF0-6F65-4149-BE77-6FB2A2F59AA8}
  380. static const GUID cfg_status_guid =
  381. { 0x27d1bbf0, 0x6f65, 0x4149, { 0xbe, 0x77, 0x6f, 0xb2, 0xa2, 0xf5, 0x9a, 0xa8 } };
  382. // {9F60BF8B-1F3F-4c11-9BCD-AA15C9EAD1C4}
  383. static const GUID cfg_misc_guid =
  384. { 0x9f60bf8b, 0x1f3f, 0x4c11, { 0x9b, 0xcd, 0xaa, 0x15, 0xc9, 0xea, 0xd1, 0xc4 } };
  385. registerSkinFile("xml/directsound-prefs.xml");
  386. registerSkinFile("xml/directsound-status.xml");
  387. registerSkinFile("xml/directsound-fading.xml");
  388. registerSkinFile("xml/directsound-misc.xml");
  389. api->preferences_registerGroup("directsound", "DirectSound", guid, cfg_audio_guid);
  390. api->preferences_registerGroup("directsound.fading", "Fading", cfg_fade_guid, guid);
  391. api->preferences_registerGroup("directsound.status", "Status display", cfg_status_guid, guid);
  392. api->preferences_registerGroup("directsound.misc", "Other settings", cfg_misc_guid, guid);
  393. fadeshiz.registerStuff();
  394. registerAttribute(&cfg_device);
  395. registerAttribute(&cfg_buf_ms);
  396. registerAttribute(&cfg_prebuf);
  397. registerAttribute(&cfg_killsil);
  398. registerAttribute(&cfg_sil_db);
  399. registerAttribute(&cfg_pitch_enabled);
  400. registerAttribute(&cfg_pitch);
  401. registerAttribute(&cfg_volume);
  402. registerAttribute(&cfg_logvol_min);
  403. registerAttribute(&cfg_logfades);
  404. registerAttribute(&cfg_refresh);
  405. fooviewer.viewer_addViewItem(&cfg_buf_ms);
  406. fooviewer.viewer_addViewItem(&cfg_prebuf);
  407. fooviewer.viewer_addViewItem(&cfg_fade);
  408. fooviewer.viewer_addViewItem(&cfg_sil_db);
  409. fooviewer.viewer_addViewItem(&cfg_refresh);
  410. cmpt.registerAttribute(&cfg_delayed);
  411. cmpt.registerAttribute(&cfg_hw_mix);
  412. cmpt.registerAttribute(&cfg_create_primary);
  413. cmpt.registerAttribute(&cfg_override_primary);
  414. cmpt.registerAttribute(&cfg_primary_sr);
  415. cmpt.registerAttribute(&cfg_primary_nch);
  416. cmpt.registerAttribute(&cfg_primary_bps);
  417. }
  418. void WACNAME::onDestroy() {
  419. WAComponentClient::onDestroy();
  420. if (cfg_wait)
  421. {
  422. while(DS2::InstanceCount()>0) Sleep(1);
  423. }
  424. DS2::Quit();
  425. {
  426. char temp[128];
  427. _i64toa(DS2::GetTotalTime(),temp,10);
  428. api->setStringPrivate("Total time",temp);
  429. }
  430. }
  431. cnvDS2::cnvDS2() {
  432. m_ds2=0;
  433. ds2_paused=0;
  434. fadenow=DS2::InstanceCount()>0 ? fade_start : fade_firststart;
  435. pitch_set=1;
  436. sr=nch=bps=chan=0;
  437. }
  438. cnvDS2::~cnvDS2() {
  439. if (m_ds2)
  440. {
  441. m_ds2->FadeAndForget(fade_pause);
  442. }
  443. }
  444. int cnvDS2::getInfos(MediaInfo *infos)
  445. {
  446. return 0;
  447. }
  448. unsigned long tea_key[4]={0xef542687,0x4d5c68ac,0x54274ef9,0x844dfc52};
  449. unsigned long tea_sum=0xC6EF3720;
  450. unsigned long tea_delta=0x9E3779B9;
  451. static int strings_decrypt=0;
  452. static char crypted_bps[]={'b'^0x25,'p'^0x25,'s'^0x25,0};
  453. static char crypted_srate[]={(char)('s'+0x41),(char)('r'+0x41),(char)('a'+0x41),(char)('t'+0x41),(char)('e'+0x41),0};
  454. static char crypted_nch[]={'n'-0x18,'c'-0x18,'h'-0x18,0};
  455. int cnvDS2::processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch)
  456. {
  457. /* if (ds2_paused && m_ds2)
  458. {
  459. m_ds2->Pause(0);
  460. ds2_paused=0;
  461. }*/
  462. // strings "encrypted" for WMA pcm "secure" stuff
  463. int old_canwrite=m_ds2 ? m_ds2->CanWrite() : 0;
  464. char pcmstr[5]={(char)('p'+23),'c'^12,'M'-64,0};
  465. pcmstr[4]=0;
  466. pcmstr[1]^=12;
  467. pcmstr[0]-=23;
  468. pcmstr[2]+=64;
  469. Chunk *chunk1=chunk_list->getChunk(pcmstr/*"PCM"*/);
  470. pcmstr[3]=(char)('x'+85);
  471. pcmstr[3]-=85;
  472. Chunk *chunk=chunk_list->getChunk(pcmstr/*"PCMx"*/);
  473. if(chunk) {
  474. // decrypt using TEA (128-bit)
  475. int i=chunk->getSize()/8;
  476. unsigned long *v=(unsigned long *)chunk->getData();
  477. const unsigned long *k=tea_key;
  478. while(i) {
  479. register unsigned long y=v[0],z=v[1],sum=tea_sum, delta=tea_delta,n=32;
  480. /* sum = delta<<5, in general sum = delta * n */
  481. while(n-->0) {
  482. z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
  483. sum -= delta;
  484. y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
  485. }
  486. v[0]=y; v[1]=z; v+=2; i--;
  487. }
  488. } else {
  489. chunk=chunk1;
  490. if(!chunk) return 0;
  491. }
  492. Chunk * c=chunk;//chunk_list->getChunk("PCM");
  493. if (!c) return 0;
  494. int size=c->getSize();
  495. if (size<=0 || !c->getData()) {
  496. if(infos->getData("audio_need_canwrite")) {
  497. int cw;
  498. if(m_ds2)
  499. {
  500. cw=old_canwrite;//can be negative
  501. if (cw<0) cw=0;
  502. }
  503. else cw=65536;
  504. infos->setDataInt("audio_canwrite",cw,MediaInfo::INFO_NOSENDCB);
  505. }
  506. return 1;
  507. }
  508. UINT _sr=c->getInfo("srate"),_nch=c->getInfo("nch"),_bps=c->getInfo("bps");
  509. DWORD _chan=0;
  510. {
  511. Chunk *cc=chunk_list->getChunk("SPEAKER_SETUP");
  512. if (cc)
  513. {
  514. if (cc->getSize()==4)
  515. {
  516. chan = *(DWORD*)cc->getData();
  517. }
  518. }
  519. }
  520. UINT _fade=fadenow;
  521. fadenow=0;
  522. DS2 * wait=0;
  523. UINT waitfade=0;
  524. if (_sr!=sr || _nch!=nch || _bps!=bps || _chan!=chan || _fade)
  525. {
  526. if (m_ds2)
  527. {
  528. wait=m_ds2;
  529. if (_fade)
  530. {
  531. waitfade=_fade;
  532. }
  533. else
  534. {
  535. waitfade=cfg_dofades ? 50 : 0;//let's pretend that we're gapless hehe
  536. wait=m_ds2;
  537. }
  538. m_ds2=0;
  539. if (*killswitch) return 0;
  540. }
  541. sr=_sr;
  542. bps=_bps;
  543. nch=_nch;
  544. chan=_chan;
  545. }
  546. if (!m_ds2)
  547. {
  548. DS2config cfg;
  549. if (_stricmp(cfg_device,DEVICE_DEFAULT)) cfg.SetDeviceGUID(DsDevEnumName(cfg_device).GetGuid());
  550. cfg.SetPCM(sr,bps,nch);
  551. cfg.SetCreatePrimary(cfg_create_primary);
  552. cfg.SetPrimaryOverride(cfg_override_primary);
  553. cfg.SetPrimaryOverrideFormat(cfg_primary_sr,cfg_primary_bps,cfg_primary_nch);
  554. if (chan) cfg.SetChanMask(chan);
  555. cfg.SetWindow(api->main_getRootWnd()->gethWnd());
  556. cfg.SetMixing(cfg_hw_mix ? 0 : 2);
  557. use_pitch=cfg_pitch_enabled;
  558. if (!_stricmp(cfg_volume,"disabled")) use_vol=0;
  559. else
  560. {
  561. use_vol=1;
  562. int volmode;
  563. if (!_stricmp(cfg_volume,"logarithmic")) volmode=1;
  564. else if (!_stricmp(cfg_volume,"hybrid")) volmode=2;
  565. else volmode=0;
  566. cfg.SetVolMode(volmode,cfg_logvol_min,cfg_logfades);
  567. }
  568. {//automagic idiotproof buffer size config (no more "too short fading" lamers)
  569. UINT bs=(UINT)cfg_buf_ms;
  570. UINT bs1=bs;
  571. UINT v=fade_endoftrack;
  572. if (bs<v) bs=v;
  573. v=fade_pause;
  574. if (bs<v) bs=v;
  575. v=fade_seek;
  576. if (bs<v) bs=v;
  577. UINT pb=cfg_prebuf;
  578. cfg.SetBuffer(bs,pb>bs ? bs : pb);
  579. }
  580. cfg.SetSilence(cfg_killsil ? (float)cfg_sil_db : 0);
  581. cfg.SetImmediateShutdown(cfg_delayed);
  582. cfg.SetHavePitch(use_pitch);
  583. m_ds2=DS2::Create(&cfg);
  584. if (!m_ds2)
  585. {
  586. const char *moo=cfg.GetError();
  587. if (moo) infos->error(moo);
  588. return 0;
  589. }
  590. if (use_vol) m_ds2->SetPan_Int(api->core_getPan(m_coretoken));
  591. if (_fade)
  592. {
  593. m_ds2->SetVolume_Int(0);
  594. m_ds2->Fade_Int(_fade,use_vol ? api->core_getVolume(m_coretoken) : 255);
  595. }
  596. else
  597. m_ds2->SetVolume_Int(use_vol ? api->core_getVolume(m_coretoken) : 255);
  598. if (wait) m_ds2->WaitFor(wait,waitfade);
  599. pitch_set=1.0;
  600. }
  601. int ret=0;
  602. if (m_ds2->ForceWriteData(c->getData(),(UINT)size))
  603. {
  604. ret=1;
  605. if (old_canwrite<0) while(!*killswitch && m_ds2->CanWrite()<0) Sleep(1);
  606. }
  607. if(infos->getData("audio_need_canwrite")) infos->setDataInt("audio_canwrite",m_ds2->CanWrite(),MediaInfo::INFO_NOSENDCB);
  608. if (use_pitch)
  609. {
  610. double foo=(double)cfg_pitch / 100.0;
  611. if (foo<0.25) foo=0.25;
  612. else if (foo>4.0) foo=4.0;
  613. if (pitch_set!=foo)
  614. {
  615. m_ds2->SetPitch(foo);
  616. pitch_set=foo;
  617. }
  618. }
  619. return ret;
  620. }
  621. int cnvDS2::corecb_onSeeked(int newpos)
  622. {
  623. if (m_ds2)
  624. {
  625. fadenow=fade_seek;
  626. m_ds2->FadeAndForget(fadenow);
  627. m_ds2=0;
  628. }
  629. return 0;
  630. }
  631. int cnvDS2::getLatency(void)
  632. {
  633. return m_ds2 ? m_ds2->GetLatency() : 0;
  634. }
  635. int cnvDS2::corecb_onAbortCurrentSong()
  636. {
  637. if (m_ds2)
  638. {
  639. m_ds2->FadeAndForget(fade_pause);
  640. m_ds2=0;
  641. fadenow=fade_start;
  642. }
  643. return 0;
  644. }
  645. int cnvDS2::corecb_onVolumeChange(int v)
  646. {
  647. if (m_ds2 && use_vol)
  648. {
  649. if (cfg_fade_volume) m_ds2->FadeX_Int(100,v);
  650. else m_ds2->SetVolume_Int(v);
  651. }
  652. return 0;
  653. }
  654. int cnvDS2::corecb_onPanChange(int v)
  655. {
  656. if (m_ds2 && use_vol)
  657. {
  658. m_ds2->SetPan_Int(v);
  659. }
  660. return 0;
  661. }
  662. int cnvDS2::corecb_onPaused()
  663. {
  664. if (m_ds2)
  665. {
  666. UINT v=fade_pause;
  667. if (!v)
  668. {
  669. m_ds2->Pause(1);
  670. }
  671. else if (cfg_oldpausefade)
  672. {
  673. m_ds2->FadeAndForget(v);
  674. m_ds2=0;
  675. fadenow=v;
  676. }
  677. else
  678. {
  679. m_ds2->FadePause(v);
  680. }
  681. ds2_paused=1;
  682. }
  683. return 0;
  684. }
  685. int cnvDS2::corecb_onUnpaused()
  686. {
  687. if (ds2_paused && m_ds2) {m_ds2->Pause(0);}
  688. ds2_paused=0;
  689. return 0;
  690. }
  691. int cnvDS2::corecb_onEndOfDecode()
  692. {
  693. if (m_ds2)
  694. {
  695. m_ds2->KillEndGap();
  696. m_ds2->ForcePlay();
  697. fadenow=fade_endoftrack;
  698. }
  699. return 0;
  700. }
  701. int cnvDS2::sortPlacement(const char *oc)
  702. {
  703. // if (!_stricmp(oc,"crossfader")) {return -1;}
  704. return 0;
  705. }