main.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. #include "../Agave/Language/api_language.h"
  2. #include "main.h"
  3. #include <math.h>
  4. #include "resource.h"
  5. #include "../Winamp/in2.h"
  6. #include "../Winamp/wa_ipc.h"
  7. extern In_Module mod;
  8. void get_temp_file(char* fn)
  9. {
  10. static char tmp_path[MAX_PATH];
  11. if (!tmp_path[0]) GetTempPathA(MAX_PATH,tmp_path);
  12. static DWORD num;
  13. if (num==0) num=GetTickCount();
  14. wsprintfA(fn,"%sasdf%x.tmp",tmp_path,num++);
  15. }
  16. void file2title(const char* f,string& t)
  17. {
  18. const char* p1=strrchr(f,'\\'),*p2=strrchr(f,':'),*p3=strrchr(f,'/');
  19. if (p2>p1) p1=p2;
  20. if (p3>p1) p1=p3;
  21. if (p1) p1++;
  22. else p1=(char*)f;
  23. t=p1;
  24. p1=strrchr(t,'.');
  25. if (p1) t.truncate(p1-(const char*)t);
  26. }
  27. static char* exts[]={"MID","MIDI","RMI","KAR","HMP","HMI","XMI","MSS","MUS","CMF","GMD","MIDS","MIZ","HMZ"};
  28. #define N_EXTS tabsize(exts)
  29. static char is_def[N_EXTS]={1,1,1,1,0,0,0,0,0,0,0,0,1,0};
  30. static int get_def_exts()
  31. {
  32. int ret=0;
  33. int n;
  34. for(n=0;n<N_EXTS;n++)
  35. {
  36. if (is_def[n]) ret|=1<<n;
  37. }
  38. return ret;
  39. }
  40. cfg_int cfg_ext_mask("ext_mask",get_def_exts());
  41. static char d_smf[128];
  42. static char d_clo[128];
  43. static char d_cmp[128];
  44. 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};
  45. int MIDI_core::FileTypes_GetNum() {return N_EXTS;}
  46. const char * MIDI_core::FileTypes_GetExtension(int n) {return exts[n];}
  47. char * MIDI_core::FileTypes_GetDescription(int n) {
  48. char* s = d_smf;
  49. if(ext_descs[n] == STRING_FILES_SMF) {
  50. if(!d_smf[0]) {
  51. WASABI_API_LNGSTRING_BUF(ext_descs[n],d_smf,128);
  52. }
  53. s = d_smf;
  54. }
  55. else if(ext_descs[n] == STRING_FILES_CLONE) {
  56. if(!d_clo[0]) {
  57. WASABI_API_LNGSTRING_BUF(ext_descs[n],d_clo,128);
  58. }
  59. s = d_clo;
  60. }
  61. else if(ext_descs[n] == STRING_FILES_COMPRESSED) {
  62. if(!d_cmp[0]) {
  63. WASABI_API_LNGSTRING_BUF(ext_descs[n],d_cmp,128);
  64. }
  65. s = d_cmp;
  66. }
  67. return s;
  68. }
  69. static int isourext(const char* ext)
  70. {
  71. UINT n;
  72. for(n=0;n<N_EXTS;n++)
  73. {
  74. if ((cfg_ext_mask&(1<<n)) && !_stricmp(ext,exts[n])) return 1;
  75. }
  76. return 0;
  77. }
  78. int MIDI_core::IsOurFile(const char *fn)
  79. {
  80. const char* p=strrchr(fn,'.');
  81. if (p)
  82. {
  83. if (isourext(p+1)) return 1;
  84. }
  85. return 0;
  86. }
  87. extern UINT volmode_detect();
  88. static BOOL CALLBACK KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp);
  89. int MIDI_core::Init()
  90. {
  91. theFile=0;
  92. data_src=0;
  93. plr=0;
  94. eof=0;
  95. mix_dev=0;mix_idx=0;
  96. kwnd=0;
  97. kmap=0;
  98. kmap_size=0;kmap_ptr=0;
  99. kmap_data=0;
  100. format_srate=0;format_nch=0;format_bps=0;
  101. device=MIDI_driver::find_device(cfg_driver,cfg_device);
  102. if (!device) return 0;
  103. use_out=device->has_output() || (cfg_smp && cfg_sampout);
  104. use_smp=cfg_smp && !device->has_output();
  105. if (cfg_volmode>2) volmod=cfg_volmode-1;
  106. else if (cfg_volmode==2) volmod = device->volctrl_happy() ? 1 : volmode_detect()+2;
  107. else volmod=cfg_volmode;
  108. if (volmod>1)
  109. {
  110. UINT idx=volmod-2;
  111. UINT id=0;
  112. UINT n_devz=mixerGetNumDevs();
  113. UINT dev=0;
  114. BOOL found=0;
  115. MIXERLINE ml;
  116. while(dev<n_devz)
  117. {
  118. mixerGetID((HMIXEROBJ)dev,&id,MIXER_OBJECTF_MIXER);
  119. ZeroMemory(&ml,sizeof(ml));
  120. ml.cbStruct=sizeof(ml);
  121. ml.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  122. mixerGetLineInfo((HMIXEROBJ)id,&ml,MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER);
  123. if (idx<ml.cConnections)
  124. {
  125. found=1;
  126. break;
  127. }
  128. idx-=ml.cConnections;
  129. dev++;
  130. }
  131. if (found)
  132. {
  133. mix_dev=id;
  134. mix_idx=idx;
  135. }
  136. else
  137. {
  138. volmod=0;
  139. }
  140. }
  141. return 1;
  142. }
  143. CStream * sampling_create(int srate,int nch,int bps);
  144. cfg_int cfg_lyrics("lyrics",1);
  145. int MIDI_core::OpenFile(MIDI_file * file)
  146. {
  147. #ifdef USE_LOG
  148. log_write("MIDI_core::Open()");
  149. #endif
  150. if (!file) return 0;
  151. format_srate=device->has_freq() ? cfg_freq : 44100;
  152. format_bps=16;
  153. format_nch=2;
  154. theFile=file->AddRef();
  155. #ifdef USE_LOG
  156. log_write("file loaded");
  157. #endif
  158. plr=0;
  159. if (use_smp)
  160. {
  161. #ifdef USE_LOG
  162. log_write("starting sampling");
  163. #endif
  164. format_srate=cfg_wavein_sr;
  165. format_bps=cfg_wavein_bps;
  166. format_nch=cfg_wavein_ch;
  167. data_src=sampling_create(format_srate,format_nch,format_bps);
  168. }
  169. plr=device->create();
  170. if (plr)
  171. {
  172. #ifdef USE_LOG
  173. if (data_src) log_write("got PCM data source");
  174. log_write("playback started");
  175. #endif
  176. if (cfg_lyrics)
  177. {
  178. kmap=kmap_create(theFile,1,&kmap_size,&kmap_data);
  179. if (kmap)
  180. {
  181. kwnd=WASABI_API_CREATEDIALOGPARAMW(IDD_LYRICS,MIDI_callback::GetMainWindow(),KarProc,0);
  182. free(kmap_data); kmap_data=0;//not needed anymore, used only on initdialog to setdlgitemtext
  183. }
  184. }
  185. return 1;
  186. }
  187. else
  188. {
  189. if (data_src) {delete data_src;data_src=0;}
  190. theFile->Free();
  191. theFile=0;
  192. return 0;
  193. }
  194. }
  195. int MIDI_core::GetSamples(void *sample_buffer, int bytes, char *killswitch)
  196. {
  197. #ifdef USE_LOG
  198. log_write("GetSamples");
  199. #endif
  200. if (data_src)
  201. {
  202. return data_src->ReadData(sample_buffer,bytes,(bool*)killswitch);
  203. }
  204. else return 0;
  205. }
  206. void MIDI_core::update_vol()
  207. {
  208. MIXERLINE ml;
  209. ZeroMemory(&ml,sizeof(ml));
  210. ml.cbStruct=sizeof(ml);
  211. ml.dwSource=mix_idx;
  212. mixerGetLineInfo((HMIXEROBJ)mix_dev,&ml,MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_MIXER);
  213. MIXERLINECONTROLS cs;
  214. MIXERCONTROL c;
  215. ZeroMemory(&cs,sizeof(cs));
  216. cs.cbStruct=sizeof(cs);
  217. cs.cControls=1;
  218. cs.dwLineID=ml.dwLineID;
  219. cs.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;
  220. cs.cbmxctrl=sizeof(c);
  221. cs.pamxctrl=&c;
  222. ZeroMemory(&c,sizeof(c));
  223. c.cbStruct=sizeof(c);
  224. if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
  225. {
  226. DWORD val;
  227. if (cfg_logvol)
  228. {
  229. double _vol=volume>0 ? 20*log10((double)volume/255.0) : -60.0;//in negative db
  230. _vol=_vol/60.0+1;
  231. if (_vol<0) _vol=0;
  232. val=c.Bounds.dwMinimum + (int)( _vol * (double)(c.Bounds.dwMaximum-c.Bounds.dwMinimum) );
  233. }
  234. else val=c.Bounds.dwMinimum + volume * (c.Bounds.dwMaximum-c.Bounds.dwMinimum) / 255;
  235. if (ml.cChannels==1)
  236. {
  237. MIXERCONTROLDETAILS_UNSIGNED ds={val};
  238. MIXERCONTROLDETAILS d;
  239. d.cbStruct=sizeof(d);
  240. d.dwControlID=c.dwControlID;
  241. d.cChannels=1;
  242. d.cMultipleItems=0;
  243. d.cbDetails=sizeof(ds);
  244. d.paDetails=&ds;
  245. mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
  246. }
  247. else if (ml.cChannels<16)
  248. {
  249. MIXERCONTROLDETAILS_UNSIGNED ds[16];
  250. UINT n;
  251. for(n=0;n<16;n++) ds[n].dwValue=val;
  252. if (pan<0)
  253. {
  254. ds[1].dwValue=ds[1].dwValue*(128+pan)>>7;
  255. }
  256. else
  257. {
  258. ds[0].dwValue=ds[0].dwValue*(128-pan)>>7;
  259. }
  260. MIXERCONTROLDETAILS d;
  261. d.cbStruct=sizeof(d);
  262. d.dwControlID=c.dwControlID;
  263. d.cChannels=ml.cChannels;
  264. d.cMultipleItems=0;
  265. d.cbDetails=sizeof(ds[0]);
  266. d.paDetails=&ds;
  267. mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
  268. }
  269. }
  270. /*
  271. ZeroMemory(&cs,sizeof(cs));
  272. cs.cbStruct=sizeof(cs);
  273. cs.cControls=1;
  274. cs.dwLineID=ml.dwLineID;
  275. cs.dwControlType=MIXERCONTROL_CONTROLTYPE_PAN;
  276. cs.cbmxctrl=sizeof(c);
  277. cs.pamxctrl=&c;
  278. ZeroMemory(&c,sizeof(c));
  279. c.cbStruct=sizeof(c);
  280. if (!mixerGetLineControls((HMIXEROBJ)mix_dev,&cs,MIXER_OBJECTF_MIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE))
  281. {
  282. MIXERCONTROLDETAILS_SIGNED ds={c.Bounds.lMinimum + (pan+128) * (c.Bounds.lMaximum-c.Bounds.lMinimum) / 255};
  283. MIXERCONTROLDETAILS d;
  284. d.cbStruct=sizeof(d);
  285. d.dwControlID=c.dwControlID;
  286. d.cbDetails=sizeof(ds);
  287. d.cChannels=ml.cChannels;
  288. d.cMultipleItems=c.cMultipleItems;
  289. d.paDetails=&ds;
  290. mixerSetControlDetails((HMIXEROBJ)mix_dev,&d,MIXER_SETCONTROLDETAILSF_VALUE|MIXER_OBJECTF_MIXER);
  291. }*/
  292. }
  293. int MIDI_core::SetVolume(int _volume)
  294. {
  295. volume=_volume;
  296. if (volmod==0) return 0;
  297. else
  298. {
  299. if (volmod==1)
  300. {
  301. if ((use_out && !use_smp) || !plr)
  302. {
  303. return 0;
  304. }
  305. else
  306. {
  307. return plr->setvol(player_getVol());
  308. }
  309. }
  310. update_vol();
  311. return 1;
  312. }
  313. }
  314. int MIDI_core::SetPan(int _pan)
  315. {
  316. pan=_pan;
  317. if (volmod==0) return 0;
  318. else
  319. {
  320. if (volmod==1)
  321. {
  322. if (plr) return plr->setpan(player_getPan());
  323. else return 0;
  324. }
  325. else
  326. {
  327. update_vol();
  328. return 1;
  329. }
  330. }
  331. }
  332. int MIDI_core::SetPosition(int pos)
  333. {
  334. if (!plr) return 0;
  335. if (!plr->settime(pos)) return 0;
  336. sync.enter();
  337. kmap_ptr=0;
  338. LeaveCriticalSection(&sync);
  339. if (data_src) data_src->Flush();
  340. return 1;
  341. }
  342. void MIDI_core::Pause(int pause)
  343. {
  344. if (plr)
  345. {
  346. if (pause) plr->pause();
  347. else plr->unpause();
  348. }
  349. if (data_src) data_src->Pause(pause);
  350. }
  351. int MIDI_core::GetPosition(void)
  352. {
  353. int i=0;
  354. if (plr)
  355. {
  356. i=plr->gettime();
  357. if (i<0) i=0;
  358. }
  359. return i;
  360. }
  361. int MIDI_core::GetLength(void)
  362. {
  363. if (theFile) return theFile->len;
  364. else return -1;
  365. }
  366. void MIDI_core::Close()
  367. {
  368. #ifdef USE_LOG
  369. log_write("shutting down MIDI_core");
  370. #endif
  371. if (plr) {delete plr;plr=0;}
  372. if (data_src) {delete data_src;data_src=0;}
  373. if (kwnd) {DestroyWindow(kwnd);kwnd=0;}
  374. if (kmap) {free(kmap);kmap=0;}
  375. if (theFile) {theFile->Free();theFile=0;}
  376. }
  377. void MIDI_core::Eof()
  378. {
  379. eof=1;
  380. if (data_src)
  381. data_src->Eof();
  382. else
  383. MIDI_callback::NotifyEOF();
  384. }
  385. static char INI_FILE[MAX_PATH];
  386. void MIDI_core::GlobalInit()
  387. {
  388. #ifdef USE_LOG
  389. log_start();
  390. log_write("initializing");
  391. log_write(NAME);
  392. #endif
  393. char *p;
  394. if (mod.hMainWindow &&
  395. (p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
  396. && p!= (char *)1)
  397. {
  398. strcpy(INI_FILE, p);
  399. }
  400. else
  401. {
  402. GetModuleFileNameA(NULL,INI_FILE,sizeof(INI_FILE));
  403. p = INI_FILE + strlen(INI_FILE);
  404. while (p >= INI_FILE && *p != '.') p--;
  405. strcpy(++p,"ini");
  406. }
  407. cfg_var::config_read(INI_FILE,"in_midi");
  408. }
  409. void MIDI_core::GlobalQuit()
  410. {
  411. MIDI_driver::shutdown();
  412. log_quit();
  413. }
  414. void MIDI_core::WriteConfig()
  415. {
  416. cfg_var::config_write(INI_FILE,"in_midi");
  417. }
  418. void MIDI_core::MM_error(DWORD code)
  419. {
  420. string temp;
  421. if (!mciGetErrorStringA(code,string_buffer_a(temp,256),256))
  422. {
  423. temp=WASABI_API_LNGSTRING(STRING_UNKNOWN_MMSYSTEM);
  424. }
  425. MIDI_callback::Error(temp);
  426. }
  427. static void fix_size(HWND wnd)
  428. {
  429. RECT r;
  430. GetClientRect(wnd,&r);
  431. SetWindowPos(GetDlgItem(wnd,IDC_BLAH),0,0,0,r.right,r.bottom,SWP_NOZORDER|SWP_NOACTIVATE);
  432. }
  433. static cfg_struct_t<RECT> cfg_lyrics_pos("lyrics_pos",-1);
  434. static void SetWindowRect(HWND w,RECT* r)
  435. {
  436. SetWindowPos(w,0,r->left,r->top,r->right-r->left,r->bottom-r->top,SWP_NOZORDER);
  437. }
  438. static cfg_int cfg_lyrics_min("lyrics_min",0),cfg_lyrics_max("lyrics_max",0);
  439. BOOL CALLBACK MIDI_core::KarProc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)
  440. {
  441. switch(msg)
  442. {
  443. case WM_INITDIALOG:
  444. SetDlgItemTextA(wnd,IDC_BLAH,MIDI_core::kmap_data);
  445. if (cfg_lyrics_pos.get_val().left!=-1)
  446. {
  447. int sx=GetSystemMetrics(SM_CXSCREEN),sy=GetSystemMetrics(SM_CYSCREEN);
  448. if (cfg_lyrics_pos.get_val().right>sx)
  449. {
  450. cfg_lyrics_pos.get_val().left-=cfg_lyrics_pos.get_val().right-sx;
  451. cfg_lyrics_pos.get_val().right=sx;
  452. }
  453. if (cfg_lyrics_pos.get_val().bottom>sy)
  454. {
  455. cfg_lyrics_pos.get_val().top-=cfg_lyrics_pos.get_val().bottom-sy;
  456. cfg_lyrics_pos.get_val().bottom=sy;
  457. }
  458. if (cfg_lyrics_pos.get_val().left<0)
  459. {
  460. cfg_lyrics_pos.get_val().right-=cfg_lyrics_pos.get_val().left;
  461. cfg_lyrics_pos.get_val().left=0;
  462. }
  463. if (cfg_lyrics_pos.get_val().top<0)
  464. {
  465. cfg_lyrics_pos.get_val().bottom-=cfg_lyrics_pos.get_val().top;
  466. cfg_lyrics_pos.get_val().top=0;
  467. }
  468. SetWindowRect(wnd,&cfg_lyrics_pos.get_val());
  469. }
  470. if (cfg_lyrics_min)
  471. {
  472. ShowWindow(wnd,SW_MINIMIZE);
  473. }
  474. else if (cfg_lyrics_max)
  475. {
  476. ShowWindow(wnd,SW_MAXIMIZE);
  477. }
  478. fix_size(wnd);
  479. SetTimer(wnd,1,100,0);
  480. return 1;
  481. case WM_TIMER:
  482. {
  483. sync.enter();
  484. UINT time=GetPosition();
  485. KAR_ENTRY * set=0;
  486. UINT ptr=kmap_ptr;
  487. while(ptr<kmap_size && kmap[ptr].time<time)
  488. {
  489. if (!kmap[ptr].foo) set=&kmap[ptr];
  490. ptr++;
  491. }
  492. kmap_ptr=ptr;
  493. sync.leave();
  494. if (set)
  495. {
  496. SendDlgItemMessage(wnd,IDC_BLAH,EM_SETSEL,set->start,set->end);
  497. }
  498. }
  499. break;
  500. case WM_DESTROY:
  501. KillTimer(wnd,1);
  502. kwnd=0;
  503. GetWindowRect(wnd,&cfg_lyrics_pos.get_val());
  504. cfg_lyrics_max=!!IsZoomed(wnd);
  505. cfg_lyrics_min=!!IsIconic(wnd);
  506. break;
  507. case WM_CLOSE:
  508. cfg_lyrics=0;
  509. if (!((int)cfg_bugged & BUGGED_BLAH))
  510. {
  511. char title[32] = {0};
  512. cfg_bugged = (int)cfg_bugged | BUGGED_BLAH;
  513. MessageBoxA(wnd,WASABI_API_LNGSTRING(IDS_TO_ENABLE_LYRICS_DISPLAY),
  514. WASABI_API_LNGSTRING_BUF(IDS_INFORMATION,title,32),MB_ICONINFORMATION);
  515. }
  516. DestroyWindow(wnd);
  517. break;
  518. case WM_SIZE:
  519. fix_size(wnd);
  520. break;
  521. }
  522. return 0;
  523. }
  524. //MIDI_core static crap
  525. bool MIDI_core::use_out;
  526. MIDI_file* MIDI_core::theFile;
  527. CStream* MIDI_core::data_src;
  528. player_base* MIDI_core::plr;
  529. int MIDI_core::format_srate,MIDI_core::format_nch,MIDI_core::format_bps;
  530. int MIDI_core::volume=255,MIDI_core::pan=0;
  531. bool MIDI_core::eof;
  532. UINT MIDI_core::volmod;
  533. UINT MIDI_core::mix_dev,MIDI_core::mix_idx;
  534. MIDI_device * MIDI_core::device;
  535. bool MIDI_core::use_smp;
  536. HWND MIDI_core::kwnd;
  537. KAR_ENTRY* MIDI_core::kmap;
  538. UINT MIDI_core::kmap_size,MIDI_core::kmap_ptr;
  539. char * MIDI_core::kmap_data;
  540. critical_section MIDI_core::sync;