#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;