out_dmusic.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. #include "main.h"
  2. #include <math.h>
  3. #include "seq.h"
  4. #include "fakedsound.h"
  5. #include "resource.h"
  6. // {B84EB58A-29F5-410b-880A-EB473BF34291}
  7. static const GUID guid_output =
  8. { 0xb84eb58a, 0x29f5, 0x410b, { 0x88, 0xa, 0xeb, 0x47, 0x3b, 0xf3, 0x42, 0x91 } };
  9. // {DF0800B6-D1E1-4b53-9C1E-642AF4CB7136}
  10. static const GUID dmusic_driver_guid =
  11. { 0xdf0800b6, 0xd1e1, 0x4b53, { 0x9c, 0x1e, 0x64, 0x2a, 0xf4, 0xcb, 0x71, 0x36 } };
  12. enum
  13. {
  14. MDD_OUT=1,
  15. };
  16. extern cfg_int cfg_dls_active,cfg_dm_keep_port;
  17. extern cfg_string cfg_dls_file;
  18. class MIDI_device_dmusic : public MIDI_device
  19. {
  20. private:
  21. GUID guid,guid_dmusic;
  22. DWORD dmFlags;
  23. bool f_has_output;
  24. virtual player_base * create();
  25. virtual bool is_default() {return 0;}
  26. virtual bool has_freq() {return !!(dmFlags&DMUS_PC_DIRECTSOUND);}
  27. virtual bool volctrl_happy() {return (dmFlags&DMUS_PC_DIRECTSOUND) || (dmFlags&DMUS_PC_SOFTWARESYNTH);}
  28. public:
  29. MIDI_device_dmusic(GUID p_guid,bool p_has_output,DWORD p_dmFlags,const wchar_t * p_name,const wchar_t * p_info)
  30. {
  31. guid = p_guid;
  32. guid_dmusic = p_guid;
  33. dmFlags = p_dmFlags;
  34. set_name(p_name);
  35. set_info(p_info);
  36. f_has_output = p_has_output;
  37. if (f_has_output)
  38. {
  39. const BYTE * src = (const BYTE*) &guid_output;
  40. BYTE * dst = (BYTE*) &guid;
  41. int n;
  42. for(n=0;n<sizeof(GUID);n++) dst[n]^=src[n];
  43. }
  44. }
  45. virtual GUID get_guid() {return guid;}
  46. GUID get_dm_guid() {return guid_dmusic;}
  47. virtual bool has_output() {return f_has_output;}
  48. virtual bool has_dls() {return !!(dmFlags&DMUS_PC_DLS);}
  49. };
  50. //bool IsDrumBankOK(BYTE n);
  51. IDirectMusicLoader* pLoader=0;
  52. IDirectMusicPerformance* pPerf=0;
  53. static IDirectMusicCollection *pGM=0;
  54. static IDirectMusic* pDM;
  55. static IDirectMusicPort *pPort;
  56. static IDirectSoundBuffer* pHack;
  57. IDirectMusicCollection *pCDLS=0;
  58. static void SendMsg(IDirectMusicPerformance *pPerf,DWORD msg)
  59. {
  60. DMUS_MIDI_PMSG *pMSG;
  61. if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_MIDI_PMSG),(DMUS_PMSG**)&pMSG)))
  62. {
  63. ZeroMemory(pMSG, sizeof(DMUS_MIDI_PMSG));
  64. pMSG->dwSize = sizeof(DMUS_MIDI_PMSG);
  65. pMSG->dwPChannel = msg&0xF;
  66. pMSG->dwVirtualTrackID = 0;
  67. pMSG->dwType = DMUS_PMSGT_MIDI;
  68. pMSG->dwVoiceID = 0;
  69. pMSG->dwGroupID = 0xFFFFFFFF;
  70. pMSG->mtTime=0;
  71. pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;
  72. pMSG->bStatus=(BYTE)(msg&0xFF);
  73. pMSG->bByte1=(BYTE)((msg>>8)&0xFF);
  74. pMSG->bByte2=(BYTE)((msg>>16)&0xFF);
  75. if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))
  76. {
  77. pPerf->FreePMsg((DMUS_PMSG*)pMSG);
  78. }
  79. }
  80. }
  81. static void SendSysex(IDirectMusicPerformance *pPerf,BYTE* data,UINT len)
  82. {
  83. DMUS_SYSEX_PMSG *pMSG;
  84. if(SUCCEEDED(pPerf->AllocPMsg(sizeof(DMUS_SYSEX_PMSG) + len,(DMUS_PMSG**)&pMSG)))
  85. {
  86. ZeroMemory(pMSG, sizeof(DMUS_SYSEX_PMSG)+len);
  87. pMSG->dwSize = sizeof(DMUS_SYSEX_PMSG);
  88. pMSG->dwPChannel = 0;
  89. pMSG->dwVirtualTrackID = 0;
  90. pMSG->dwType = DMUS_PMSGT_SYSEX;
  91. pMSG->dwVoiceID = 0;
  92. pMSG->dwGroupID = 0xFFFFFFFF;
  93. pMSG->dwLen = len;
  94. memcpy(pMSG->abData, (void*)data, len);
  95. pMSG->mtTime=0;
  96. pMSG->dwFlags = DMUS_PMSGF_REFTIME|DMUS_PMSGF_TOOL_IMMEDIATE;//pMSG->dwFlags = |DMUS_PMSGF_TOOL_IMMEDIATE;
  97. if (FAILED(pPerf->SendPMsg((DMUS_PMSG*)pMSG)))
  98. {
  99. pPerf->FreePMsg((DMUS_PMSG*)pMSG);
  100. }
  101. }
  102. }
  103. static void PortKill()
  104. {
  105. #ifdef USE_LOG
  106. log_write("portkill()");
  107. #endif
  108. if (pPort)
  109. {
  110. pPort->Activate(0);
  111. if (pPerf) pPerf->RemovePort(pPort);
  112. pPort->Release();
  113. pPort=0;
  114. }
  115. }
  116. static int PortInit(MIDI_device_dmusic * dev)
  117. {
  118. #ifdef USE_LOG
  119. log_write("portinit()");
  120. #endif
  121. static int _act_freq;
  122. static int _cfg_reverb,_cfg_chorus;
  123. static GUID last_port;
  124. if (!pPort || last_port!=dev->get_guid() || _act_freq!=cfg_freq || _cfg_reverb!=cfg_reverb || _cfg_chorus!=cfg_chorus)
  125. {
  126. #ifdef USE_LOG
  127. log_write("port settings changed");
  128. #endif
  129. if (pPort) PortKill();
  130. DMUS_PORTPARAMS dmpp;
  131. ZeroMemory(&dmpp,sizeof(dmpp));
  132. dmpp.dwSize=sizeof(dmpp);
  133. dmpp.dwValidParams=DMUS_PORTPARAMS_EFFECTS|DMUS_PORTPARAMS_SAMPLERATE|DMUS_PORTPARAMS_CHANNELGROUPS;
  134. dmpp.dwChannelGroups=1;
  135. dmpp.dwSampleRate=cfg_freq;
  136. if (cfg_reverb) dmpp.dwEffectFlags=DMUS_EFFECT_REVERB;
  137. if (cfg_chorus) dmpp.dwEffectFlags|=DMUS_EFFECT_CHORUS;
  138. if (FAILED( pDM->CreatePort(dev->get_dm_guid(),&dmpp,&pPort,0) )) return 0;
  139. pPerf->AddPort(pPort);
  140. pPerf->AssignPChannelBlock(0,pPort,1);
  141. last_port = dev->get_guid();
  142. _act_freq=cfg_freq;
  143. _cfg_reverb=cfg_reverb;
  144. _cfg_chorus=cfg_chorus;
  145. }
  146. if ((dev->has_output()))
  147. {
  148. #ifdef USE_LOG
  149. log_write("initializing output hack");
  150. #endif
  151. DWORD buf_s=0,blah=0;
  152. pPort->GetFormat(0,&blah,&buf_s);
  153. pHack=dhb_create(buf_s,cfg_freq);
  154. if (FAILED(pPort->SetDirectSound(get_ds(),pHack)))
  155. {//BORK
  156. PortKill();
  157. return 0;
  158. }
  159. }
  160. return 1;
  161. }
  162. /*
  163. int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log((double)vol/256.0)));
  164. if (pPerf)
  165. {
  166. return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));
  167. }
  168. */
  169. static int DM_setvol(int vol)
  170. {
  171. int lastvol1=(vol==0)?0x80000000:((int)(2000.0*log10((double)vol/255.0)));
  172. if (pPerf)
  173. {
  174. return SUCCEEDED(pPerf->SetGlobalParam(GUID_PerfMasterVolume,&lastvol1,4));
  175. }
  176. return 0;
  177. }
  178. class player_dmusic_imm : public seq_base
  179. {
  180. private:
  181. MIDI_device_dmusic * dev;
  182. UINT n_ins,s_ins;
  183. IDirectMusicDownloadedInstrument ** ins;
  184. IDirectMusicCollection *edls;
  185. protected:
  186. virtual void seq_shortmsg(DWORD msg) {SendMsg(pPerf,msg);}
  187. virtual void seq_sysex(BYTE* d,UINT l) {SendSysex(pPerf,d,l);}
  188. virtual void eof() {MIDI_core::Eof();}
  189. int setvol(int t) {return DM_setvol(t);}
  190. public:
  191. player_dmusic_imm(MIDI_device_dmusic * p_dev)
  192. {
  193. dev=p_dev;
  194. s_ins=n_ins=0;
  195. ins=0;
  196. edls=0;
  197. if (dev->has_dls())
  198. {
  199. s_ins=0x100;
  200. ins=(IDirectMusicDownloadedInstrument**)malloc(s_ins*sizeof(void*));
  201. }
  202. }
  203. ~player_dmusic_imm();
  204. int play();
  205. };
  206. int player_dmusic_imm::play()
  207. {
  208. if (!PortInit(dev)) return 0;
  209. MIDI_file * mf=MIDI_core::getFile();
  210. if (ins)
  211. {
  212. if (mf->pDLSdata)
  213. {
  214. LoadDLS(mf);
  215. if (mf->pDLS)
  216. {
  217. edls=mf->pDLS;
  218. }
  219. }
  220. if (!edls) edls=pCDLS;
  221. {
  222. INSTRUMENT_DESC* instr=GetInstruments(mf,1);
  223. while(instr)
  224. {
  225. DWORD i=instr->patch | (instr->bank_lo<<8) | (instr->bank_hi<<16);
  226. if (instr->drum) i|=0x80000000;
  227. if (n_ins>=s_ins)
  228. {
  229. s_ins<<=1;
  230. void *t=realloc(ins,s_ins);
  231. // if (!t) {s_ins>>=1;return ;}
  232. ins=(IDirectMusicDownloadedInstrument**)t;
  233. }
  234. IDirectMusicInstrument * pi=0;
  235. start:
  236. if (edls)
  237. {
  238. edls->GetInstrument(i,&pi);
  239. }
  240. if (!pi && pGM)
  241. {
  242. pGM->GetInstrument(i,&pi);
  243. }
  244. if (!pi) //cleaner's hacks don't work here
  245. {
  246. if (i&0x80000000)
  247. {
  248. if (i&0xFFFF00) {i&=0x800000FF;goto start;}
  249. }
  250. else
  251. {
  252. if (i&0xFF00) {i&=0xFF00FF;goto start;}
  253. if (i&0xFF0000) {i&=0xFF;goto start;}
  254. }
  255. }
  256. #if 0
  257. if (!pi)
  258. {
  259. char tmp[128] = {0};
  260. if (i&0x80000000)
  261. wsprintf(tmp,"missing drum kit: %u",i&0xFF);
  262. else
  263. wsprintf(tmp,"missing instrument: bank %x:%x / patch %x",(i>>16)&0xFF,(i>>8)&0xFF,i&0xFF);
  264. Warning(tmp);
  265. }
  266. #endif
  267. if (pi)
  268. {
  269. // DMUS_NOTERANGE nr = {instr->note_min,instr->note_max};
  270. // pPort->DownloadInstrument(pi,&ins[n_ins++],&nr,1);
  271. pPort->DownloadInstrument(pi,&ins[n_ins++],0,0);
  272. pi->Release();
  273. }
  274. {
  275. INSTRUMENT_DESC * d=instr->next;
  276. delete instr;
  277. instr=d;
  278. }
  279. }
  280. }
  281. }
  282. /* UINT n;
  283. for(n=0;n<16;n++)
  284. {
  285. pPort->SetChannelPriority(0,n,DAUD_CRITICAL_VOICE_PRIORITY);
  286. }*/
  287. pPort->Activate(1);
  288. DM_setvol(MIDI_core::player_getVol());
  289. return seq_cmd_start(CLEAN_DM);
  290. }
  291. player_dmusic_imm::~player_dmusic_imm()
  292. {
  293. seq_cmd_stop();
  294. if (ins)
  295. {
  296. if (pPort)
  297. {
  298. pPort->Activate(0);
  299. UINT n;
  300. for(n=0;n<n_ins;n++)
  301. {
  302. if (ins[n])
  303. {
  304. pPort->UnloadInstrument(ins[n]);
  305. ins[n]=0;
  306. }
  307. }
  308. }
  309. free(ins);
  310. }
  311. if (pHack)
  312. {
  313. pPort->SetDirectSound(0,0);
  314. pHack->Release();
  315. pHack=0;
  316. }
  317. if (!cfg_dm_keep_port) PortKill();
  318. }
  319. static void CALLBACK TimerProc(HWND,UINT,UINT id,DWORD)
  320. {
  321. DMUS_NOTIFICATION_PMSG* pMsg;
  322. while(pPerf->GetNotificationPMsg(&pMsg)==S_OK)
  323. {
  324. if (IsEqualGUID(pMsg->guidNotificationType,GUID_NOTIFICATION_SEGMENT))
  325. {
  326. if (MIDI_core::HavePlayer() && pMsg->dwNotificationOption == DMUS_NOTIFICATION_SEGEND)
  327. {
  328. MIDI_core::Eof();
  329. }
  330. }
  331. pPerf->FreePMsg((DMUS_PMSG*)pMsg);
  332. }
  333. }
  334. class player_dmusic : public player_base
  335. {
  336. public:
  337. ~player_dmusic();
  338. int gettime();
  339. int settime(int);
  340. int setvol(int vol) {return DM_setvol(vol);}
  341. void pause();
  342. void unpause();
  343. int play();
  344. player_dmusic(MIDI_device_dmusic * p_dev)
  345. {
  346. dev = p_dev;
  347. pSeg=0;
  348. pSS=0;
  349. rtStart=rtOffset=0;
  350. mtStart=mtOffset=0;
  351. }
  352. private:
  353. MIDI_device_dmusic * dev;
  354. IDirectMusicSegment* pSeg;
  355. IDirectMusicSegmentState* pSS;
  356. REFERENCE_TIME rtStart,rtOffset;
  357. MUSIC_TIME mtOffset,mtStart;
  358. bool dloaded,paused;
  359. UINT timer_id;
  360. };
  361. player_base * MIDI_device_dmusic::create()
  362. {
  363. #ifdef USE_LOG
  364. log_write("DM_create");
  365. #endif
  366. CoInitialize(0);
  367. if (!pLoader)
  368. {
  369. try {
  370. CoCreateInstance(CLSID_DirectMusicLoader,0,CLSCTX_INPROC,IID_IDirectMusicLoader,(void**)&pLoader);
  371. if (!pLoader) return 0;
  372. pLoader->EnableCache(GUID_DirectMusicAllTypes,0);
  373. } catch(...) {
  374. return 0;
  375. }
  376. }
  377. if (!pPerf)
  378. {
  379. try {
  380. CoCreateInstance(CLSID_DirectMusicPerformance,0,CLSCTX_INPROC,IID_IDirectMusicPerformance,(void**)&pPerf);
  381. if (!pPerf) return 0;
  382. pPerf->Init(&pDM,0,0);
  383. pPerf->AddNotificationType(GUID_NOTIFICATION_SEGMENT);
  384. } catch(...) {
  385. return 0;
  386. }
  387. }
  388. if (!pGM)
  389. {
  390. DMUS_OBJECTDESC desc;
  391. ZeroMemory(&desc,sizeof(desc));
  392. desc.dwSize=sizeof(desc);
  393. desc.dwValidData=DMUS_OBJ_OBJECT|DMUS_OBJ_CLASS;
  394. desc.guidObject=GUID_DefaultGMCollection;
  395. desc.guidClass=CLSID_DirectMusicCollection;
  396. try {
  397. pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pGM);
  398. } catch(...) {
  399. return 0;
  400. }
  401. }
  402. if (has_dls())
  403. {
  404. static string current_dls;
  405. if (!cfg_dls_active)
  406. {
  407. if (pCDLS) {pCDLS->Release();pCDLS=0;}
  408. }
  409. else
  410. {
  411. if (pCDLS && _stricmp(current_dls,cfg_dls_file)) {pCDLS->Release();pCDLS=0;}
  412. if (!pCDLS)
  413. {
  414. DMUS_OBJECTDESC desc;
  415. ZeroMemory(&desc,sizeof(desc));
  416. desc.dwSize=sizeof(desc);
  417. desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
  418. desc.guidClass = CLSID_DirectMusicCollection;
  419. mbstowcs(desc.wszFileName,cfg_dls_file,DMUS_MAX_FILENAME);
  420. if (FAILED(pLoader->GetObject(&desc,IID_IDirectMusicCollection,(void**)&pCDLS)))
  421. {
  422. // ErrorBox(Can't load DLS file.);
  423. pCDLS=0;
  424. cfg_dls_active=0;
  425. }
  426. else
  427. {
  428. ReleaseObject(pCDLS);
  429. current_dls = cfg_dls_file;
  430. }
  431. }
  432. }
  433. }
  434. if (cfg_playback_mode)
  435. {
  436. player_dmusic_imm * p=new player_dmusic_imm(this);
  437. if (p)
  438. {
  439. if (!p->play())
  440. {
  441. delete p;
  442. p=0;
  443. }
  444. }
  445. return p;
  446. }
  447. else
  448. {
  449. player_dmusic* p=new player_dmusic(this);
  450. if (p)
  451. {
  452. if (!p->play()) {delete p;p=0;}
  453. }
  454. return p;
  455. }
  456. }
  457. MUSIC_TIME GetMTforMS(IDirectMusicSegment* pS,DWORD ms)
  458. {
  459. MUSIC_TIME mtSeg,mct=0,mnt;
  460. DMUS_TEMPO_PARAM tp;
  461. pS->GetLength(&mtSeg);
  462. double _r=0,r1;
  463. while(mct<mtSeg)
  464. {
  465. if (FAILED(pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp))) break;
  466. if (!mnt) mnt=mtSeg-mct;
  467. r1=_r;
  468. _r+=(mnt)/tp.dblTempo*78;
  469. if (_r>ms)
  470. {
  471. return (MUSIC_TIME)(mct+mnt*((double)ms-r1)/(_r-r1));
  472. }
  473. mct+=mnt;
  474. }
  475. return mtSeg;
  476. }
  477. DWORD GetSegLen(IDirectMusicSegment* pS)
  478. {
  479. MUSIC_TIME mtSeg,mct=0,mnt;
  480. DMUS_TEMPO_PARAM tp;
  481. pS->GetLength(&mtSeg);
  482. double _r=0;
  483. while(mct<mtSeg)
  484. {
  485. pS->GetParam(GUID_TempoParam,-1,0,mct,&mnt,&tp);
  486. if (!mnt) mnt=mtSeg-mct;
  487. _r+=(double)mnt/tp.dblTempo*78;
  488. mct+=mnt;
  489. }
  490. return (DWORD)_r;
  491. }
  492. void ReleaseObject(IUnknown* o)
  493. {
  494. IDirectMusicObject* pObject=0;
  495. if (pLoader && SUCCEEDED(o->QueryInterface(IID_IDirectMusicObject,(void**)&pObject)))
  496. {
  497. pLoader->ReleaseObject(pObject);
  498. pObject->Release();
  499. }
  500. }
  501. player_dmusic::~player_dmusic()
  502. {
  503. pPerf->Stop(0,0,0,0);
  504. if (pPort) pPort->Activate(0);
  505. // pPerf->Invalidate(0,0);
  506. mtOffset=0;
  507. rtOffset=0;
  508. mtStart=0;
  509. rtStart=0;
  510. if (pSS) {pSS->Release();pSS=0;}
  511. if (pSeg)
  512. {
  513. if (dloaded) pSeg->SetParam(GUID_Unload,0xFFFFFFFF,0,0,(void*)pPerf);
  514. pSeg->Release();
  515. pSeg=0;
  516. }
  517. if (pHack)
  518. {
  519. pPort->SetDirectSound(0,0);
  520. pHack->Release();
  521. pHack=0;
  522. }
  523. if (!cfg_dm_keep_port) PortKill();
  524. if (timer_id) KillTimer(0,timer_id);
  525. }
  526. void player_dmusic::pause()
  527. {
  528. MUSIC_TIME mt;
  529. REFERENCE_TIME rt;
  530. pPerf->Stop(0,0,0,0);
  531. if (pSS)
  532. {
  533. pSS->Release();
  534. pSS=0;
  535. }
  536. pPerf->GetTime(&rt,&mt);
  537. mtOffset+=mt-mtStart;
  538. rtOffset+=rt-rtStart;
  539. pSeg->SetStartPoint(mtOffset);
  540. paused=1;
  541. }
  542. void player_dmusic::unpause()
  543. {
  544. if (pSS)
  545. {
  546. pSS->Release();
  547. pSS=0;
  548. }
  549. if (SUCCEEDED(pPerf->PlaySegment(pSeg,0,0,&pSS)))
  550. {
  551. pSS->GetStartTime(&mtStart);
  552. pPerf->MusicToReferenceTime(mtStart,&rtStart);
  553. }
  554. paused=0;
  555. }
  556. int player_dmusic::gettime()
  557. {
  558. static DWORD tm;
  559. if (pSS)
  560. {
  561. REFERENCE_TIME rt;
  562. pPerf->GetTime(&rt,0);
  563. tm=(int)((rt-rtStart+rtOffset)/10000);
  564. }
  565. return tm;
  566. }
  567. int player_dmusic::play()
  568. {
  569. #ifdef USE_LOG
  570. log_write("player_dmusic::play()");
  571. #endif
  572. if (!PortInit(dev)) return 0;
  573. pSeg=LoadSegment(MIDI_core::getFile());
  574. if (!pSeg)
  575. {
  576. #ifdef USE_LOG
  577. log_write("LoadSegment() failed");
  578. #endif
  579. // Error("Unable to get IDirectMusicSegment.");
  580. return 0;
  581. }
  582. #ifdef USE_LOG
  583. log_write("player_dmusic::play() : got IDirectMusicSegment");
  584. #endif
  585. pSeg->SetRepeats( (cfg_loop_type==2 || (cfg_loop_type==1 && MIDI_core::getFile()->loopstart)) ? (cfg_loop_infinite ? -1 : cfg_loop_count-1) : 0);
  586. dloaded=0;
  587. if (dev->has_dls())
  588. if (SUCCEEDED(pSeg->SetParam(GUID_Download,-1,0,0,(void*)pPerf)))
  589. dloaded=1;
  590. pSeg->SetStartPoint(0);
  591. #ifdef USE_LOG
  592. log_write("Activating port...");
  593. #endif
  594. pPort->Activate(1);
  595. #ifdef USE_LOG
  596. log_write("IDirectMusicPort::Activate() returned");
  597. #endif
  598. sysex_startup((SYSEXFUNC)SendSysex,pPerf);
  599. #ifdef USE_LOG
  600. log_write("IDirectMusicPerformance::PlaySegment()");
  601. #endif
  602. pSS=0;
  603. DM_setvol(MIDI_core::player_getVol());
  604. if (FAILED(pPerf->PlaySegment(pSeg,DMUS_SEGF_DEFAULT,0,&pSS)))
  605. {
  606. // Error("IDirectMusicPerformance::PlaySegment() failed.");
  607. return 0;
  608. }
  609. #ifdef USE_LOG
  610. log_write("IDirectMusicPerformance::PlaySegment() returned OK");
  611. #endif
  612. rtOffset=0;
  613. if (pSS)
  614. {
  615. pSS->GetStartTime(&mtStart);
  616. }
  617. else
  618. {
  619. #ifdef USE_LOG
  620. log_write("no segment starte. WTF ?");
  621. #endif
  622. mtStart=0;
  623. }
  624. pPerf->MusicToReferenceTime(mtStart,&rtStart);
  625. timer_id=SetTimer(0,0,33,(TIMERPROC)TimerProc);
  626. return 1;
  627. }
  628. static struct
  629. {
  630. int name;
  631. UINT flag;
  632. } DMCAPZ[]=
  633. {
  634. /*
  635. #define DMUS_PC_DLS (0x00000001) // Supports DLS downloading and DLS level 1.
  636. #define DMUS_PC_EXTERNAL (0x00000002) // External MIDI module.
  637. #define DMUS_PC_SOFTWARESYNTH (0x00000004) // Software synthesizer.
  638. #define DMUS_PC_MEMORYSIZEFIXED (0x00000008) // Memory size is fixed.
  639. #define DMUS_PC_GMINHARDWARE (0x00000010) // GM sound set is built in, no need to download.
  640. #define DMUS_PC_GSINHARDWARE (0x00000020) // GS sound set is built in.
  641. #define DMUS_PC_XGINHARDWARE (0x00000040) // XG sound set is built in.
  642. #define DMUS_PC_DIRECTSOUND (0x00000080) // Connects to DirectSound via a DSound buffer.
  643. #define DMUS_PC_SHAREABLE (0x00000100) // Synth can be actively shared by multiple apps at once.
  644. #define DMUS_PC_DLS2 (0x00000200) // Supports DLS2 instruments.
  645. #define DMUS_PC_AUDIOPATH (0x00000400) // Multiple outputs can be connected to DirectSound for audiopaths.
  646. #define DMUS_PC_WAVE (0x00000800) // Supports streaming and one shot waves.
  647. */
  648. {STRING_DMCAPS_DLS1,DMUS_PC_DLS},
  649. {STRING_DMCAPS_DLS2,DMUS_PC_DLS2},
  650. {STRING_DMCAPS_SOFTSYNTH,DMUS_PC_SOFTWARESYNTH},
  651. {STRING_DMCAPS_GM,DMUS_PC_GMINHARDWARE},
  652. {STRING_DMCAPS_GS,DMUS_PC_GSINHARDWARE},
  653. {STRING_DMCAPS_XG,DMUS_PC_XGINHARDWARE},
  654. // {STRING_DMCAPS_DSOUND,DMUS_PC_DIRECTSOUND},
  655. {STRING_DMCAPS_SHARE,DMUS_PC_SHAREABLE},
  656. };
  657. #define N_DMCAPZ (sizeof(DMCAPZ)/sizeof(DMCAPZ[0]))
  658. static struct
  659. {
  660. int name;
  661. UINT flag;
  662. } DMCAPZ1[]= //effects
  663. {
  664. {STRING_REVERB,DMUS_EFFECT_REVERB},
  665. {STRING_CHORUS,DMUS_EFFECT_CHORUS},
  666. };
  667. #define N_DMCAPZ1 (sizeof(DMCAPZ1)/sizeof(DMCAPZ1[0]))
  668. int player_dmusic::settime(int tm)
  669. {
  670. int rv;
  671. #ifdef USE_LOG
  672. log_write("player_dmusic::settime");
  673. #endif
  674. rtOffset=UInt32x32To64(tm,10000);
  675. #ifdef USE_LOG
  676. log_write("calling IDirectMusicPerformance::Stop()");
  677. #endif
  678. if (!paused)
  679. {
  680. #ifdef USE_LOG
  681. log_write("IDirectMusicPerformance::Stop() returned");
  682. #endif
  683. if (pSS) {pSS->Release();pSS=0;}
  684. }
  685. // not ideal but a pause, seek and unpause seems to resolve a failed seek issue
  686. // with the 'Direct Music / Microsoft Synthesizer' and 'streamed' output mode
  687. pause();
  688. MUSIC_TIME time=GetMTforMS(pSeg,tm);
  689. rv = SUCCEEDED( pSeg->SetStartPoint(time) );
  690. if (rv) mtOffset=time;
  691. unpause();
  692. if (!paused)
  693. {
  694. #ifdef USE_LOG
  695. log_write("calling IDirectMusicPerformance::PlaySegment()");
  696. #endif
  697. pSS=0;
  698. pPerf->PlaySegment(pSeg,0,0,&pSS);
  699. if (pSS) pSS->GetStartTime(&mtStart);
  700. pPerf->MusicToReferenceTime(mtStart,&rtStart);
  701. }
  702. return rv;
  703. }
  704. BOOL test_ins_dls(DWORD patch,IDirectMusicCollection* pDLS)
  705. {
  706. IDirectMusicInstrument *pi=0;
  707. BOOL rv=0;
  708. if (SUCCEEDED(pDLS->GetInstrument(patch,&pi)))
  709. {
  710. pi->Release();
  711. rv=1;
  712. }
  713. return rv;
  714. }
  715. int test_drum_kit(DWORD no,IDirectMusicCollection* dls)
  716. {
  717. DWORD p=no|0x80000000;
  718. if (pGM)
  719. if (test_ins_dls(p,pGM)) return 1;
  720. if (pCDLS)
  721. if (test_ins_dls(p,pCDLS)) return 1;
  722. if (dls)
  723. if (test_ins_dls(p,dls)) return 1;
  724. return 0;
  725. }
  726. void do_dls_check(DWORD * i,IDirectMusicCollection * dls)
  727. {
  728. start:
  729. if (pGM)
  730. if (test_ins_dls(*i,pGM)) return;
  731. if (pCDLS)
  732. if (test_ins_dls(*i,pCDLS)) return;
  733. if (dls)
  734. if (test_ins_dls(*i,dls)) return;
  735. //hack hack hack
  736. if (*i&0xFF00)
  737. {
  738. *i&=0xFF00FF;
  739. goto start;
  740. }
  741. if (*i&0xFF0000)
  742. {
  743. *i&=0xFF;
  744. return;
  745. }
  746. }
  747. static cfg_int cfg_show_all("dmusic_show_all",0);
  748. class MIDI_driver_dmusic : MIDI_driver
  749. {
  750. bool dm_inited;
  751. virtual void do_init()
  752. {
  753. dm_inited=1;
  754. try {
  755. #ifdef USE_LOG
  756. log_write("CoInitialize()");
  757. #endif
  758. CoInitialize(0);
  759. #ifdef USE_LOG
  760. log_write("CoCreateInstance / IDirectMusic");
  761. #endif
  762. IDirectMusic* pDM=0;
  763. if (SUCCEEDED(CoCreateInstance(CLSID_DirectMusic,0,CLSCTX_INPROC,IID_IDirectMusic,(void**)&pDM)) && pDM)
  764. {
  765. #ifdef USE_LOG
  766. log_write("IDirectMusic created OK");
  767. #endif
  768. DMUS_PORTCAPS dmpc;
  769. memset(&dmpc,0,sizeof(dmpc));
  770. dmpc.dwSize=sizeof(dmpc);
  771. UINT np=0;
  772. GUID def;
  773. pDM->GetDefaultPort(&def);
  774. while(1)
  775. {
  776. if (pDM->EnumPort(np++,&dmpc)==S_FALSE) break;
  777. if (dmpc.dwClass==DMUS_PC_OUTPUTCLASS && (cfg_show_all || (dmpc.dwType!=DMUS_PORT_WINMM_DRIVER && dmpc.dwType==DMUS_PORT_KERNEL_MODE) || (dmpc.dwFlags&DMUS_PC_DLS) ))
  778. {
  779. wchar_t name_mbs[2*DMUS_MAX_DESCRIPTION] = {0};
  780. wcsncpy(name_mbs,dmpc.wszDescription,256);
  781. string_w info;
  782. {
  783. if (dmpc.dwType<3)
  784. {
  785. int dmport_types[3]={STRING_DMCAPS_WINMM,STRING_DMCAPS_USERMODE,STRING_DMCAPS_WDM};
  786. info+=WASABI_API_LNGSTRINGW(STRING_DEVICE_TYPE);
  787. info+=WASABI_API_LNGSTRINGW(dmport_types[dmpc.dwType]);
  788. info+=L"\x0d\x0a";
  789. }
  790. UINT z;
  791. for(z=0;z<N_DMCAPZ;z++)
  792. {
  793. if (dmpc.dwFlags & DMCAPZ[z].flag)
  794. {
  795. info+=WASABI_API_LNGSTRINGW(DMCAPZ[z].name);
  796. info+=L"\x0d\x0a";
  797. }
  798. }
  799. UINT n_effects=0;
  800. for(z=0;z<N_DMCAPZ1;z++)
  801. {
  802. if (dmpc.dwEffectFlags&DMCAPZ1[z].flag)
  803. {
  804. info+=n_effects ? L", " : WASABI_API_LNGSTRINGW(STRING_EFFECTS);
  805. info+=WASABI_API_LNGSTRINGW(DMCAPZ1[z].name);
  806. n_effects++;
  807. }
  808. }
  809. if (n_effects) info+=L"\x0d\x0a";
  810. }
  811. add_device(new MIDI_device_dmusic(dmpc.guidPort,0,dmpc.dwFlags,name_mbs,info));
  812. if ((dmpc.dwFlags&DMUS_PC_DIRECTSOUND)&&(dmpc.dwFlags&DMUS_PC_SOFTWARESYNTH))
  813. {
  814. wcscat(name_mbs,WASABI_API_LNGSTRINGW(IDS_WITH_OUTPUT));
  815. info+=WASABI_API_LNGSTRINGW(IDS_USES_WINAMPS_OUTPUT_PLUGINS);
  816. add_device(new MIDI_device_dmusic(dmpc.guidPort,1,dmpc.dwFlags,name_mbs,info));
  817. }
  818. }
  819. }
  820. pDM->Release();
  821. }
  822. } catch(...) {
  823. // bewm.
  824. reset_devices();
  825. }
  826. }
  827. virtual const wchar_t * get_name() {return L"DirectMusic";}
  828. virtual GUID get_guid() {return dmusic_driver_guid;}
  829. public:
  830. MIDI_driver_dmusic() {dm_inited=0;}
  831. protected:
  832. void do_deinit()
  833. {
  834. if (!dm_inited) return;
  835. if (pGM)
  836. {
  837. pGM->Release();
  838. pGM=0;
  839. }
  840. if (pCDLS) {pCDLS->Release();pCDLS=0;}
  841. if (pLoader) {pLoader->Release();pLoader=0;}
  842. if (pPort) PortKill();
  843. if (pDM)
  844. {
  845. pDM->Release();
  846. pDM=0;
  847. }
  848. if (pPerf)
  849. {
  850. pPerf->CloseDown();
  851. pPerf->Release();
  852. pPerf=0;
  853. }
  854. CoUninitialize();
  855. }
  856. };
  857. static MIDI_driver_dmusic midi_driver_dmusic;