cnv_pcmwaveout.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "cnv_pcmwaveout.h"
  2. #include <mmsystem.h>
  3. #include "waveout.h"
  4. #include "../studio/services/svc_textfeed.h"
  5. #define FEEDID_DEVICELIST "waveOut:DEVICES"
  6. static String * devlist;
  7. static UINT n_devs;
  8. #define DEVICE_DEFAULT "(default device)" //trick: use this string for default wave mapper, without querying device names and shit
  9. _string cfg_dev("Device",DEVICE_DEFAULT);
  10. static void devlist_init()
  11. {
  12. if (devlist) return;
  13. n_devs=waveOutGetNumDevs()+1;
  14. UINT n;
  15. WAVEOUTCAPS caps;
  16. devlist=new String[n_devs];
  17. for(n=0;n<n_devs;n++)
  18. {
  19. if (waveOutGetDevCaps(n-1,&caps,sizeof(caps))==MMSYSERR_NOERROR)
  20. {
  21. devlist[n]=caps.szPname;
  22. }
  23. }
  24. }
  25. class TextFeed : public svc_textFeedI {
  26. public:
  27. TextFeed() {
  28. registerFeed(FEEDID_DEVICELIST); // we output shit in <List> objects whose feed param is "DirectSound::DEVICES"
  29. }
  30. static const char *getServiceName() { return "waveOut TextFeed Service"; }
  31. protected:
  32. virtual void registerCallback(const char *feedid, TextFeedCallback *cb)
  33. {
  34. if (!STRICMP(feedid,FEEDID_DEVICELIST))
  35. {//HACK: nice delayed init - don't query device list before we really need to, for really short loading time
  36. static bool inited;
  37. if (!inited)
  38. {
  39. inited=1;
  40. devlist_init();
  41. String feed_devlist="";
  42. UINT n;
  43. for(n=0;n<n_devs;n++)
  44. {
  45. if (!feed_devlist.isempty()) feed_devlist += ";";
  46. feed_devlist+=devlist[n];
  47. }
  48. sendFeed(FEEDID_DEVICELIST, feed_devlist);
  49. if (!strcmp(cfg_dev,DEVICE_DEFAULT)) cfg_dev=devlist[0];
  50. }
  51. }
  52. svc_textFeedI::registerCallback(feedid,cb);
  53. }
  54. };
  55. static waServiceTSingle<svc_textFeed, TextFeed> g_feed;
  56. _int cfg_buf_ms("Buffer length (ms)",2000);
  57. _int cfg_prebuf("Prebuffer (ms)",0);
  58. _bool cfg_vol_enabled("Volume control enabled",1);
  59. _bool cfg_vol_alt("Alt volume control method",0);
  60. _bool cfg_vol_reset("Reset volume on stop",0);
  61. class cnv_pcmwaveout: public svc_mediaConverterI {
  62. private:
  63. WaveOut * pWO;
  64. int fmt_sr,fmt_bps,fmt_nch;
  65. public:
  66. cnv_pcmwaveout()
  67. {
  68. pWO = 0;
  69. fmt_sr = 0;
  70. fmt_bps = 0;
  71. fmt_nch = 0;
  72. }
  73. ~cnv_pcmwaveout()
  74. {
  75. if (pWO) delete pWO;
  76. }
  77. static const char *getServiceName() { return "WaveOut Output"; }
  78. virtual int canConvertFrom(svc_fileReader *reader, const char *name, const char *chunktype) {
  79. if(chunktype && !STRICMP(chunktype,"pcm")) return 1;
  80. return 0;
  81. }
  82. virtual const char *getConverterTo() { return "OUTPUT:waveOut"; }
  83. virtual int getInfos(MediaInfo *infos) {return 0;}
  84. virtual int processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch)
  85. {
  86. Chunk * c=chunk_list->getChunk("PCM");
  87. if (!c) return 0;
  88. char * data=(char*)c->getData();
  89. int size=c->getSize();
  90. if (size<=0) {
  91. if (pWO && infos->getData("audio_need_canwrite")) infos->setDataInt("audio_canwrite",pWO->CanWrite(),FALSE);
  92. return 1;
  93. }
  94. int sr,bps,nch;
  95. sr=c->getInfo("srate");
  96. bps=c->getInfo("bps");
  97. nch=c->getInfo("nch");
  98. if (pWO && (fmt_sr!=sr || fmt_bps!=bps || fmt_nch!=nch))
  99. {
  100. while(!*killswitch && pWO->GetLatency()>0) Sleep(1);
  101. delete pWO;
  102. pWO=0;
  103. }
  104. if (*killswitch) return 0;
  105. if (!pWO)
  106. {
  107. fmt_sr=sr;
  108. fmt_bps=bps;
  109. fmt_nch=nch;
  110. WaveOutConfig cfg;
  111. cfg.SetPCM(sr,nch,bps);
  112. cfg.SetBuffer(cfg_buf_ms,cfg_prebuf);
  113. const char * devname=cfg_dev;
  114. if (_stricmp(devname,DEVICE_DEFAULT))
  115. {
  116. devlist_init();
  117. for(UINT n=0;n<n_devs;n++)
  118. {
  119. if (!_stricmp(devname,devlist[n]))
  120. {
  121. cfg.SetDevice(n);
  122. break;
  123. }
  124. }
  125. }
  126. cfg.SetVolumeSetup(cfg_vol_enabled,cfg_vol_alt,cfg_vol_reset);
  127. pWO=WaveOut::Create(&cfg);
  128. if (!pWO)
  129. {
  130. //todo: cfg.GetError() yadda yadda
  131. return 0;
  132. }
  133. pWO->SetVolume(api->core_getVolume(m_coretoken));
  134. pWO->SetPan(api->core_getPan(m_coretoken));
  135. }
  136. while(!*killswitch)
  137. {
  138. int d=pWO->WriteData(data,size);
  139. if (d>0)
  140. {
  141. size-=d;
  142. if (size<=0) break;
  143. data+=d;
  144. }
  145. Sleep(1);
  146. }
  147. return 1;
  148. }
  149. virtual int getLatency(void) {return pWO ? pWO->GetLatency() : 0;}
  150. virtual int corecb_onSeeked(int newpos) {if (pWO) pWO->Flush();return 0;}
  151. virtual int corecb_onVolumeChange(int v) {pWO->SetVolume(v);return 0;}
  152. virtual int corecb_onPanChange(int v) {pWO->SetPan(v);return 0;}
  153. virtual int corecb_onAbortCurrentSong() {if (pWO) pWO->Flush();return 0;}
  154. virtual int corecb_onPaused() {if (pWO) pWO->Pause(1);return 0;}
  155. virtual int corecb_onUnpaused() {if (pWO) pWO->Pause(0);return 0;}
  156. };
  157. static WACNAME wac;
  158. WAComponentClient *the = &wac;
  159. #include "../studio/services/servicei.h"
  160. static waServiceT<svc_mediaConverter, cnv_pcmwaveout> waveout;
  161. // {E91551F2-E1CE-4484-B331-B3BE2B754B52}
  162. static const GUID guid =
  163. { 0xe91551f2, 0xe1ce, 0x4484, { 0xb3, 0x31, 0xb3, 0xbe, 0x2b, 0x75, 0x4b, 0x52 } };
  164. WACNAME::WACNAME() {
  165. #ifdef FORTIFY
  166. FortifySetName("cnv_pcmwaveout.wac");
  167. FortifyEnterScope();
  168. #endif
  169. registerService(&g_feed);//autoderegistered on shutdown
  170. registerService(&waveout);
  171. registerSkinFile("Wacs/xml/waveout/waveout-prefs.xml");
  172. }
  173. WACNAME::~WACNAME() {
  174. #ifdef FORTIFY
  175. FortifyLeaveScope();
  176. #endif
  177. if (devlist)
  178. {
  179. delete[] devlist;
  180. devlist=0;
  181. }
  182. n_devs=0;
  183. }
  184. GUID WACNAME::getGUID() {
  185. return guid;
  186. }
  187. void WACNAME::onDestroy() {
  188. }
  189. void WACNAME::onCreate()
  190. {
  191. // {EDAA0599-3E43-4eb5-A65D-C0A0484240E7}
  192. static const GUID cfg_audio_guid =
  193. { 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } };
  194. api->preferences_registerGroup("waveout", "waveOut", guid, cfg_audio_guid);
  195. registerAttribute(&cfg_dev);
  196. registerAttribute(&cfg_buf_ms);
  197. registerAttribute(&cfg_prebuf);
  198. registerAttribute(&cfg_vol_enabled);
  199. registerAttribute(&cfg_vol_alt);
  200. registerAttribute(&cfg_vol_reset);
  201. }