main.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. LICENSE
  3. -------
  4. Copyright 2005 Nullsoft, Inc.
  5. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without modification,
  7. are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright notice,
  9. this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. * Neither the name of Nullsoft nor the names of its contributors may be used to
  14. endorse or promote products derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  16. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  21. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  22. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include <windows.h>
  25. #include <math.h>
  26. #include <process.h>
  27. #include "draw.h"
  28. #include "wnd.h"
  29. #include "r_defs.h"
  30. #include "render.h"
  31. #include "vis.h"
  32. #include "cfgwnd.h"
  33. #include "resource.h"
  34. #include "bpm.h"
  35. #include "api.h"
  36. #include "../winamp/wa_ipc.h"
  37. #include "../Agave/Language/api_language.h"
  38. #include <api/service/waServiceFactory.h>
  39. #include <stdio.h>
  40. #ifdef REAPLAY_PLUGIN
  41. #include "../../jmde/reaper_plugin.h"
  42. const char *(*get_ini_file)();
  43. int (*vuGetVisData)(char *vdata, int size);
  44. #endif
  45. #define PLUGIN_VERSION "v2.93"
  46. #include "avs_eelif.h"
  47. extern void GetClientRect_adj(HWND hwnd, RECT *r);
  48. static unsigned char g_logtab[256];
  49. HINSTANCE g_hInstance;
  50. /* char *verstr=
  51. #ifndef LASER
  52. "Advanced Visualization Studio"
  53. #else
  54. "AVS/Laser"
  55. #endif
  56. " v2.92"
  57. ;
  58. */
  59. static unsigned int WINAPI RenderThread(LPVOID a);
  60. static void config(struct winampVisModule *this_mod);
  61. static int init(struct winampVisModule *this_mod);
  62. static int render(struct winampVisModule *this_mod);
  63. static void quit(struct winampVisModule *this_mod);
  64. HANDLE g_hThread;
  65. volatile int g_ThreadQuit;
  66. static CRITICAL_SECTION g_cs;
  67. static unsigned char g_visdata[2][2][576];
  68. static int g_visdata_pstat;
  69. /* wasabi based services for localisation support */
  70. api_service *WASABI_API_SVC = 0;
  71. api_language *WASABI_API_LNG = 0;
  72. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  73. static char module1[128];
  74. static winampVisModule *getModule(int which);
  75. static winampVisHeader hdr = { VIS_HDRVER, 0, getModule };
  76. // use this to get our own HINSTACE since overriding DllMain(..) causes instant crashes (should see why)
  77. static HINSTANCE GetMyInstance()
  78. {
  79. MEMORY_BASIC_INFORMATION mbi = {0};
  80. if(VirtualQuery(GetMyInstance, &mbi, sizeof(mbi)))
  81. return (HINSTANCE)mbi.AllocationBase;
  82. return NULL;
  83. }
  84. extern "C" {
  85. __declspec( dllexport ) winampVisHeader* winampVisGetHeader(HWND hwndParent)
  86. {
  87. if(!WASABI_API_LNG_HINST)
  88. {
  89. // loader so that we can get the localisation service api for use
  90. WASABI_API_SVC = (api_service*)SendMessage(hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
  91. if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
  92. waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
  93. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  94. // need to have this initialised before we try to do anything with localisation features
  95. WASABI_API_START_LANG(GetMyInstance(),VisAVSLangGUID);
  96. }
  97. #ifndef LASER
  98. static char szDescription[256];
  99. wsprintfA(szDescription,"%s " PLUGIN_VERSION,WASABI_API_LNGSTRING_BUF(IDS_AVS,module1,128));
  100. hdr.description = szDescription;
  101. #else
  102. hdr.description = "AVS/Laser "PLUGIN_VERSION;
  103. #endif
  104. return &hdr;
  105. }
  106. }
  107. static winampVisModule *getModule(int which)
  108. {
  109. static winampVisModule mod =
  110. {
  111. #ifdef LASER
  112. "Advanced Visualization Studio/Laser",
  113. #else
  114. module1,
  115. #endif
  116. NULL, // hwndParent
  117. NULL, // hDllInstance
  118. 0, // sRate
  119. 0, // nCh
  120. 1000/70, // latencyMS
  121. 1000/70,// delayMS
  122. 2, // spectrumNch
  123. 2, // waveformNch
  124. { 0, }, // spectrumData
  125. { 0, }, // waveformData
  126. config,
  127. init,
  128. render,
  129. quit
  130. };
  131. if (which==0) return &mod;
  132. return 0;
  133. }
  134. void about(HWND hwndParent)
  135. {
  136. static int about_here = 0;
  137. char aboutbuf[1024] = {0}, aboutTitle[48] = {0};
  138. if (about_here)
  139. {
  140. SetActiveWindow(FindWindow("#32770",WASABI_API_LNGSTRING_BUF(IDS_ABOUT_AVS,aboutTitle,48)));
  141. return;
  142. }
  143. about_here = 1;
  144. wsprintf(aboutbuf,WASABI_API_LNGSTRING(IDS_ABOUT_STRING),hdr.description);
  145. MessageBox(hwndParent,aboutbuf,WASABI_API_LNGSTRING_BUF(IDS_ABOUT_AVS,aboutTitle,48),0);
  146. about_here = 0;
  147. }
  148. HWND GetDialogBoxParent(HWND winamp)
  149. {
  150. HWND parent = (HWND)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
  151. if (!parent || parent == (HWND)1)
  152. return winamp;
  153. return parent;
  154. /*
  155. BOOL CALLBACK aboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  156. {
  157. switch (uMsg)
  158. {
  159. case WM_INITDIALOG:
  160. SetDlgItemText(hwndDlg,IDC_VERSTR,verstr);
  161. return 1;
  162. case WM_COMMAND:
  163. switch (LOWORD(wParam))
  164. {
  165. case IDOK: case IDCANCEL:
  166. EndDialog(hwndDlg,0);
  167. return 0;
  168. }
  169. return 0;
  170. }
  171. return 0;
  172. */
  173. }
  174. static void config(struct winampVisModule *this_mod)
  175. {
  176. if (!g_hwnd || !IsWindow(g_hwnd))
  177. {
  178. about(GetDialogBoxParent(this_mod->hwndParent));
  179. // DialogBox(this_mod->hDllInstance,MAKEINTRESOURCE(IDD_DIALOG2),this_mod->hwndParent,aboutProc);
  180. }
  181. else
  182. {
  183. SendMessage(g_hwnd,WM_USER+33,0,0);
  184. }
  185. }
  186. CRITICAL_SECTION g_render_cs;
  187. static int g_is_beat;
  188. char g_path[1024];
  189. int beat_peak1,beat_peak2, beat_cnt,beat_peak1_peak;
  190. void main_setRenderThreadPriority()
  191. {
  192. int prios[]={
  193. GetThreadPriority(GetCurrentThread()),
  194. THREAD_PRIORITY_IDLE,
  195. THREAD_PRIORITY_LOWEST,
  196. THREAD_PRIORITY_NORMAL,
  197. THREAD_PRIORITY_HIGHEST,
  198. };
  199. SetThreadPriority(g_hThread,prios[cfg_render_prio]);
  200. }
  201. extern void previous_preset(HWND hwnd);
  202. extern void next_preset(HWND hwnd);
  203. extern void random_preset(HWND hwnd);
  204. #if 0//syntax highlighting
  205. HINSTANCE hRich;
  206. #endif
  207. static int init(struct winampVisModule *this_mod)
  208. {
  209. DWORD id;
  210. FILETIME ft;
  211. #if 0//syntax highlighting
  212. if (!hRich) hRich=LoadLibrary("RICHED32.dll");
  213. #endif
  214. GetSystemTimeAsFileTime(&ft);
  215. srand(ft.dwLowDateTime|ft.dwHighDateTime^GetCurrentThreadId());
  216. g_hInstance=this_mod->hDllInstance;
  217. GetModuleFileName(g_hInstance,g_path,MAX_PATH);
  218. char *p=g_path+strlen(g_path);
  219. while (p > g_path && *p != '\\') p--;
  220. *p = 0;
  221. #ifdef WA2_EMBED
  222. if (SendMessage(this_mod->hwndParent,WM_USER,0,0) < 0x2900)
  223. {
  224. char title[16];
  225. MessageBox(this_mod->hwndParent,WASABI_API_LNGSTRING(IDS_REQUIRES_2_9_PLUS),
  226. WASABI_API_LNGSTRING_BUF(IDS_AVS_ERROR,title,16),MB_OK|MB_ICONSTOP);
  227. return 1;
  228. }
  229. #endif
  230. #ifndef NO_MMX
  231. extern int is_mmx(void);
  232. if (!is_mmx())
  233. {
  234. char title[16];
  235. MessageBox(this_mod->hwndParent,WASABI_API_LNGSTRING(IDS_NO_MMX_SUPPORT),
  236. WASABI_API_LNGSTRING_BUF(IDS_AVS_ERROR,title,16),MB_OK|MB_ICONSTOP);
  237. return 1;
  238. }
  239. #endif
  240. #ifdef LASER
  241. strcat(g_path,"\\avs_laser");
  242. #else
  243. strcat(g_path,"\\avs");
  244. #endif
  245. CreateDirectory(g_path,NULL);
  246. InitializeCriticalSection(&g_cs);
  247. InitializeCriticalSection(&g_render_cs);
  248. g_ThreadQuit=0;
  249. g_visdata_pstat=1;
  250. AVS_EEL_IF_init();
  251. if (Wnd_Init(this_mod)) return 1;
  252. {
  253. int x;
  254. for (x = 0; x < 256; x ++)
  255. {
  256. double a=log((double)x*60.0/255.0 + 1.0)/log(60.0);
  257. int t=(int)(a*255.0);
  258. if (t<0)t=0;
  259. if (t>255)t=255;
  260. g_logtab[x]=(unsigned char )t;
  261. }
  262. }
  263. initBpm();
  264. Render_Init(g_hInstance);
  265. CfgWnd_Create(this_mod);
  266. g_hThread=(HANDLE)_beginthreadex(NULL,0,RenderThread,0,0,(unsigned int *)&id);
  267. main_setRenderThreadPriority();
  268. SetForegroundWindow(g_hwnd);
  269. SetFocus(g_hwnd);
  270. return 0;
  271. }
  272. static int render(struct winampVisModule *this_mod)
  273. {
  274. int x,avs_beat=0,b;
  275. if (g_ThreadQuit) return 1;
  276. EnterCriticalSection(&g_cs);
  277. if (g_ThreadQuit)
  278. {
  279. LeaveCriticalSection(&g_cs);
  280. return 1;
  281. }
  282. if (g_visdata_pstat)
  283. for (x = 0; x< 576*2; x ++)
  284. g_visdata[0][0][x]=g_logtab[(unsigned char)this_mod->spectrumData[0][x]];
  285. else
  286. {
  287. for (x = 0; x < 576*2; x ++)
  288. {
  289. int t=g_logtab[(unsigned char)this_mod->spectrumData[0][x]];
  290. if (g_visdata[0][0][x] < t)
  291. g_visdata[0][0][x] = t;
  292. }
  293. }
  294. memcpy(&g_visdata[1][0][0],this_mod->waveformData,576*2);
  295. {
  296. int lt[2]={0,0};
  297. int x;
  298. int ch;
  299. for (ch = 0; ch < 2; ch ++)
  300. {
  301. unsigned char *f=(unsigned char*)&this_mod->waveformData[ch][0];
  302. for (x = 0; x < 576; x ++)
  303. {
  304. int r= *f++^128;
  305. r-=128;
  306. if (r<0)r=-r;
  307. lt[ch]+=r;
  308. }
  309. }
  310. lt[0]=max(lt[0],lt[1]);
  311. beat_peak1=(beat_peak1*125+beat_peak2*3)/128;
  312. beat_cnt++;
  313. if (lt[0] >= (beat_peak1*34)/32 && lt[0] > (576*16))
  314. {
  315. if (beat_cnt>0)
  316. {
  317. beat_cnt=0;
  318. avs_beat=1;
  319. }
  320. beat_peak1=(lt[0]+beat_peak1_peak)/2;
  321. beat_peak1_peak=lt[0];
  322. }
  323. else if (lt[0] > beat_peak2)
  324. {
  325. beat_peak2=lt[0];
  326. }
  327. else beat_peak2=(beat_peak2*14)/16;
  328. }
  329. b=refineBeat(avs_beat);
  330. if (b) g_is_beat=1;
  331. g_visdata_pstat=0;
  332. LeaveCriticalSection(&g_cs);
  333. return 0;
  334. }
  335. static void quit(struct winampVisModule *this_mod)
  336. {
  337. #define DS(x)
  338. //MessageBox(this_mod->hwndParent,x,"AVS Debug",MB_OK)
  339. if (g_hThread)
  340. {
  341. DS("Waitin for thread to quit\n");
  342. g_ThreadQuit=1;
  343. if (WaitForSingleObject(g_hThread,10000) != WAIT_OBJECT_0)
  344. {
  345. DS("Terminated thread (BAD!)\n");
  346. //MessageBox(NULL,"error waiting for thread to quit","a",MB_TASKMODAL);
  347. TerminateThread(g_hThread,0);
  348. }
  349. DS("Thread done... calling ddraw_quit\n");
  350. DDraw_Quit();
  351. DS("Calling cfgwnd_destroy\n");
  352. CfgWnd_Destroy();
  353. DS("Calling render_quit\n");
  354. Render_Quit(this_mod->hDllInstance);
  355. DS("Calling wnd_quit\n");
  356. Wnd_Quit();
  357. DS("closing thread handle\n");
  358. CloseHandle(g_hThread);
  359. g_hThread=NULL;
  360. DS("calling eel quit\n");
  361. AVS_EEL_IF_quit();
  362. DS("cleaning up critsections\n");
  363. DeleteCriticalSection(&g_cs);
  364. DeleteCriticalSection(&g_render_cs);
  365. DS("smp_cleanupthreads\n");
  366. C_RenderListClass::smp_cleanupthreads();
  367. }
  368. #undef DS
  369. #if 0//syntax highlighting
  370. if (hRich) FreeLibrary(hRich);
  371. hRich=0;
  372. #endif
  373. }
  374. #define FPS_NF 64
  375. static unsigned int WINAPI RenderThread(LPVOID a)
  376. {
  377. int framedata[FPS_NF]={0,};
  378. int framedata_pos=0;
  379. int s=0;
  380. char vis_data[2][2][576];
  381. FILETIME ft;
  382. GetSystemTimeAsFileTime(&ft);
  383. srand(ft.dwLowDateTime|ft.dwHighDateTime^GetCurrentThreadId());
  384. while (!g_ThreadQuit)
  385. {
  386. int w,h,*fb=NULL, *fb2=NULL,beat=0;
  387. #ifdef REAPLAY_PLUGIN
  388. if(!IsWindowVisible(g_hwnd))
  389. {
  390. Sleep(1);
  391. continue;
  392. }
  393. char visdata[576*2*2];
  394. int ret = vuGetVisData(visdata, sizeof(visdata));
  395. if (!ret)
  396. {
  397. memset(&vis_data[0][0][0],0,576*2*2);
  398. beat=0;
  399. }
  400. else
  401. {
  402. int x;
  403. unsigned char *v=(unsigned char *)visdata;
  404. for (x = 0; x < 576*2; x ++)
  405. vis_data[0][0][x]=g_logtab[*v++];
  406. for (x = 0; x < 576*2; x ++)
  407. ((unsigned char *)vis_data[1][0])[x]=*v++;
  408. v=(unsigned char *)visdata+1152;
  409. {
  410. int lt[2]={0,0};
  411. int ch;
  412. for (ch = 0; ch < 2; ch ++)
  413. {
  414. for (x = 0; x < 576; x ++)
  415. {
  416. int r=*v++^128;
  417. r-=128;
  418. if (r<0)r=-r;
  419. lt[ch]+=r;
  420. }
  421. }
  422. lt[0]=max(lt[0],lt[1]);
  423. beat_peak1=(beat_peak1*125+beat_peak2*3)/128;
  424. beat_cnt++;
  425. if (lt[0] >= (beat_peak1*34)/32 && lt[0] > (576*16))
  426. {
  427. if (beat_cnt>0)
  428. {
  429. beat_cnt=0;
  430. beat=1;
  431. }
  432. beat_peak1=(lt[0]+beat_peak1_peak)/2;
  433. beat_peak1_peak=lt[0];
  434. }
  435. else if (lt[0] > beat_peak2)
  436. {
  437. beat_peak2=lt[0];
  438. }
  439. else beat_peak2=(beat_peak2*14)/16;
  440. }
  441. // EnterCriticalSection(&g_title_cs);
  442. beat=refineBeat(beat);
  443. // LeaveCriticalSection(&g_title_cs);
  444. }
  445. #else
  446. EnterCriticalSection(&g_cs);
  447. memcpy(&vis_data[0][0][0],&g_visdata[0][0][0],576*2*2);
  448. g_visdata_pstat=1;
  449. beat=g_is_beat;
  450. g_is_beat=0;
  451. LeaveCriticalSection(&g_cs);
  452. #endif
  453. if (!g_ThreadQuit)
  454. {
  455. if (IsWindow(g_hwnd)&&!g_in_destroy) DDraw_Enter(&w,&h,&fb,&fb2);
  456. else break;
  457. if (fb&&fb2)
  458. {
  459. extern int g_dlg_w, g_dlg_h, g_dlg_fps;
  460. #ifdef LASER
  461. g_laser_linelist->ClearLineList();
  462. #endif
  463. EnterCriticalSection(&g_render_cs);
  464. int t=g_render_transition->render(vis_data,beat,s?fb2:fb,s?fb:fb2,w,h);
  465. LeaveCriticalSection(&g_render_cs);
  466. if (t&1) s^=1;
  467. #ifdef LASER
  468. s=0;
  469. memset(fb,0,w*h*sizeof(int));
  470. LineDrawList(g_laser_linelist,fb,w,h);
  471. #endif
  472. if (IsWindow(g_hwnd)) DDraw_Exit(s);
  473. int lastt=framedata[framedata_pos];
  474. int thist=GetTickCount();
  475. framedata[framedata_pos]=thist;
  476. g_dlg_w=w;
  477. g_dlg_h=h;
  478. if (lastt)
  479. {
  480. g_dlg_fps=MulDiv(sizeof(framedata)/sizeof(framedata[0]),10000,thist-lastt);
  481. }
  482. framedata_pos++;
  483. if (framedata_pos >= sizeof(framedata)/sizeof(framedata[0])) framedata_pos=0;
  484. }
  485. int fs=DDraw_IsFullScreen();
  486. int sv=(fs?(cfg_speed>>8):cfg_speed)&0xff;
  487. Sleep(min(max(sv,1),100));
  488. }
  489. }
  490. _endthreadex(0);
  491. return 0;
  492. }
  493. #ifdef REAPLAY_PLUGIN
  494. static winampVisModule dummyMod;
  495. extern "C"
  496. {
  497. REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec)
  498. {
  499. g_hInstance=hInstance;
  500. if (rec)
  501. {
  502. if (rec->caller_version != REAPER_PLUGIN_VERSION || !rec->GetFunc)
  503. return 0;
  504. *((void **)&get_ini_file) = rec->GetFunc("get_ini_file");
  505. *((void **)&vuGetVisData) = rec->GetFunc("vuGetVisData");
  506. if (!get_ini_file || !vuGetVisData)
  507. return 0;
  508. dummyMod.hwndParent=rec->hwnd_main;
  509. dummyMod.hDllInstance=g_hInstance;
  510. init(&dummyMod);
  511. return 1;
  512. }
  513. else
  514. {
  515. quit(&dummyMod);
  516. return 0;
  517. }
  518. }
  519. };
  520. #endif