123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820 |
- #include "main.h"
- #include "resource.h"
- #include <shlwapi.h>
- #include <api/service/waServiceFactory.h>
- #include "../winamp/wa_ipc.h"
- #include "../Agave/language/api_language.h"
- #include "CompressionUtility.h"
- #include "minizip/unzip.h"
- static bool paused;
- static int volume=255;
- static int pan=0;
- static string cur_file;
- static HANDLE thread;
- static HINSTANCE hRFdll;
- static reader_source * pRF;
- // wasabi based services for localisation support
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- #define IPC_GETHTTPGETTER 240
- typedef int (*t_getf)(HWND hwnd, char *url, char *file, char *dlgtitle);
- static WReader * get_reader(const char * fn);//wa2 hack
- static int reader_process_file(WReader * r,const char * fn,void * &out_data, size_t &out_size)
- {
- void * data=0;
- int size=0;
- char ks=0;
- if (r->Open((char*)fn,&ks))
- return 0;
- size = r->GetLength();
-
- if (size==-1 || size<0x20)
- return 0;
-
- data=malloc(size);//scan funcs assume that theres at least 256 data
-
- if (!data)
- return 0;
-
- if (r->Read((char*)data,size,&ks)!=size)
- {
- free(data);
- return 0;
- }
- void* pvOut;
- size_t nSizeOut = 0;
- // GZIP
- if (((*(DWORD*)data) & 0xFFFFFF) == 0x088b1f)
- {
- if (CompressionUtility::DecompressGZip(data, size, &pvOut, nSizeOut) >= 0)
- {
- out_data = pvOut;
- out_size = nSizeOut;
- return 1;
- }
- else
- {
- return 0;
- }
- }
- // PKZIP
- else if (*(DWORD*)data == 0x04034B50)
- {
- if (CompressionUtility::DecompressPKZip(fn, &pvOut, nSizeOut) >= 0)
- {
- out_data = pvOut;
- out_size = nSizeOut;
- return 1;
- }
- else
- {
- return 0;
- }
- }
-
- out_size = size;
- out_data = data;
- return 1;
- }
- MIDI_file * wa2_open_file(const char * url)
- {
- WReader * r=get_reader(url);
- if (!r) return 0;
- void * data=0;
- size_t size=0;
- MIDI_file* mf=0;
- if (reader_process_file(r,url,data,size))
- {
- mf=MIDI_file::Create(url,data,size);
- free(data);
- }
- delete r;
- return mf;
- }
- static void build_fmtstring();
- static cfg_int cfg_mod_output("dev_output",1);
- static void wa2_onCfgUpdate()
- {
- MIDI_device * dev = MIDI_driver::find_device(cfg_driver,cfg_device);
- if (!dev)
- {
- dev = MIDI_driver::find_device_default();
- }
- //hack for wa2input.wac in wa3
- mod.UsesOutputPlug=(dev->has_output() || (cfg_smp && cfg_sampout)) ? 1 : 0x8001;
- cfg_mod_output=mod.UsesOutputPlug;
- build_fmtstring();
- }
- static char fmts_string[1024];
- #define NSEEK(a) {while(!(cfg_ext_mask&(1<<a)) && a<n_exts) a++;}
- static void build_fmtstring()
- {
- UINT n_exts = MIDI_core::FileTypes_GetNum();
- if (!cfg_ext_mask)
- {
- fmts_string[1]=fmts_string[0]=0;
- return;
- }
- UINT n=0;
- NSEEK(n);
- const char* d=MIDI_core::FileTypes_GetDescription(n);
- char* o=fmts_string;
- while(1)
- {
- UINT f=n;
- while(n<n_exts && d==MIDI_core::FileTypes_GetDescription(n))
- {
- const char * e=MIDI_core::FileTypes_GetExtension(n);
- while(e && *e) *(o++)=*(e++);
- n++;
- NSEEK(n);
- *(o++)=';';
- }
- o[-1]=0;
- while(d && *d) *(o++)=*(d++);
- *(o++)=' ';
- *(o++)='(';
- while(f<n)
- {
- const char * e=MIDI_core::FileTypes_GetExtension(f);
- while(e && *e) *(o++)=*(e++);
- f++;
- NSEEK(f);
- *(o++)=',';
- }
- o[-1]=')';
- *(o++)=0;
- if (n>=n_exts) break;
- d=MIDI_core::FileTypes_GetDescription(n);
- }
- if (cfg_extra_exts.get_string().length()>0)
- {
- d=cfg_extra_exts;
- while(d && *d) *(o++)=*(d++);
- *(o++)=0;
- d=WASABI_API_LNGSTRING(STRING_FILES_OTHER);
- while(d && *d) *(o++)=*(d++);
- d=cfg_extra_exts;
- while(d && *d)
- {
- if (*d==';') *o=',';
- else *o=*d;
- o++;
- d++;
- }
- *(o++)=')';
- *(o++)=0;
- }
- *(o++)=0;
- }
- #undef NSEEK
- static void Config(HWND p)
- {
- if (MIDI_core::Config(p))
- {
- MIDI_core::WriteConfig();
- wa2_onCfgUpdate();
- }
- }
- void About(HWND);
- class CMemReader : public WReader
- {
- public:
- BYTE* mem;
- UINT sz;
- UINT pos;
- int Open(char *url, char *killswitch);
- int Read(char *buffer, int length, char* killswitch) {if (!mem) return 0;if (length+pos>sz) length=sz-pos;memcpy(buffer,mem+pos,length);pos+=length;return length;}
- int GetLength(void) {return sz;}
- int CanSeek(void) {return 1;};
- int Seek(int position, char*killswitch) {pos=position;return 0;};
-
- CMemReader() {mem=0;sz=0;pos=0;}
- ~CMemReader() {if (mem) free(mem);}
- };
- static int Download(char* url,UINT* f_size,BYTE** m_buf)
- {
- typedef int (*t_getf)(HWND hwnd, char *url, char *file, char *dlgtitle);
- t_getf getf;
- int t=SendMessage(mod.hMainWindow,WM_USER,0,IPC_GETHTTPGETTER);
- if (!t || t==1)
- {
- #ifndef WINAMPX
- MessageBoxA(mod.hMainWindow,WASABI_API_LNGSTRING(STRING_URL_ERROR),ERROR,MB_ICONERROR);
- #endif
- return 0;
- }
- else
- {
- int rv=0;
- char tmp[MAX_PATH] = {0};
- get_temp_file(tmp);
- HANDLE f;
- DWORD br = 0,s = 0;
- void* b;
- getf=(t_getf)t;
- if (getf(mod.hMainWindow,url,tmp,WASABI_API_LNGSTRING(STRING_RETRIEVING_FILE))) goto fail;
- f=CreateFileA(tmp,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
- if (f==INVALID_HANDLE_VALUE) goto fail;
- br=0;
- s=GetFileSize(f,0);
- if (!s) goto fail;
- b=malloc(s);
- if (!b) goto fail;
- ReadFile(f,b,s,&br,0);
- rv=1;
- *f_size=br;
- *m_buf=(BYTE*)b;
- fail:
- CloseHandle(f);
- DeleteFileA(tmp);
- return rv;
- }
- }
- int CMemReader::Open(char* url,char*)
- {
- sz=pos=0;
- if (mem) {free(mem);mem=0;}
- HANDLE f=CreateFileA(url,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);
- if (f!=INVALID_HANDLE_VALUE)
- {
- sz=GetFileSize(f,0);
- mem=(BYTE*)malloc(sz);
- if (!mem) {CloseHandle(f);return 1;}
- ReadFile(f,mem,sz,(DWORD*)&sz,0);
- CloseHandle(f);
- return 0;
- }
- return !Download(url,&sz,&mem);
- }
- class CFileReader : public WReader
- {
- public:
- HANDLE f;
- CFileReader() {f=0;};
- ~CFileReader() {if (f) CloseHandle(f);}
- int Open(char *url, char*killswitch) {f=CreateFileA(url,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);return f==INVALID_HANDLE_VALUE;}
- int Read(char *buffer, int length, char*killswitch) {DWORD br=0;ReadFile(f,buffer,length,&br,0);return br;}
- int GetLength(void) {return GetFileSize(f,0);}
- int CanSeek(void) {return 1;};
- int Seek(int position, char*killswitch) {SetFilePointer(f,position,0,FILE_BEGIN);return 0;}
-
- };
- static WReader *get_reader(const char* url)
- {
- if (!_strnicmp(url,"file://",7)) url+=7;
- WReader* ret=0;
- if (pRF && pRF->ismine((char*)url)) ret=pRF->create();
- if (ret)
- {
- ret->m_player=0;
- return ret;
- }
- if (_strnicmp(url,"http://",7)==0 || _strnicmp(url,"ftp://",6)==0 || _strnicmp(url,"https://",8)==0) return new CMemReader;
- return new CFileReader();
- }
- int Init()
- {
- if (!IsWindow(mod.hMainWindow))
- return IN_INIT_FAILURE;
- // loader so that we can get the localisation service api for use
- waServiceFactory *sf = mod.service->service_getServiceByGuid(languageApiGUID);
- if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(mod.hDllInstance,InMidiLangGUID);
- static wchar_t szDescription[256];
- swprintf(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_MIDI_PLAYER),VER);
- mod.description = (char*)szDescription;
- MIDI_core::GlobalInit();
- mod.UsesOutputPlug=cfg_mod_output;
- build_fmtstring();
- return IN_INIT_SUCCESS;
- }
- void Quit()
- {
- MIDI_core::GlobalQuit();
- }
- void GetFileInfo(const char *url, char *title, int *len)
- {
- if (!url || !*url)
- {
- url=cur_file;
- }
- if (len) *len=0;
- if (title) *title=0;
- char ks=0;
- bool file_local=0;
- MIDI_file * file=0;
- if (MIDI_core::getFile() && !_stricmp(url,MIDI_core::getFile()->path))
- {
- file = MIDI_core::getFile()->AddRef();
- }
- if (!file)
- {
- file = wa2_open_file(url);
- if (!file) {
- return;
- }
- file_local=1;
- }
- if (len)
- *len=file->GetLength();
- if (title)
- file->GetTitle(title,256);
- file->Free();
- }
- BOOL CALLBACK InfoProc(HWND,UINT,WPARAM,LPARAM);
- int show_rmi_info(HWND w,MIDI_file* mf);
- int infoDlg(const char *fn, HWND hwnd)
- {
- int rv=1;
- MIDI_file *mf=wa2_open_file(fn);
- if (!mf) return INFOBOX_UNCHANGED;
-
- if (cfg_rmi_def) rv=show_rmi_info(hwnd,mf);
- else
- {
- rv = WASABI_API_DIALOGBOXPARAM(IDD_INFO,hwnd,InfoProc,(LPARAM)mf);
- }
- if (!rv && !_stricmp(mf->path,cur_file))
- {
- PostMessage(mod.hMainWindow,WM_USER,0,243);
- }
- mf->Free();
- return rv;
- }
- int InfoBox(const char *file, HWND parent)
- {
- if (!file) file=cur_file;
- return infoDlg(file,parent);
- }
- static char kill;
- static int pos_ms;
- static int seek_to;
- static bool out_open;
- DWORD WINAPI PlayThread(void*)
- {
- #ifdef USE_LOG
- log_write("PlayThread");
- #endif
- short * visbuf;
- char *sample_buf;
- int sr,bps,nch;
- pos_ms=0;
- int pos_base=0;
- int samp_wr=0;
- int max_l=0;
- MIDI_core::GetPCM(&sr,&nch,&bps);
- int s_size=576 * (bps/8) * nch;
- if (bps>16)
- {
- visbuf=(short*)malloc(576*2*nch);
- }
- else visbuf=0;
- sample_buf = (char*)malloc(576 * 2 * (bps/8) * nch);
- bool done=0;
- while(!(kill&1))
- {
- #ifdef USE_LOG
- log_write("main loop");
- #endif
- if (paused) {
- #ifdef USE_LOG
- log_write("paused");
- #endif
- Sleep(10);
- continue;
- }
- if (seek_to!=-1)
- {
- #ifdef USE_LOG
- log_write("seeking");
- #endif
- if (MIDI_core::SetPosition(seek_to))
- {
- pos_ms=seek_to;
- if (out_open)
- {
- mod.outMod->Flush(pos_ms);
- }
- pos_base=pos_ms;
- samp_wr=0;
- done=0;
- }
- kill&=~2;
- seek_to=-1;
- }
- if (done)
- {
- #ifdef USE_LOG
- log_write("done");
- #endif
- if (!mod.outMod->IsPlaying())
- {
- PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
- break;
- }
- Sleep(10);continue;
- }
- #ifdef USE_LOG
- log_write("calling GetSamples");
- #endif
- int l=MIDI_core::GetSamples(sample_buf,s_size,&kill);
- if (kill&1) {
- #ifdef USE_LOG
- log_write("kill&1");
- #endif
- break;
- }
- if (kill&2) {
- #ifdef USE_LOG
- log_write("kill&2");
- #endif
- continue;
- }
- if (l<=0 && !paused)
- {
- #ifdef USE_LOG
- log_write("done(?)");
- #endif
- done=1;
- if (out_open)
- {
- mod.outMod->Write(sample_buf,0);
- continue;
- }
- else
- {
- PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
- break;
- }
- }
- if (mod.dsp_isactive())
- {
- #ifdef USE_LOG
- log_write("DSP");
- #endif
- l=(8*l)/(bps*nch);
- l=mod.dsp_dosamples((short*)sample_buf,l,bps,nch,sr);
- l*=(nch*bps)/8;
- }
- if (out_open)
- {
- #ifdef USE_LOG
- log_write("sending to output");
- #endif
- if (kill&1) break;
- while(mod.outMod->CanWrite()<l && !kill) Sleep(2);
- if (kill&1) break;
- if (!kill) mod.outMod->Write((char*)sample_buf,l);
- }
- {
- char * vis=sample_buf;
- UINT vis_bps=bps;
- if (bps>16)
- {
- int n;
- UINT d=bps>>3;
- char * foo=sample_buf+d-2;
- for(n=0;n<576*nch;n++)
- {
- visbuf[n]=*(short*)foo;
- foo+=d;
- }
- vis=(char*)visbuf;
- vis_bps=16;
- }
- #ifdef USE_LOG
- log_write("doing vis");
- #endif
- mod.SAAddPCMData(vis,nch,vis_bps,pos_ms);
- mod.VSAAddPCMData(vis,nch,vis_bps,pos_ms);
- }
- samp_wr+=(8*l)/(bps*nch);
- pos_ms=pos_base+MulDiv(1000,samp_wr,sr);
- }
- free(sample_buf);
- if (visbuf) free(visbuf);
- return 0;
- }
- int initDefaultDeviceShit()
- {
- //CT> find default device if no device set
- MIDI_device * dev = MIDI_driver::find_device(cfg_driver,cfg_device);
- if(dev) return 1;
- //reinit to default
- MIDI_driver *driver=MIDI_driver::driver_enumerate(0);
- if(!driver) return 0;
- MIDI_device *device=driver->device_enumerate(0);
- if(!device) return 0;
- cfg_driver=driver->get_guid();
- cfg_device=device->get_guid();
- return 1;
- }
- int Play(const char *fn)
- {
- if(!initDefaultDeviceShit()) return 0;
- paused=0;
- seek_to=-1;
- kill=0;
- if (!MIDI_core::Init()) return 0;
- if (!MIDI_core::UsesOutput())
- {
- MIDI_core::SetVolume(volume);
- MIDI_core::SetPan(pan);
- }
- else
- {
- MIDI_core::SetVolume(255);
- MIDI_core::SetPan(0);
- }
- MIDI_file * file = wa2_open_file(fn);
- if (!file) return -1;
- int rv=MIDI_core::OpenFile(file);
-
- file->Free();
- if (rv==0)
- {
- MIDI_core::Close();
- return 1;
- }
- cur_file=fn;
- int sr,nch,bps;
- MIDI_core::GetPCM(&sr,&nch,&bps);
- {
- MIDI_file * mf=MIDI_core::getFile();
- UINT nc=0;
- if (mf) nc=mf->info.channels;
- mod.SetInfo(nc*10000,sr/1000,2,1);
- }
- if (MIDI_core::HavePCM())
- {
- int max_l=0;
- MIDI_core::GetPCM(&sr,&nch,&bps);
- if (MIDI_core::UsesOutput())
- {
- #ifdef USE_LOG
- log_write("output init");
- #endif
- max_l=mod.outMod->Open(sr,nch,bps,-1,-1);
- if (max_l<0)
- {
- MIDI_core::Close();
- return 1;
- }
- out_open=1;
- mod.outMod->SetVolume(volume);
- mod.outMod->SetPan(pan);
- }
- mod.SAVSAInit(max_l,sr);
- mod.VSASetInfo(sr,nch);
- #ifdef USE_LOG
- log_write("Creating thread");
- #endif
- DWORD id;
- thread=CreateThread(0,0,PlayThread,0,CREATE_SUSPENDED,&id);
- #ifndef _DEBUG
- SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
- #endif
- ResumeThread(thread);
- }
- else
- {
- #ifdef USE_LOG
- log_write("threadless mode");
- #endif
- thread=0;
- }
-
- return 0;
- }
- void Pause()
- {
- if (MIDI_core::HavePlayer() && !paused)
- {
- MIDI_core::Pause(paused=1);
- if (MIDI_core::UsesOutput()) mod.outMod->Pause(1);
- }
- }
- void UnPause()
- {
- if (MIDI_core::HavePlayer() && paused)
- {
- MIDI_core::Pause(paused=0);
- if (MIDI_core::UsesOutput())
- {
- mod.outMod->Flush(0);
- mod.outMod->Pause(0);
- }
- }
- }
- int IsPaused()
- {
- return paused;
- }
- void Stop()
- {
- if (thread)
- {
- kill|=1;
- WaitForSingleObject(thread,INFINITE);
- CloseHandle(thread);
- thread=0;
- mod.SAVSADeInit();
- if (out_open)
- {
- out_open=0;
- mod.outMod->Close();
- }
- }
- MIDI_core::Close();
- }
- void EQSet(int on, char data[10], int preamp)
- {
- }
- int GetLength()
- {
- return MIDI_core::GetLength();
- }
- int GetOutputTime()
- {
- if (seek_to!=-1) return seek_to;
- if (thread && MIDI_core::UsesOutput()) return pos_ms+mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime();
- else return MIDI_core::GetPosition();
- }
- void SetOutputTime(int t)
- {
- if (thread)
- {
- seek_to=t;
- kill|=2;
- }
- else MIDI_core::SetPosition(t);
- }
- void SetVolume(int v)
- {
- volume=v;
- if (MIDI_core::UsesOutput()) mod.outMod->SetVolume(v);
- else MIDI_core::SetVolume(v);
- }
- void SetPan(int p)
- {
- pan=p;
- if (MIDI_core::UsesOutput()) mod.outMod->SetPan(p);
- else MIDI_core::SetPan(p);
- }
- In_Module mod=
- {
- IN_VER_RET,
- "nullsoft(in_midi.dll)",
- 0,0,
-
- fmts_string,
-
- 1,
- 1,
- Config,
- About,
- Init,
- Quit,
- GetFileInfo,
- InfoBox,
-
- MIDI_core::IsOurFile,
- Play,
- Pause,
- UnPause,
- IsPaused,
- Stop,
- GetLength,
- GetOutputTime,
- SetOutputTime,
- SetVolume,
- SetPan,
-
- 0,0,0,0,0,0,0,0,0,0,0,
- EQSet,
- 0,
- 0,
- };
- extern "C"
- {
- __declspec( dllexport ) In_Module * winampGetInModule2()
- {
- return &mod;
- }
- }
- void MIDI_callback::NotifyEOF() {PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);}
- HWND MIDI_callback::GetMainWindow() {return mod.hMainWindow;}
- HINSTANCE MIDI_callback::GetInstance() {return mod.hDllInstance;}
- void MIDI_callback::Error(const char * tx)
- {
- #ifndef WINAMPX
- MessageBoxA(mod.hMainWindow,tx,0,MB_ICONERROR);
- #endif
- }
- BOOL APIENTRY DllMain(HANDLE hMod,DWORD r,void*)
- {
- if (r==DLL_PROCESS_ATTACH)
- {
- DisableThreadLibraryCalls((HMODULE)hMod);
- }
- return 1;
-
- }
- void MIDI_callback::Idle(int ms)
- {
- int start = timeGetTime();
- do Sleep(1); while( (int)timeGetTime() - start < ms);
- }
|