aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_midi/wa3.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_midi/wa3.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_midi/wa3.cpp')
-rw-r--r--Src/Plugins/Input/in_midi/wa3.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_midi/wa3.cpp b/Src/Plugins/Input/in_midi/wa3.cpp
new file mode 100644
index 00000000..661a5001
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/wa3.cpp
@@ -0,0 +1,395 @@
+#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;n<MIDI_core::FileTypes_GetNum();n++)
+ {
+ int bit = 1<<n;
+ if ( (new_mask & bit) && !(old_mask & bit) )
+ api->core_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<char> 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<char> 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()<size) sample_buffer.setSize(size);
+ size = MIDI_core::GetSamples(sample_buffer.getMemory(),size,(char*)killswitch);
+ if (size<=0)
+ return 0;
+
+ ChunkInfosI *ci=new ChunkInfosI();
+ ci->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<svc_mediaConverter, cnv_MIDI> 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<svc_actionI, MIDI_actions> 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;
+
+}
+}