#include "../studio/services/svc_mediaconverter.h" #include "../studio/wac.h" #include "../common/rootcomp.h" #include "../studio/services/svc_action.h" #include "../unpack/unpack_helper.h" #include "main.h" #define WACNAME WACcnv_midi class WACNAME : public WAComponentClient{ public: WACNAME(); virtual ~WACNAME(); virtual const char *getName() { return NAME; }; virtual GUID getGUID(); virtual void onCreate(); virtual void onDestroy(); virtual int getDisplayComponent() { return FALSE; }; virtual CfgItem *getCfgInterface(int n) { return this; } private: }; static WACNAME wac; WAComponentClient *the = &wac; // {28FDCD38-26A2-482c-A691-55901A355D9E} static const GUID guid = { 0x28fdcd38, 0x26a2, 0x482c, { 0xa6, 0x91, 0x55, 0x90, 0x1a, 0x35, 0x5d, 0x9e } }; GUID WACNAME::getGUID() { return guid; } static void update_extensions() { static int old_mask; int new_mask = cfg_ext_mask; int n; for(n=0;ncore_registerExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n)),MIDI_core::FileTypes_GetDescription(n),"Audio"); else if ( !(new_mask & bit) && (old_mask & bit) ) { api->core_unregisterExtension(StringPrintf("*.%s",MIDI_core::FileTypes_GetExtension(n))); } } old_mask = new_mask; } void WACNAME::onCreate() { // {EDAA0599-3E43-4eb5-A65D-C0A0484240E7} static const GUID cfg_audio_guid = { 0xedaa0599, 0x3e43, 0x4eb5, { 0xa6, 0x5d, 0xc0, 0xa0, 0x48, 0x42, 0x40, 0xe7 } }; registerSkinFile("xml/midi-prefs.xml"); api->preferences_registerGroup("winamp.preferences.midi", "MIDI playback", guid, cfg_audio_guid); MIDI_core::GlobalInit(); update_extensions(); } void WACNAME::onDestroy() { MIDI_core::GlobalQuit(); } static void check_messages() { MSG msg; while(PeekMessage(&msg,0,0,0,PM_REMOVE)) DispatchMessage(&msg); } //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. class cnv_MIDI : public svc_mediaConverterI { private: static critical_section core_owner_sync; static cnv_MIDI * core_owner; DWORD thread_id; MemBlock sample_buffer; MIDI_file * file; int is_open; int eof_flag; void core_reset() { core_owner_sync.enter(); if (core_owner==this) {core_owner=0;MIDI_core::Close();} core_owner_sync.leave(); if (file) {file->Free();file=0;} is_open=0; eof_flag=0; } int core_takeover() { core_owner_sync.enter(); if (core_owner!=this) { if (core_owner!=0) {core_owner_sync.leave();return 0;} core_owner=this; thread_id = GetCurrentThreadId(); MIDI_core::Init(); } core_owner_sync.leave(); return 1; } int check_file(MediaInfo * infos) { if (file && !STRICMP(file->path,infos->getFilename())) return 1; core_reset(); MemBlock data; int size; try { svc_fileReader * reader = infos->getReader(); if (!reader) return 0; size = reader->getLength(); if (size<=0) return 0; reader->seek(0); int firstread = size > 256 ? 256 : size; data.setSize(firstread); if (reader->read(data.getMemory(),firstread)!=firstread) return 0; if (MIDI_file::HeaderTest(data.getMemory(),size)) { if (firstread != size) { if (data.setSize(size)==0) return 0; if (reader->read(data.getMemory()+firstread,size-firstread)!=size-firstread) return 0; } } else { void * unpack = unpack_helper::unpack_getHandle(reader); if (!unpack) return 0; size = api->fileGetFileSize(unpack); firstread = size > 256 ? 256 : size; data.setSize(firstread); if (api->fileRead(data.getMemory(),firstread,unpack)!=firstread) {api->fileClose(unpack);return 0;} if (!MIDI_file::HeaderTest(data.getMemory(),size)) {api->fileClose(unpack);return 0;} if (firstread != size) { if (data.setSize(size)==0) {api->fileClose(unpack);return 0;} if (api->fileRead(data.getMemory()+firstread,size-firstread,unpack)!=size-firstread) {api->fileClose(unpack);return 0;} } api->fileClose(unpack); } file = MIDI_file::Create(infos->getFilename(),data.getMemory(),size); return !!file; } catch(...) { file = 0; return 0; } } public: static const char *getServiceName() { return NAME; } cnv_MIDI() { file=0; is_open=0; eof_flag=0; thread_id=0; } ~cnv_MIDI() { core_reset(); } virtual int canConvertFrom(svc_fileReader *reader, const char *name, const char *chunktype) { return reader && !chunktype && name && MIDI_core::IsOurFile(name); } virtual const char *getConverterTo() { if (!core_takeover()) return "FINAL"; return MIDI_core::UsesOutput() ? "PCM" : "FINAL"; } virtual int getInfos(MediaInfo *infos) { if (!check_file(infos)) return 0; infos->setTitle(Std::filename(file->path)); infos->setLength(file->len); infos->setInfo( StringPrintf("%sMIDI %i channels", file->info.e_type ? StringPrintf("%s ",file->info.e_type) : "" ,file->info.channels) ); return 1; } virtual int processData(MediaInfo *infos, ChunkList *chunk_list, bool *killswitch) { if (!check_file(infos)) return 0; if (!core_takeover()) return 0; if (!is_open) { MIDI_core::SetVolume(api->core_getVolume(m_coretoken)); MIDI_core::SetPan(api->core_getPan(m_coretoken)); if (!MIDI_core::OpenFile(file)) return 0; is_open=1; eof_flag=0; } check_messages(); if (!MIDI_core::HavePCM()) {Sleep(1);check_messages();return eof_flag ? 0 : 1;} else { int srate,nch,bps; int size; MIDI_core::GetPCM(&srate,&nch,&bps); size = 576 * nch * (bps/8); if (sample_buffer.getSize()addInfo("srate",srate); ci->addInfo("bps",bps); ci->addInfo("nch",nch); chunk_list->setChunk("PCM",sample_buffer.getMemory(),size,ci); return 1; } } virtual int getLatency(void) { return 0; } // callbacks virtual int corecb_onSeeked(int newpos) { if (core_owner==this) MIDI_core::SetPosition(newpos); return 0; } int getPosition(void) { if (core_owner==this && !MIDI_core::UsesOutput()) return MIDI_core::GetPosition(); return -1; } virtual int corecb_onVolumeChange(int v) { if (core_owner==this) MIDI_core::SetVolume(v); return 0; } virtual int corecb_onPanChange(int v) { if (core_owner==this) MIDI_core::SetPan(v); return 0; } virtual int corecb_onAbortCurrentSong() {return 0;}; virtual int corecb_onPaused() { if (core_owner==this) MIDI_core::Pause(1); return 0; } virtual int corecb_onUnpaused() { if (core_owner==this) MIDI_core::Pause(0); return 0; } static void notify_eof() { core_owner_sync.enter(); if (core_owner) core_owner->eof_flag=1; core_owner_sync.leave(); } static DWORD get_core_thread() { DWORD ret = 0; core_owner_sync.enter(); if (core_owner) ret = core_owner->thread_id; core_owner_sync.leave(); return ret; } }; cnv_MIDI * cnv_MIDI::core_owner=0; critical_section cnv_MIDI::core_owner_sync; static waServiceFactoryT midi_svc; #define ACTIONID_CONFIG "MIDI:CONFIG" class MIDI_actions : public svc_actionI { public: MIDI_actions() { registerAction(ACTIONID_CONFIG, 0); } virtual ~MIDI_actions() { } virtual int onActionId(int id, const char *action, const char *param,int,int,void*,int,RootWnd*) { switch (id) { case 0: if (!_stricmp(action,ACTIONID_CONFIG)) { if (MIDI_core::Config(MIDI_callback::GetMainWindow())) { update_extensions(); } } return 1; } return 0; } static const char *getServiceName() { return "MIDI Player Actions Service"; } }; static waServiceFactoryTSingle actions; WACNAME::WACNAME() { #ifdef FORTIFY FortifySetName("cnv_midi.wac"); FortifyEnterScope(); #endif registerService(&midi_svc); registerService(&actions); } WACNAME::~WACNAME() { #ifdef FORTIFY FortifyLeaveScope(); #endif } void MIDI_callback::NotifyEOF() {cnv_MIDI::notify_eof();} HWND MIDI_callback::GetMainWindow() {return api->main_getRootWnd()->gethWnd();} HINSTANCE MIDI_callback::GetInstance() {return wac.gethInstance();} void MIDI_callback::Error(const char * tx) {} void MIDI_callback::Idle(int ms) { int core_thread = (GetCurrentThreadId() == cnv_MIDI::get_core_thread()); int start = timeGetTime(); do { if (core_thread) check_messages(); Sleep(1); } while((int)timeGetTime() - start < ms); if (core_thread) check_messages(); } extern "C" { BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*) { if (r==DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls((HMODULE)hMod); } return 1; } }