diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Visualization/vis_avs/main.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Visualization/vis_avs/main.cpp')
-rw-r--r-- | Src/Plugins/Visualization/vis_avs/main.cpp | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/Src/Plugins/Visualization/vis_avs/main.cpp b/Src/Plugins/Visualization/vis_avs/main.cpp new file mode 100644 index 00000000..05b16d5c --- /dev/null +++ b/Src/Plugins/Visualization/vis_avs/main.cpp @@ -0,0 +1,604 @@ +/* + LICENSE + ------- +Copyright 2005 Nullsoft, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Nullsoft nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ +#include <windows.h> +#include <math.h> +#include <process.h> +#include "draw.h" +#include "wnd.h" +#include "r_defs.h" +#include "render.h" +#include "vis.h" +#include "cfgwnd.h" +#include "resource.h" +#include "bpm.h" +#include "api.h" +#include "../winamp/wa_ipc.h" +#include "../Agave/Language/api_language.h" +#include <api/service/waServiceFactory.h> + +#include <stdio.h> + +#ifdef REAPLAY_PLUGIN +#include "../../jmde/reaper_plugin.h" +const char *(*get_ini_file)(); +int (*vuGetVisData)(char *vdata, int size); +#endif + +#define PLUGIN_VERSION "v2.93" + +#include "avs_eelif.h" + +extern void GetClientRect_adj(HWND hwnd, RECT *r); + +static unsigned char g_logtab[256]; +HINSTANCE g_hInstance; + +/* char *verstr= +#ifndef LASER +"Advanced Visualization Studio" +#else +"AVS/Laser" +#endif +" v2.92" +; +*/ + +static unsigned int WINAPI RenderThread(LPVOID a); + +static void config(struct winampVisModule *this_mod); +static int init(struct winampVisModule *this_mod); +static int render(struct winampVisModule *this_mod); +static void quit(struct winampVisModule *this_mod); + +HANDLE g_hThread; +volatile int g_ThreadQuit; + +static CRITICAL_SECTION g_cs; + +static unsigned char g_visdata[2][2][576]; +static int g_visdata_pstat; + +/* wasabi based services for localisation support */ +api_service *WASABI_API_SVC = 0; +api_language *WASABI_API_LNG = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; +static char module1[128]; + +static winampVisModule *getModule(int which); +static winampVisHeader hdr = { VIS_HDRVER, 0, getModule }; + +// use this to get our own HINSTACE since overriding DllMain(..) causes instant crashes (should see why) + +static HINSTANCE GetMyInstance() +{ + MEMORY_BASIC_INFORMATION mbi = {0}; + if(VirtualQuery(GetMyInstance, &mbi, sizeof(mbi))) + return (HINSTANCE)mbi.AllocationBase; + return NULL; +} + +extern "C" { + __declspec( dllexport ) winampVisHeader* winampVisGetHeader(HWND hwndParent) + { + if(!WASABI_API_LNG_HINST) + { + // loader so that we can get the localisation service api for use + WASABI_API_SVC = (api_service*)SendMessage(hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE); + if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL; + + waServiceFactory *sf = WASABI_API_SVC->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(GetMyInstance(),VisAVSLangGUID); + } + + #ifndef LASER + static char szDescription[256]; + wsprintfA(szDescription,"%s " PLUGIN_VERSION,WASABI_API_LNGSTRING_BUF(IDS_AVS,module1,128)); + hdr.description = szDescription; + #else + hdr.description = "AVS/Laser "PLUGIN_VERSION; + #endif + + return &hdr; + } +} + +static winampVisModule *getModule(int which) +{ + static winampVisModule mod = + { +#ifdef LASER + "Advanced Visualization Studio/Laser", +#else + module1, +#endif + NULL, // hwndParent + NULL, // hDllInstance + 0, // sRate + 0, // nCh + 1000/70, // latencyMS + 1000/70,// delayMS + 2, // spectrumNch + 2, // waveformNch + { 0, }, // spectrumData + { 0, }, // waveformData + config, + init, + render, + quit + }; + if (which==0) return &mod; + return 0; +} + +void about(HWND hwndParent) + + { + static int about_here = 0; + char aboutbuf[1024] = {0}, aboutTitle[48] = {0}; + if (about_here) + { + SetActiveWindow(FindWindow("#32770",WASABI_API_LNGSTRING_BUF(IDS_ABOUT_AVS,aboutTitle,48))); + return; + } + about_here = 1; + wsprintf(aboutbuf,WASABI_API_LNGSTRING(IDS_ABOUT_STRING),hdr.description); + MessageBox(hwndParent,aboutbuf,WASABI_API_LNGSTRING_BUF(IDS_ABOUT_AVS,aboutTitle,48),0); + about_here = 0; +} + +HWND GetDialogBoxParent(HWND winamp) +{ + HWND parent = (HWND)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT); + if (!parent || parent == (HWND)1) + return winamp; + return parent; + +/* +BOOL CALLBACK aboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + SetDlgItemText(hwndDlg,IDC_VERSTR,verstr); + + return 1; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: case IDCANCEL: + EndDialog(hwndDlg,0); + return 0; + } + return 0; + } + return 0; +*/ + +} + +static void config(struct winampVisModule *this_mod) +{ + if (!g_hwnd || !IsWindow(g_hwnd)) + { + about(GetDialogBoxParent(this_mod->hwndParent)); +// DialogBox(this_mod->hDllInstance,MAKEINTRESOURCE(IDD_DIALOG2),this_mod->hwndParent,aboutProc); + } + else + { + SendMessage(g_hwnd,WM_USER+33,0,0); + } +} + +CRITICAL_SECTION g_render_cs; +static int g_is_beat; +char g_path[1024]; + +int beat_peak1,beat_peak2, beat_cnt,beat_peak1_peak; + +void main_setRenderThreadPriority() +{ + int prios[]={ + GetThreadPriority(GetCurrentThread()), + THREAD_PRIORITY_IDLE, + THREAD_PRIORITY_LOWEST, + THREAD_PRIORITY_NORMAL, + THREAD_PRIORITY_HIGHEST, + }; + SetThreadPriority(g_hThread,prios[cfg_render_prio]); +} + +extern void previous_preset(HWND hwnd); +extern void next_preset(HWND hwnd); +extern void random_preset(HWND hwnd); + +#if 0//syntax highlighting +HINSTANCE hRich; +#endif + +static int init(struct winampVisModule *this_mod) +{ + DWORD id; + FILETIME ft; +#if 0//syntax highlighting + if (!hRich) hRich=LoadLibrary("RICHED32.dll"); +#endif + GetSystemTimeAsFileTime(&ft); + srand(ft.dwLowDateTime|ft.dwHighDateTime^GetCurrentThreadId()); + g_hInstance=this_mod->hDllInstance; + GetModuleFileName(g_hInstance,g_path,MAX_PATH); + char *p=g_path+strlen(g_path); + while (p > g_path && *p != '\\') p--; + *p = 0; + +#ifdef WA2_EMBED + if (SendMessage(this_mod->hwndParent,WM_USER,0,0) < 0x2900) + { + char title[16]; + MessageBox(this_mod->hwndParent,WASABI_API_LNGSTRING(IDS_REQUIRES_2_9_PLUS), + WASABI_API_LNGSTRING_BUF(IDS_AVS_ERROR,title,16),MB_OK|MB_ICONSTOP); + return 1; + } +#endif + +#ifndef NO_MMX + extern int is_mmx(void); + if (!is_mmx()) + { + char title[16]; + MessageBox(this_mod->hwndParent,WASABI_API_LNGSTRING(IDS_NO_MMX_SUPPORT), + WASABI_API_LNGSTRING_BUF(IDS_AVS_ERROR,title,16),MB_OK|MB_ICONSTOP); + return 1; + } +#endif + +#ifdef LASER + strcat(g_path,"\\avs_laser"); +#else + strcat(g_path,"\\avs"); +#endif + CreateDirectory(g_path,NULL); + + InitializeCriticalSection(&g_cs); + InitializeCriticalSection(&g_render_cs); + g_ThreadQuit=0; + g_visdata_pstat=1; + + AVS_EEL_IF_init(); + + if (Wnd_Init(this_mod)) return 1; + + { + int x; + for (x = 0; x < 256; x ++) + { + double a=log((double)x*60.0/255.0 + 1.0)/log(60.0); + int t=(int)(a*255.0); + if (t<0)t=0; + if (t>255)t=255; + g_logtab[x]=(unsigned char )t; + } + } + + initBpm(); + + Render_Init(g_hInstance); + + CfgWnd_Create(this_mod); + + g_hThread=(HANDLE)_beginthreadex(NULL,0,RenderThread,0,0,(unsigned int *)&id); + main_setRenderThreadPriority(); + SetForegroundWindow(g_hwnd); + SetFocus(g_hwnd); + + return 0; +} + +static int render(struct winampVisModule *this_mod) +{ + int x,avs_beat=0,b; + if (g_ThreadQuit) return 1; + EnterCriticalSection(&g_cs); + if (g_ThreadQuit) + { + LeaveCriticalSection(&g_cs); + return 1; + } + if (g_visdata_pstat) + for (x = 0; x< 576*2; x ++) + g_visdata[0][0][x]=g_logtab[(unsigned char)this_mod->spectrumData[0][x]]; + else + { + for (x = 0; x < 576*2; x ++) + { + int t=g_logtab[(unsigned char)this_mod->spectrumData[0][x]]; + if (g_visdata[0][0][x] < t) + g_visdata[0][0][x] = t; + } + } + memcpy(&g_visdata[1][0][0],this_mod->waveformData,576*2); + { + int lt[2]={0,0}; + int x; + int ch; + for (ch = 0; ch < 2; ch ++) + { + unsigned char *f=(unsigned char*)&this_mod->waveformData[ch][0]; + for (x = 0; x < 576; x ++) + { + int r= *f++^128; + r-=128; + if (r<0)r=-r; + lt[ch]+=r; + } + } + lt[0]=max(lt[0],lt[1]); + + beat_peak1=(beat_peak1*125+beat_peak2*3)/128; + + beat_cnt++; + + if (lt[0] >= (beat_peak1*34)/32 && lt[0] > (576*16)) + { + if (beat_cnt>0) + { + beat_cnt=0; + avs_beat=1; + } + beat_peak1=(lt[0]+beat_peak1_peak)/2; + beat_peak1_peak=lt[0]; + } + else if (lt[0] > beat_peak2) + { + beat_peak2=lt[0]; + } + else beat_peak2=(beat_peak2*14)/16; + + } + b=refineBeat(avs_beat); + if (b) g_is_beat=1; + g_visdata_pstat=0; + LeaveCriticalSection(&g_cs); + return 0; +} + +static void quit(struct winampVisModule *this_mod) +{ +#define DS(x) + //MessageBox(this_mod->hwndParent,x,"AVS Debug",MB_OK) + if (g_hThread) + { + DS("Waitin for thread to quit\n"); + g_ThreadQuit=1; + if (WaitForSingleObject(g_hThread,10000) != WAIT_OBJECT_0) + { + DS("Terminated thread (BAD!)\n"); + //MessageBox(NULL,"error waiting for thread to quit","a",MB_TASKMODAL); + TerminateThread(g_hThread,0); + } + DS("Thread done... calling ddraw_quit\n"); + DDraw_Quit(); + + DS("Calling cfgwnd_destroy\n"); + CfgWnd_Destroy(); + DS("Calling render_quit\n"); + Render_Quit(this_mod->hDllInstance); + + DS("Calling wnd_quit\n"); + Wnd_Quit(); + + DS("closing thread handle\n"); + CloseHandle(g_hThread); + g_hThread=NULL; + + DS("calling eel quit\n"); + AVS_EEL_IF_quit(); + + DS("cleaning up critsections\n"); + DeleteCriticalSection(&g_cs); + DeleteCriticalSection(&g_render_cs); + + DS("smp_cleanupthreads\n"); + C_RenderListClass::smp_cleanupthreads(); + } +#undef DS +#if 0//syntax highlighting + if (hRich) FreeLibrary(hRich); + hRich=0; +#endif +} + +#define FPS_NF 64 + +static unsigned int WINAPI RenderThread(LPVOID a) +{ + int framedata[FPS_NF]={0,}; + int framedata_pos=0; + int s=0; + char vis_data[2][2][576]; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + srand(ft.dwLowDateTime|ft.dwHighDateTime^GetCurrentThreadId()); + while (!g_ThreadQuit) + { + int w,h,*fb=NULL, *fb2=NULL,beat=0; + +#ifdef REAPLAY_PLUGIN + if(!IsWindowVisible(g_hwnd)) + { + Sleep(1); + continue; + } + + char visdata[576*2*2]; + int ret = vuGetVisData(visdata, sizeof(visdata)); + if (!ret) + { + memset(&vis_data[0][0][0],0,576*2*2); + beat=0; + } + else + { + int x; + unsigned char *v=(unsigned char *)visdata; + for (x = 0; x < 576*2; x ++) + vis_data[0][0][x]=g_logtab[*v++]; + for (x = 0; x < 576*2; x ++) + ((unsigned char *)vis_data[1][0])[x]=*v++; + + v=(unsigned char *)visdata+1152; + { + int lt[2]={0,0}; + int ch; + for (ch = 0; ch < 2; ch ++) + { + for (x = 0; x < 576; x ++) + { + int r=*v++^128; + r-=128; + if (r<0)r=-r; + lt[ch]+=r; + } + } + lt[0]=max(lt[0],lt[1]); + + beat_peak1=(beat_peak1*125+beat_peak2*3)/128; + beat_cnt++; + + if (lt[0] >= (beat_peak1*34)/32 && lt[0] > (576*16)) + { + if (beat_cnt>0) + { + beat_cnt=0; + beat=1; + } + beat_peak1=(lt[0]+beat_peak1_peak)/2; + beat_peak1_peak=lt[0]; + } + else if (lt[0] > beat_peak2) + { + beat_peak2=lt[0]; + } + else beat_peak2=(beat_peak2*14)/16; + + } +// EnterCriticalSection(&g_title_cs); + beat=refineBeat(beat); +// LeaveCriticalSection(&g_title_cs); + } +#else + EnterCriticalSection(&g_cs); + memcpy(&vis_data[0][0][0],&g_visdata[0][0][0],576*2*2); + g_visdata_pstat=1; + beat=g_is_beat; + g_is_beat=0; + LeaveCriticalSection(&g_cs); +#endif + + if (!g_ThreadQuit) + { + if (IsWindow(g_hwnd)&&!g_in_destroy) DDraw_Enter(&w,&h,&fb,&fb2); + else break; + if (fb&&fb2) + { + extern int g_dlg_w, g_dlg_h, g_dlg_fps; +#ifdef LASER + g_laser_linelist->ClearLineList(); +#endif + + EnterCriticalSection(&g_render_cs); + int t=g_render_transition->render(vis_data,beat,s?fb2:fb,s?fb:fb2,w,h); + LeaveCriticalSection(&g_render_cs); + if (t&1) s^=1; + +#ifdef LASER + s=0; + memset(fb,0,w*h*sizeof(int)); + LineDrawList(g_laser_linelist,fb,w,h); +#endif + if (IsWindow(g_hwnd)) DDraw_Exit(s); + + int lastt=framedata[framedata_pos]; + int thist=GetTickCount(); + framedata[framedata_pos]=thist; + g_dlg_w=w; + g_dlg_h=h; + if (lastt) + { + g_dlg_fps=MulDiv(sizeof(framedata)/sizeof(framedata[0]),10000,thist-lastt); + } + framedata_pos++; + if (framedata_pos >= sizeof(framedata)/sizeof(framedata[0])) framedata_pos=0; + + } + int fs=DDraw_IsFullScreen(); + int sv=(fs?(cfg_speed>>8):cfg_speed)&0xff; + Sleep(min(max(sv,1),100)); + } + } + _endthreadex(0); + return 0; +} + +#ifdef REAPLAY_PLUGIN +static winampVisModule dummyMod; +extern "C" +{ + + REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec) + { + g_hInstance=hInstance; + if (rec) + { + if (rec->caller_version != REAPER_PLUGIN_VERSION || !rec->GetFunc) + return 0; + + *((void **)&get_ini_file) = rec->GetFunc("get_ini_file"); + *((void **)&vuGetVisData) = rec->GetFunc("vuGetVisData"); + if (!get_ini_file || !vuGetVisData) + return 0; + + dummyMod.hwndParent=rec->hwnd_main; + dummyMod.hDllInstance=g_hInstance; + init(&dummyMod); + + return 1; + } + else + { + quit(&dummyMod); + return 0; + } + } + +}; +#endif |