aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_midi/main.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/main.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_midi/main.cpp')
-rw-r--r--Src/Plugins/Input/in_midi/main.cpp612
1 files changed, 612 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_midi/main.cpp b/Src/Plugins/Input/in_midi/main.cpp
new file mode 100644
index 00000000..b9012b56
--- /dev/null
+++ b/Src/Plugins/Input/in_midi/main.cpp
@@ -0,0 +1,612 @@
+#include "../Agave/Language/api_language.h"
+#include "main.h"
+#include <math.h>
+#include "resource.h"
+#include "../Winamp/in2.h"
+#include "../Winamp/wa_ipc.h"
+
+extern In_Module mod;
+void get_temp_file(char* fn)
+{
+ static char tmp_path[MAX_PATH];
+ if (!tmp_path[0]) GetTempPathA(MAX_PATH,tmp_path);
+ static DWORD num;
+ if (num==0) num=GetTickCount();
+ wsprintfA(fn,"%sasdf%x.tmp",tmp_path,num++);
+}
+
+void file2title(const char* f,string& t)
+{
+ const char* p1=strrchr(f,'\\'),*p2=strrchr(f,':'),*p3=strrchr(f,'/');
+ if (p2>p1) p1=p2;
+ if (p3>p1) p1=p3;
+ if (p1) p1++;
+ else p1=(char*)f;
+ t=p1;
+ p1=strrchr(t,'.');
+ if (p1) t.truncate(p1-(const char*)t);
+}
+
+static char* exts[]={"MID","MIDI","RMI","KAR","HMP","HMI","XMI","MSS","MUS","CMF","GMD","MIDS","MIZ","HMZ"};
+#define N_EXTS tabsize(exts)
+static char is_def[N_EXTS]={1,1,1,1,0,0,0,0,0,0,0,0,1,0};
+
+static int get_def_exts()
+{
+ int ret=0;
+ int n;
+ for(n=0;n<N_EXTS;n++)
+ {
+ if (is_def[n]) ret|=1<<n;
+ }
+ return ret;
+}
+
+cfg_int cfg_ext_mask("ext_mask",get_def_exts());
+
+static char d_smf[128];
+static char d_clo[128];
+static char d_cmp[128];
+
+int ext_descs[N_EXTS]={STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_SMF,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_CLONE,STRING_FILES_COMPRESSED,STRING_FILES_COMPRESSED};
+
+int MIDI_core::FileTypes_GetNum() {return N_EXTS;}
+const char * MIDI_core::FileTypes_GetExtension(int n) {return exts[n];}
+char * MIDI_core::FileTypes_GetDescription(int n) {
+ char* s = d_smf;
+ if(ext_descs[n] == STRING_FILES_SMF) {
+ if(!d_smf[0]) {
+ WASABI_API_LNGSTRING_BUF(ext_descs[n],d_smf,128);
+ }
+ s = d_smf;
+ }
+ else if(ext_descs[n] == STRING_FILES_CLONE) {
+ if(!d_clo[0]) {
+ WASABI_API_LNGSTRING_BUF(ext_descs[n],d_clo,128);
+ }
+ s = d_clo;
+ }
+ else if(ext_descs[n] == STRING_FILES_COMPRESSED) {
+ if(!d_cmp[0]) {
+ WASABI_API_LNGSTRING_BUF(ext_descs[n],d_cmp,128);
+ }
+ s = d_cmp;
+ }
+ return s;
+}
+
+static int isourext(const char* ext)
+{
+ UINT n;
+ for(n=0;n<N_EXTS;n++)
+ {
+ if ((cfg_ext_mask&(1<<n)) && !_stricmp(ext,exts[n])) return 1;
+ }
+ return 0;
+}
+
+int MIDI_core::IsOurFile(const char *fn)
+{
+ const char* p=strrchr(fn,'.');
+ if (p)
+ {
+ if (isourext(p+1)) return 1;
+ }
+
+ return 0;
+}
+
+extern UINT volmode_detect();
+
+static BOOL CALLBACK KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
+
+int MIDI_core::Init()
+{
+ theFile=0;
+ data_src=0;
+ plr=0;
+ eof=0;
+ mix_dev=0;mix_idx=0;
+ kwnd=0;
+ kmap=0;
+ kmap_size=0;kmap_ptr=0;
+ kmap_data=0;
+ format_srate=0;format_nch=0;format_bps=0;
+
+ device=MIDI_driver::find_device(cfg_driver,cfg_device);
+ if (!device) return 0;
+ use_out=device->has_output() || (cfg_smp && cfg_sampout);
+ use_smp=cfg_smp && !device->has_output();
+
+ if (cfg_volmode>2) volmod=cfg_volmode-1;
+ else if (cfg_volmode==2) volmod = device->volctrl_happy() ? 1 : volmode_detect()+2;
+ else volmod=cfg_volmode;
+
+ if (volmod>1)
+ {
+ UINT idx=volmod-2;
+ UINT id=0;
+ UINT n_devz=mixerGetNumDevs();
+ UINT dev=0;
+ BOOL found=0;
+ MIXERLINE ml;
+ while(dev<n_devz)
+ {
+ mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
+
+ ZeroMemory(&ml,sizeof(ml));
+ ml.cbStruct=sizeof(ml);
+ ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+
+ mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
+
+ if (idx<ml.cConnections)
+ {
+ found=1;
+ break;
+ }
+ idx-=ml.cConnections;
+ dev++;
+ }
+ if (found)
+ {
+ mix_dev=id;
+ mix_idx=idx;
+ }
+ else
+ {
+ volmod=0;
+ }
+ }
+ return 1;
+}
+
+CStream * sampling_create(int srate,int nch,int bps);
+
+cfg_int cfg_lyrics("lyrics",1);
+
+int MIDI_core::OpenFile(MIDI_file * file)
+{
+
+#ifdef USE_LOG
+ log_write("MIDI_core::Open()");
+#endif
+
+ if (!file) return 0;
+
+ format_srate=device->has_freq() ? cfg_freq : 44100;
+ format_bps=16;
+ format_nch=2;
+
+
+
+ theFile=file->AddRef();
+#ifdef USE_LOG
+ log_write("file loaded");
+#endif
+ plr=0;
+
+
+ if (use_smp)
+ {
+#ifdef USE_LOG
+ log_write("starting sampling");
+#endif
+ format_srate=cfg_wavein_sr;
+ format_bps=cfg_wavein_bps;
+ format_nch=cfg_wavein_ch;
+ data_src=sampling_create(format_srate,format_nch,format_bps);
+ }
+
+ plr=device->create();
+
+ if (plr)
+ {
+#ifdef USE_LOG
+ if (data_src) log_write("got PCM data source");
+
+ log_write("playback started");
+#endif
+
+ if (cfg_lyrics)
+ {
+ kmap=kmap_create(theFile,1,&kmap_size,&kmap_data);
+ if (kmap)
+ {
+ kwnd=WASABI_API_CREATEDIALOGPARAMW(IDD_LYRICS,MIDI_callback::GetMainWindow(),KarProc,0);
+ free(kmap_data); kmap_data=0;//not needed anymore, used only on initdialog to setdlgitemtext
+ }
+ }
+
+ return 1;
+ }
+ else
+ {
+ if (data_src) {delete data_src;data_src=0;}
+
+ theFile->Free();
+ theFile=0;
+
+ return 0;
+ }
+}
+
+int MIDI_core::GetSamples(void *sample_buffer, int bytes, char *killswitch)
+{
+#ifdef USE_LOG
+ log_write("GetSamples");
+#endif
+ if (data_src)
+ {
+ return data_src->ReadData(sample_buffer,bytes,(bool*)killswitch);
+ }
+ else return 0;
+}
+
+void MIDI_core::update_vol()
+{
+ MIXERLINE ml;
+ ZeroMemory(&ml,sizeof(ml));
+ ml.cbStruct=sizeof(ml);
+ ml.dwSource=mix_idx;
+ mixerGetLineInfo((HMIXEROBJ)mix_dev,&ml,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
+
+ MIXERLINECONTROLS cs;
+ MIXERCONTROL c;
+ ZeroMemory(&cs,sizeof(cs));
+ cs.cbStruct=sizeof(cs);
+ cs.cControls=1;
+ cs.dwLineID=ml.dwLineID;
+ cs.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;
+ cs.cbmxctrl=sizeof(c);
+ cs.pamxctrl=&c;
+ ZeroMemory(&c,sizeof(c));
+ c.cbStruct=sizeof(c);
+
+ if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
+ {
+ DWORD val;
+ if (cfg_logvol)
+ {
+ double _vol=volume>0 ? 20*log10((double)volume/255.0) : -60.0;//in negative db
+ _vol=_vol/60.0+1;
+ if (_vol<0) _vol=0;
+ val=c.Bounds.dwMinimum + (int)( _vol * (double)(c.Bounds.dwMaximum-c.Bounds.dwMinimum) );
+ }
+ else val=c.Bounds.dwMinimum + volume * (c.Bounds.dwMaximum-c.Bounds.dwMinimum) / 255;
+ if (ml.cChannels==1)
+ {
+ MIXERCONTROLDETAILS_UNSIGNED ds={val};
+ MIXERCONTROLDETAILS d;
+ d.cbStruct=sizeof(d);
+ d.dwControlID=c.dwControlID;
+ d.cChannels=1;
+ d.cMultipleItems=0;
+ d.cbDetails=sizeof(ds);
+ d.paDetails=&ds;
+ mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
+ }
+ else if (ml.cChannels<16)
+ {
+ MIXERCONTROLDETAILS_UNSIGNED ds[16];
+ UINT n;
+ for(n=0;n<16;n++) ds[n].dwValue=val;
+ if (pan<0)
+ {
+ ds[1].dwValue=ds[1].dwValue*(128+pan)>>7;
+ }
+ else
+ {
+ ds[0].dwValue=ds[0].dwValue*(128-pan)>>7;
+ }
+ MIXERCONTROLDETAILS d;
+ d.cbStruct=sizeof(d);
+ d.dwControlID=c.dwControlID;
+ d.cChannels=ml.cChannels;
+ d.cMultipleItems=0;
+ d.cbDetails=sizeof(ds[0]);
+ d.paDetails=&ds;
+ mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
+ }
+ }
+/*
+ ZeroMemory(&cs,sizeof(cs));
+ cs.cbStruct=sizeof(cs);
+ cs.cControls=1;
+ cs.dwLineID=ml.dwLineID;
+ cs.dwControlType=MIXERCONTROL_CONTROLTYPE_PAN;
+ cs.cbmxctrl=sizeof(c);
+ cs.pamxctrl=&c;
+ ZeroMemory(&c,sizeof(c));
+ c.cbStruct=sizeof(c);
+
+ if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
+ {
+ MIXERCONTROLDETAILS_SIGNED ds={c.Bounds.lMinimum + (pan+128) * (c.Bounds.lMaximum-c.Bounds.lMinimum) / 255};
+ MIXERCONTROLDETAILS d;
+ d.cbStruct=sizeof(d);
+ d.dwControlID=c.dwControlID;
+ d.cbDetails=sizeof(ds);
+ d.cChannels=ml.cChannels;
+ d.cMultipleItems=c.cMultipleItems;
+ d.paDetails=&ds;
+ mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
+ }*/
+}
+
+int MIDI_core::SetVolume(int _volume)
+{
+ volume=_volume;
+ if (volmod==0) return 0;
+ else
+ {
+ if (volmod==1)
+ {
+ if ((use_out && !use_smp) || !plr)
+ {
+ return 0;
+ }
+ else
+ {
+ return plr->setvol(player_getVol());
+ }
+ }
+ update_vol();
+ return 1;
+ }
+}
+
+int MIDI_core::SetPan(int _pan)
+{
+ pan=_pan;
+ if (volmod==0) return 0;
+ else
+ {
+ if (volmod==1)
+ {
+ if (plr) return plr->setpan(player_getPan());
+ else return 0;
+ }
+ else
+ {
+ update_vol();
+ return 1;
+ }
+ }
+}
+
+int MIDI_core::SetPosition(int pos)
+{
+ if (!plr) return 0;
+ if (!plr->settime(pos)) return 0;
+ sync.enter();
+ kmap_ptr=0;
+ LeaveCriticalSection(&sync);
+
+ if (data_src) data_src->Flush();
+ return 1;
+}
+
+void MIDI_core::Pause(int pause)
+{
+ if (plr)
+ {
+ if (pause) plr->pause();
+ else plr->unpause();
+ }
+ if (data_src) data_src->Pause(pause);
+}
+
+int MIDI_core::GetPosition(void)
+{
+ int i=0;
+ if (plr)
+ {
+ i=plr->gettime();
+ if (i<0) i=0;
+ }
+ return i;
+}
+
+int MIDI_core::GetLength(void)
+{
+ if (theFile) return theFile->len;
+ else return -1;
+}
+
+void MIDI_core::Close()
+{
+#ifdef USE_LOG
+ log_write("shutting down MIDI_core");
+#endif
+ if (plr) {delete plr;plr=0;}
+ if (data_src) {delete data_src;data_src=0;}
+ if (kwnd) {DestroyWindow(kwnd);kwnd=0;}
+ if (kmap) {free(kmap);kmap=0;}
+ if (theFile) {theFile->Free();theFile=0;}
+}
+
+void MIDI_core::Eof()
+{
+ eof=1;
+ if (data_src)
+ data_src->Eof();
+ else
+ MIDI_callback::NotifyEOF();
+}
+
+
+static char INI_FILE[MAX_PATH];
+
+void MIDI_core::GlobalInit()
+{
+#ifdef USE_LOG
+ log_start();
+ log_write("initializing");
+ log_write(NAME);
+#endif
+
+ char *p;
+ if (mod.hMainWindow &&
+ (p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
+ && p!= (char *)1)
+ {
+ strcpy(INI_FILE, p);
+ }
+ else
+ {
+ GetModuleFileNameA(NULL,INI_FILE,sizeof(INI_FILE));
+ p = INI_FILE + strlen(INI_FILE);
+ while (p >= INI_FILE && *p != '.') p--;
+ strcpy(++p,"ini");
+ }
+ cfg_var::config_read(INI_FILE,"in_midi");
+}
+
+void MIDI_core::GlobalQuit()
+{
+ MIDI_driver::shutdown();
+ log_quit();
+}
+
+void MIDI_core::WriteConfig()
+{
+ cfg_var::config_write(INI_FILE,"in_midi");
+}
+
+void MIDI_core::MM_error(DWORD code)
+{
+ string temp;
+ if (!mciGetErrorStringA(code,string_buffer_a(temp,256),256))
+ {
+ temp=WASABI_API_LNGSTRING(STRING_UNKNOWN_MMSYSTEM);
+ }
+ MIDI_callback::Error(temp);
+
+}
+
+
+static void fix_size(HWND wnd)
+{
+ RECT r;
+ GetClientRect(wnd,&r);
+ SetWindowPos(GetDlgItem(wnd,IDC_BLAH),0,0,0,r.right,r.bottom,SWP_NOZORDER|SWP_NOACTIVATE);
+}
+
+static cfg_struct_t<RECT> cfg_lyrics_pos("lyrics_pos",-1);
+
+static void SetWindowRect(HWND w,RECT* r)
+{
+ SetWindowPos(w,0,r->left,r->top,r->right-r->left,r->bottom-r->top,SWP_NOZORDER);
+}
+
+
+static cfg_int cfg_lyrics_min("lyrics_min",0),cfg_lyrics_max("lyrics_max",0);
+
+BOOL CALLBACK MIDI_core::KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
+{
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ SetDlgItemTextA(wnd,IDC_BLAH,MIDI_core::kmap_data);
+
+ if (cfg_lyrics_pos.get_val().left!=-1)
+ {
+ int sx=GetSystemMetrics(SM_CXSCREEN),sy=GetSystemMetrics(SM_CYSCREEN);
+ if (cfg_lyrics_pos.get_val().right>sx)
+ {
+ cfg_lyrics_pos.get_val().left-=cfg_lyrics_pos.get_val().right-sx;
+ cfg_lyrics_pos.get_val().right=sx;
+ }
+ if (cfg_lyrics_pos.get_val().bottom>sy)
+ {
+ cfg_lyrics_pos.get_val().top-=cfg_lyrics_pos.get_val().bottom-sy;
+ cfg_lyrics_pos.get_val().bottom=sy;
+ }
+ if (cfg_lyrics_pos.get_val().left<0)
+ {
+ cfg_lyrics_pos.get_val().right-=cfg_lyrics_pos.get_val().left;
+ cfg_lyrics_pos.get_val().left=0;
+ }
+ if (cfg_lyrics_pos.get_val().top<0)
+ {
+ cfg_lyrics_pos.get_val().bottom-=cfg_lyrics_pos.get_val().top;
+ cfg_lyrics_pos.get_val().top=0;
+ }
+ SetWindowRect(wnd,&cfg_lyrics_pos.get_val());
+ }
+ if (cfg_lyrics_min)
+ {
+ ShowWindow(wnd,SW_MINIMIZE);
+ }
+ else if (cfg_lyrics_max)
+ {
+ ShowWindow(wnd,SW_MAXIMIZE);
+ }
+ fix_size(wnd);
+ SetTimer(wnd,1,100,0);
+ return 1;
+ case WM_TIMER:
+ {
+ sync.enter();
+ UINT time=GetPosition();
+ KAR_ENTRY * set=0;
+ UINT ptr=kmap_ptr;
+ while(ptr<kmap_size && kmap[ptr].time<time)
+ {
+ if (!kmap[ptr].foo) set=&kmap[ptr];
+ ptr++;
+ }
+ kmap_ptr=ptr;
+ sync.leave();
+ if (set)
+ {
+ SendDlgItemMessage(wnd,IDC_BLAH,EM_SETSEL,set->start,set->end);
+ }
+
+ }
+ break;
+ case WM_DESTROY:
+ KillTimer(wnd,1);
+ kwnd=0;
+ GetWindowRect(wnd,&cfg_lyrics_pos.get_val());
+ cfg_lyrics_max=!!IsZoomed(wnd);
+ cfg_lyrics_min=!!IsIconic(wnd);
+ break;
+ case WM_CLOSE:
+
+ cfg_lyrics=0;
+
+ if (!((int)cfg_bugged & BUGGED_BLAH))
+ {
+ char title[32] = {0};
+ cfg_bugged = (int)cfg_bugged | BUGGED_BLAH;
+ MessageBoxA(wnd,WASABI_API_LNGSTRING(IDS_TO_ENABLE_LYRICS_DISPLAY),
+ WASABI_API_LNGSTRING_BUF(IDS_INFORMATION,title,32),MB_ICONINFORMATION);
+ }
+ DestroyWindow(wnd);
+ break;
+ case WM_SIZE:
+ fix_size(wnd);
+ break;
+ }
+ return 0;
+}
+
+//MIDI_core static crap
+bool MIDI_core::use_out;
+MIDI_file* MIDI_core::theFile;
+CStream* MIDI_core::data_src;
+player_base* MIDI_core::plr;
+int MIDI_core::format_srate,MIDI_core::format_nch,MIDI_core::format_bps;
+int MIDI_core::volume=255,MIDI_core::pan=0;
+bool MIDI_core::eof;
+UINT MIDI_core::volmod;
+UINT MIDI_core::mix_dev,MIDI_core::mix_idx;
+MIDI_device * MIDI_core::device;
+bool MIDI_core::use_smp;
+HWND MIDI_core::kwnd;
+KAR_ENTRY* MIDI_core::kmap;
+UINT MIDI_core::kmap_size,MIDI_core::kmap_ptr;
+char * MIDI_core::kmap_data;
+critical_section MIDI_core::sync; \ No newline at end of file