wa3.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. #include "../studio/services/svc_mediaconverter.h"
  2. #include "../studio/wac.h"
  3. #include "../common/rootcomp.h"
  4. #include "../studio/services/svc_action.h"
  5. #include "../unpack/unpack_helper.h"
  6. #include "main.h"
  7. #define WACNAME WACcnv_midi
  8. class WACNAME : public WAComponentClient{
  9. public:
  10. WACNAME();
  11. virtual ~WACNAME();
  12. virtual const char *getName() { return NAME; };
  13. virtual GUID getGUID();
  14. virtual void onCreate();
  15. virtual void onDestroy();
  16. virtual int getDisplayComponent() { return FALSE; };
  17. virtual CfgItem *getCfgInterface(int n) { return this; }
  18. private:
  19. };
  20. static WACNAME wac;
  21. WAComponentClient *the = &wac;
  22. // {28FDCD38-26A2-482c-A691-55901A355D9E}
  23. static const GUID guid =
  24. { 0x28fdcd38, 0x26a2, 0x482c, { 0xa6, 0x91, 0x55, 0x90, 0x1a, 0x35, 0x5d, 0x9e } };
  25. GUID WACNAME::getGUID() {
  26. return guid;
  27. }
  28. static void update_extensions()
  29. {
  30. static int old_mask;
  31. int new_mask = cfg_ext_mask;
  32. int n;
  33. for(n=0;n<MIDI_core::FileTypes_GetNum();n++)
  34. {
  35. int bit = 1<<n;
  36. if ( (new_mask & bit) && !(old_mask & bit) )
  37. api->core_registerExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n)),MIDI_core::FileTypes_GetDescription(n),"Audio");
  38. else if ( !(new_mask & bit) && (old_mask & bit) )
  39. {
  40. api->core_unregisterExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n)));
  41. }
  42. }
  43. old_mask = new_mask;
  44. }
  45. void WACNAME::onCreate()
  46. {
  47. // {EDAA0599-3E43-4eb5-A65D-C0A0484240E7}
  48. static const GUID cfg_audio_guid =
  49. { 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } };
  50. registerSkinFile("xml/midi-prefs.xml");
  51. api->preferences_registerGroup("winamp.preferences.midi", "MIDI playback", guid, cfg_audio_guid);
  52. MIDI_core::GlobalInit();
  53. update_extensions();
  54. }
  55. void WACNAME::onDestroy() {
  56. MIDI_core::GlobalQuit();
  57. }
  58. static void check_messages()
  59. {
  60. MSG msg;
  61. while(PeekMessage(&msg,0,0,0,PM_REMOVE))
  62. DispatchMessage(&msg);
  63. }
  64. //note: multiinstance support is NOT working, and will never be; it makes no sense anyway. also, multiinstance safety was totally fuct in directmusic drivers last time i bothered trying.
  65. class cnv_MIDI : public svc_mediaConverterI {
  66. private:
  67. static critical_section core_owner_sync;
  68. static cnv_MIDI * core_owner;
  69. DWORD thread_id;
  70. MemBlock<char> sample_buffer;
  71. MIDI_file * file;
  72. int is_open;
  73. int eof_flag;
  74. void core_reset()
  75. {
  76. core_owner_sync.enter();
  77. if (core_owner==this) {core_owner=0;MIDI_core::Close();}
  78. core_owner_sync.leave();
  79. if (file) {file->Free();file=0;}
  80. is_open=0;
  81. eof_flag=0;
  82. }
  83. int core_takeover()
  84. {
  85. core_owner_sync.enter();
  86. if (core_owner!=this)
  87. {
  88. if (core_owner!=0) {core_owner_sync.leave();return 0;}
  89. core_owner=this;
  90. thread_id = GetCurrentThreadId();
  91. MIDI_core::Init();
  92. }
  93. core_owner_sync.leave();
  94. return 1;
  95. }
  96. int check_file(MediaInfo * infos)
  97. {
  98. if (file && !STRICMP(file->path,infos->getFilename())) return 1;
  99. core_reset();
  100. MemBlock<char> data;
  101. int size;
  102. try {
  103. svc_fileReader * reader = infos->getReader();
  104. if (!reader) return 0;
  105. size = reader->getLength();
  106. if (size<=0) return 0;
  107. reader->seek(0);
  108. int firstread = size > 256 ? 256 : size;
  109. data.setSize(firstread);
  110. if (reader->read(data.getMemory(),firstread)!=firstread) return 0;
  111. if (MIDI_file::HeaderTest(data.getMemory(),size))
  112. {
  113. if (firstread != size)
  114. {
  115. if (data.setSize(size)==0) return 0;
  116. if (reader->read(data.getMemory()+firstread,size-firstread)!=size-firstread) return 0;
  117. }
  118. }
  119. else
  120. {
  121. void * unpack = unpack_helper::unpack_getHandle(reader);
  122. if (!unpack) return 0;
  123. size = api->fileGetFileSize(unpack);
  124. firstread = size > 256 ? 256 : size;
  125. data.setSize(firstread);
  126. if (api->fileRead(data.getMemory(),firstread,unpack)!=firstread) {api->fileClose(unpack);return 0;}
  127. if (!MIDI_file::HeaderTest(data.getMemory(),size)) {api->fileClose(unpack);return 0;}
  128. if (firstread != size)
  129. {
  130. if (data.setSize(size)==0) {api->fileClose(unpack);return 0;}
  131. if (api->fileRead(data.getMemory()+firstread,size-firstread,unpack)!=size-firstread) {api->fileClose(unpack);return 0;}
  132. }
  133. api->fileClose(unpack);
  134. }
  135. file = MIDI_file::Create(infos->getFilename(),data.getMemory(),size);
  136. return !!file;
  137. }
  138. catch(...)
  139. {
  140. file = 0;
  141. return 0;
  142. }
  143. }
  144. public:
  145. static const char *getServiceName() { return NAME; }
  146. cnv_MIDI()
  147. {
  148. file=0;
  149. is_open=0;
  150. eof_flag=0;
  151. thread_id=0;
  152. }
  153. ~cnv_MIDI()
  154. {
  155. core_reset();
  156. }
  157. virtual int canConvertFrom(svc_fileReader *reader, const char *name, const char *chunktype)
  158. {
  159. return reader && !chunktype && name && MIDI_core::IsOurFile(name);
  160. }
  161. virtual const char *getConverterTo()
  162. {
  163. if (!core_takeover()) return "FINAL";
  164. return MIDI_core::UsesOutput() ? "PCM" : "FINAL";
  165. }
  166. virtual int getInfos(MediaInfo *infos)
  167. {
  168. if (!check_file(infos)) return 0;
  169. infos->setTitle(Std::filename(file->path));
  170. infos->setLength(file->len);
  171. infos->setInfo(
  172. StringPrintf("%sMIDI %i channels",
  173. file->info.e_type ? StringPrintf("%s ",file->info.e_type) : ""
  174. ,file->info.channels)
  175. );
  176. return 1;
  177. }
  178. virtual int processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch)
  179. {
  180. if (!check_file(infos)) return 0;
  181. if (!core_takeover()) return 0;
  182. if (!is_open)
  183. {
  184. MIDI_core::SetVolume(api->core_getVolume(m_coretoken));
  185. MIDI_core::SetPan(api->core_getPan(m_coretoken));
  186. if (!MIDI_core::OpenFile(file))
  187. return 0;
  188. is_open=1;
  189. eof_flag=0;
  190. }
  191. check_messages();
  192. if (!MIDI_core::HavePCM()) {Sleep(1);check_messages();return eof_flag ? 0 : 1;}
  193. else
  194. {
  195. int srate,nch,bps;
  196. int size;
  197. MIDI_core::GetPCM(&srate,&nch,&bps);
  198. size = 576 * nch * (bps/8);
  199. if (sample_buffer.getSize()<size) sample_buffer.setSize(size);
  200. size = MIDI_core::GetSamples(sample_buffer.getMemory(),size,(char*)killswitch);
  201. if (size<=0)
  202. return 0;
  203. ChunkInfosI *ci=new ChunkInfosI();
  204. ci->addInfo("srate",srate);
  205. ci->addInfo("bps",bps);
  206. ci->addInfo("nch",nch);
  207. chunk_list->setChunk("PCM",sample_buffer.getMemory(),size,ci);
  208. return 1;
  209. }
  210. }
  211. virtual int getLatency(void) { return 0; }
  212. // callbacks
  213. virtual int corecb_onSeeked(int newpos)
  214. {
  215. if (core_owner==this) MIDI_core::SetPosition(newpos);
  216. return 0;
  217. }
  218. int getPosition(void)
  219. {
  220. if (core_owner==this && !MIDI_core::UsesOutput()) return MIDI_core::GetPosition();
  221. return -1;
  222. }
  223. virtual int corecb_onVolumeChange(int v)
  224. {
  225. if (core_owner==this) MIDI_core::SetVolume(v);
  226. return 0;
  227. }
  228. virtual int corecb_onPanChange(int v)
  229. {
  230. if (core_owner==this) MIDI_core::SetPan(v);
  231. return 0;
  232. }
  233. virtual int corecb_onAbortCurrentSong() {return 0;};
  234. virtual int corecb_onPaused()
  235. {
  236. if (core_owner==this) MIDI_core::Pause(1);
  237. return 0;
  238. }
  239. virtual int corecb_onUnpaused()
  240. {
  241. if (core_owner==this) MIDI_core::Pause(0);
  242. return 0;
  243. }
  244. static void notify_eof()
  245. {
  246. core_owner_sync.enter();
  247. if (core_owner) core_owner->eof_flag=1;
  248. core_owner_sync.leave();
  249. }
  250. static DWORD get_core_thread()
  251. {
  252. DWORD ret = 0;
  253. core_owner_sync.enter();
  254. if (core_owner) ret = core_owner->thread_id;
  255. core_owner_sync.leave();
  256. return ret;
  257. }
  258. };
  259. cnv_MIDI * cnv_MIDI::core_owner=0;
  260. critical_section cnv_MIDI::core_owner_sync;
  261. static waServiceFactoryT<svc_mediaConverter, cnv_MIDI> midi_svc;
  262. #define ACTIONID_CONFIG "MIDI:CONFIG"
  263. class MIDI_actions : public svc_actionI {
  264. public:
  265. MIDI_actions() {
  266. registerAction(ACTIONID_CONFIG, 0);
  267. }
  268. virtual ~MIDI_actions() { }
  269. virtual int onActionId(int id, const char *action, const char *param,int,int,void*,int,RootWnd*) {
  270. switch (id) {
  271. case 0:
  272. if (!_stricmp(action,ACTIONID_CONFIG))
  273. {
  274. if (MIDI_core::Config(MIDI_callback::GetMainWindow()))
  275. {
  276. update_extensions();
  277. }
  278. }
  279. return 1;
  280. }
  281. return 0;
  282. }
  283. static const char *getServiceName() { return "MIDI Player Actions Service"; }
  284. };
  285. static waServiceFactoryTSingle<svc_actionI, MIDI_actions> actions;
  286. WACNAME::WACNAME() {
  287. #ifdef FORTIFY
  288. FortifySetName("cnv_midi.wac");
  289. FortifyEnterScope();
  290. #endif
  291. registerService(&midi_svc);
  292. registerService(&actions);
  293. }
  294. WACNAME::~WACNAME() {
  295. #ifdef FORTIFY
  296. FortifyLeaveScope();
  297. #endif
  298. }
  299. void MIDI_callback::NotifyEOF() {cnv_MIDI::notify_eof();}
  300. HWND MIDI_callback::GetMainWindow() {return api->main_getRootWnd()->gethWnd();}
  301. HINSTANCE MIDI_callback::GetInstance() {return wac.gethInstance();}
  302. void MIDI_callback::Error(const char * tx) {}
  303. void MIDI_callback::Idle(int ms)
  304. {
  305. int core_thread = (GetCurrentThreadId() == cnv_MIDI::get_core_thread());
  306. int start = timeGetTime();
  307. do {
  308. if (core_thread) check_messages();
  309. Sleep(1);
  310. } while((int)timeGetTime() - start < ms);
  311. if (core_thread) check_messages();
  312. }
  313. extern "C" {
  314. BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
  315. {
  316. if (r==DLL_PROCESS_ATTACH)
  317. {
  318. DisableThreadLibraryCalls((HMODULE)hMod);
  319. }
  320. return 1;
  321. }
  322. }