123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- #include <windowsx.h>
- #include "Main.h"
- #include "vis.h"
- #include "fft.h"
- #include <bfc/platform/types.h>
- #include <math.h>
- #include <assert.h>
- #include "./api.h"
- #include "../nsutil/window.h"
- #include "../nu/threadname.h"
- static winampVisModule *vis_mod;
- static DWORD WINAPI vis_thread(void *tmp);
- static HANDLE hThread;
- static DWORD visThreadId=0;
- static volatile int killThread;
- static int _nch = 2, _numframes=1;
- int _srate = 44100;
- static wchar_t _visplugin_name[512];
- static int _visplugin_num;
- static char *vsa_data;
- static int vsa_position, vsa_entrysize=577*4;
- static int vsa_length,size=576*4;
- static int vis_stopping;
- static CRITICAL_SECTION cs;
- static HWND external_window = NULL;
- static HWND external_window_host = NULL;
- #ifdef _M_IX86
- __inline static int lrint(float flt)
- {
- int intgr;
- _asm
- {
- fld flt
- fistp intgr
- }
- return intgr;
- }
- #else
- __inline static int lrint(float flt)
- {
- return (int)flt;
- }
- #endif
- // quantizes to 23 bits - use appropriately
- #define FASTMIN(x,b) { x = b - x; x += (float)fabs(x); x *= 0.5f; x = b - x; }
- static size_t vis_refCount=0;
- static winampVisModule *GetVis()
- {
- winampVisModule *ret = 0;
- EnterCriticalSection(&cs);
- if (vis_stopping)
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- if (vis_mod)
- {
- ret = vis_mod;
- vis_refCount++;
- }
- LeaveCriticalSection(&cs);
- return ret;
- }
- static void DestroyVis()
- {
- killThread=1;
- vis_stopping=1;
- if (GetCurrentThreadId() != visThreadId)
- {
- HANDLE thisThread = hThread;
- LeaveCriticalSection(&cs);
- // run message pump. this shouldn't last long.
- int x=200;
- while (WaitForSingleObject(thisThread,10) == WAIT_TIMEOUT && x-- > 0)
- {
- WASABI_API_APP->app_messageLoopStep();
- }
- WaitForSingleObject(thisThread,INFINITE);
- EnterCriticalSection(&cs);
- }
- CloseHandle(hThread);
- if (vis_mod)
- FreeLibrary(vis_mod->hDllInstance);
- vis_stopping=0;
- vis_mod=0;
-
- hThread=0;
- killThread=0;
- }
- static void ReleaseVis(winampVisModule *vis)
- {
- if (vis)
- {
- EnterCriticalSection(&cs);
- vis_refCount--;
- if (vis_refCount == 0)
- {
- DestroyVis();
- }
- LeaveCriticalSection(&cs);
- }
- }
- void vis_init(void)
- {
- InitializeCriticalSectionAndSpinCount(&cs, 4000);
- }
- static char *vsa_get(int timestamp);
- static void vsa_setdatasize();
- int vis_running()
- {
- int running=0;
- winampVisModule *vis = GetVis();
- if (vis)
- {
- running = !vis_stopping;
- ReleaseVis(vis);
- }
- return running;
- }
- static int priorities[5] =
- {
- THREAD_PRIORITY_LOWEST,
- THREAD_PRIORITY_BELOW_NORMAL,
- THREAD_PRIORITY_NORMAL,
- THREAD_PRIORITY_ABOVE_NORMAL,
- THREAD_PRIORITY_HIGHEST
- };
- void vis_start(HWND hwnd, wchar_t *fn)
- {
- if (vis_stopping || g_safeMode) return;
- vis_stop();
- vsa_deinit();
- if (!config_visplugin_name[0]) return;
- killThread=0;
- if (!fn || !*fn)
- {
- PathCombineW(_visplugin_name, VISDIR, config_visplugin_name);
- _visplugin_num=config_visplugin_num;
- }
- else
- {
- wchar_t buf[MAX_PATH] = {0};
- wchar_t *p;
- StringCchCopyW(buf,MAX_PATH,fn);
- p=wcsstr(buf,L",");
- if (p)
- {
- *p++=0;
- _visplugin_num=_wtoi(p);
- }
- else _visplugin_num=0;
- if (PathIsFileSpecW(buf) || PathIsRelativeW(buf))
- PathCombineW(_visplugin_name, VISDIR, buf);
- else
- StringCchCopyW(_visplugin_name,512,buf);
- }
- hThread = (HANDLE) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) vis_thread,NULL,0,&visThreadId);
- SetThreadPriority(hThread,priorities[config_visplugin_priority]);
- }
- void vis_setprio()
- {
- if (vis_stopping) return;
- if (hThread) SetThreadPriority(hThread,priorities[config_visplugin_priority]);
- }
- void vis_stop()
- {
- if (vis_stopping||!hThread) return;
- EnterCriticalSection(&cs); // go into critical section so vis_mod doesn't suddenly appear out of nowhere
- winampVisModule *thisVis = vis_mod;
- LeaveCriticalSection(&cs);
- ReleaseVis(thisVis);
- }
- void vis_setinfo(int srate, int nch)
- {
- if (srate > 0) _srate = srate;
- if (nch > 0) _nch = nch;
- if (!vis_running()) return;
- EnterCriticalSection(&cs);
- winampVisModule *vis = GetVis();
- if (vis)
- {
- vis->sRate = _srate;
- vis->nCh = _nch;
- ReleaseVis(vis);
- }
- LeaveCriticalSection(&cs);
- }
- void vis_setextwindow(HWND hwnd)
- {
- HWND test_window;
- unsigned int test_window_style_ex;
- unsigned long window_thread_id;
- EnterCriticalSection(&cs);
- external_window = hwnd;
- external_window_host = external_window;
- window_thread_id = GetWindowThreadProcessId(external_window, NULL);
- while(NULL != external_window_host)
- {
- test_window = GetAncestor(external_window_host, GA_PARENT);
- if (NULL != test_window &&
- window_thread_id == GetWindowThreadProcessId(test_window, NULL))
- {
- test_window_style_ex = (unsigned int)GetWindowLongPtrW(test_window, GWL_STYLE);
- if (0 != (WS_EX_CONTROLPARENT & test_window_style_ex))
- {
- external_window_host = test_window;
- continue;
- }
- }
- break;
- }
-
- LeaveCriticalSection(&cs);
- }
- static winampVisModule *CreateVis(HINSTANCE visLib)
- {
- EnterCriticalSection(&cs);
- winampVisModule *ret = 0;
- ret = GetVis();
- if (ret)
- {
- LeaveCriticalSection(&cs);
- return ret;
- }
- winampVisGetHeaderType pr;
- pr = (winampVisGetHeaderType) GetProcAddress(visLib,"winampVisGetHeader");
- if (!pr)
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- winampVisHeader* pv = pr(hMainWindow);
- if (!pv)
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- vis_mod = pv->getModule(_visplugin_num);
- if (!vis_mod)
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- vis_mod->sRate = _srate;
- vis_mod->nCh = _nch;
- vis_mod->hwndParent = hMainWindow;
- vis_mod->hDllInstance = visLib;
- vis_refCount++;
- LeaveCriticalSection(&cs);
- return vis_mod;
- }
- static BOOL vis_process_message(MSG *msg)
- {
- if (msg->message >= WM_KEYFIRST && msg->message <= WM_KEYLAST &&
- msg->hwnd == external_window &&
- NULL != external_window)
- {
- return FALSE;
- }
- if (WM_MOUSEWHEEL == msg->message &&
- NULL != external_window_host)
- {
- POINT cursor;
- HWND target_window;
-
- POINTSTOPOINT(cursor, msg->lParam);
- target_window = WindowFromPoint(cursor);
- if (NULL != target_window &&
- FALSE == IsChild(external_window_host, target_window ) &&
- GetWindowThreadProcessId(target_window, NULL) != GetWindowThreadProcessId(external_window_host, NULL))
- {
- PostMessageW(hMainWindow, msg->message, msg->wParam, msg->lParam);
- return TRUE;
- }
- }
- if (NULL != external_window_host)
- return IsDialogMessageW(external_window_host, msg);
- return FALSE;
- }
- static DWORD WINAPI vis_thread(void *tmp)
- {
- winampVisModule *vis = 0;
- MSG Msg;
- HINSTANCE hLib=0;
- int t=0;
- SetThreadName((DWORD)-1, "Vis (plugin) thread");
- hLib = LoadLibrary(_visplugin_name);
- if (!hLib)
- {
- t=1;
- }
- else
- {
- vis = CreateVis(hLib);
- if (!vis)
- {
- FreeLibrary(hLib);
- hLib = 0;
- t=1;
- }
- }
- if (!t)
- {
- if (!(config_no_visseh&1))
- {
- __try
- {
- t = (vis ? vis->Init(vis) : 1);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- t=1;
- char errstr[512] = {0};
- char caption[512] = {0};
- getString(IDS_PLUGINERROR,errstr,512);
- StringCchCatA(errstr, 512, " (1)");
- MessageBoxA(NULL,errstr,getString(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
- }
- }
- else
- {
- t = vis->Init(vis);
- }
- }
- if (!t)
- {
- if (config_disvis) sa_setthread(0);
- vsa_setdatasize();
-
- while (!killThread)
- {
- if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
- {
- if (Msg.message == WM_QUIT)
- break;
- if (FALSE == vis_process_message(&Msg))
- {
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
- }
- }
- else if (!paused)
- {
- static int upd;
- int p=playing;
- char *data=0;
- if (in_mod && p) data = vsa_get(in_mod->GetOutputTime()+vis->latencyMs);
- if (data)
- {
- int l=vis->spectrumNch;
- for (int n = 0; n < l; n ++)
- {
- memcpy(vis->spectrumData[n],data,576);
- data += 576;
- }
- l=vis->waveformNch;
- for (int n = 0; n < l; n ++)
- {
- memcpy(vis->waveformData[n],data,576);
- data += 576;
- }
- }
- if (!data)
- {
- memset(vis->spectrumData,0,576*2);
- memset(vis->waveformData,0,576*2);
- }
- if (p) upd=1;
- if (upd)
- if (!(config_no_visseh&1))
- {
- __try
- {
- if (vis->Render(vis))
- {
- break;
- }
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- char errstr[512] = {0};
- char caption[512] = {0};
- getString(IDS_PLUGINERROR,errstr,512);
- StringCchCatA(errstr, 512, " (2)");
- MessageBoxA(NULL,errstr,getString(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
- break;
- }
- }
- else
- {
- if (vis->Render(vis))
- {
- break;
- }
- }
- if (!p) upd=0;
- Sleep(vis->delayMs);
- }
- else Sleep(min(1,vis->delayMs));
- }
- vsa_deinit();
- sa_setthread(config_sa);
- if (!(config_no_visseh&1))
- {
- __try
- {
- vis->Quit(vis);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- wchar_t errstr[512] = {0};
- wchar_t caption[512] = {0};
- getStringW(IDS_PLUGINERROR,errstr,512);
- StringCchCatW(errstr, 512, L" (3)");
- MessageBoxW(NULL,errstr,getStringW(IDS_ERROR,caption,512),MB_OK|MB_ICONEXCLAMATION);
- }
- }
- else
- {
- vis->Quit(vis);
- }
- EnterCriticalSection(&cs);
- if (killThread)
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- else
- {
- ReleaseVis(vis);
- LeaveCriticalSection(&cs);
- return 0;
- }
- }
-
- ReleaseVis(vis);
- if (hLib)
- FreeLibrary(hLib);
- hLib = 0;
- return 0;
- }
- static int last_pos;
- static void _vsa_init()
- {
- vsa_deinit();
- if (_numframes < 1) _numframes=1;
- vsa_entrysize = 4+size;
- vsa_data = (char *) GlobalAlloc(GPTR,vsa_entrysize * _numframes);
- vsa_position=0;
- vsa_length = _numframes;
- }
- void vsa_init(int numframes)
- {
- EnterCriticalSection(&cs);
- if (vis_running())
- {
- last_pos=0;
- _numframes=numframes;
- _vsa_init();
- }
- else
- {
- last_pos=0;
- _numframes=numframes;
- }
- LeaveCriticalSection(&cs);
- }
- static void vsa_setdatasize()
- {
- EnterCriticalSection(&cs);
- winampVisModule *vis = GetVis();
- if (vis)
- {
- size=576*(vis->waveformNch+vis->spectrumNch);
- _vsa_init();
- ReleaseVis(vis);
- }
- LeaveCriticalSection(&cs);
- }
- int vsa_add(void *data, int timestamp)
- {
- if (!vsa_data) return 1;
- EnterCriticalSection(&cs);
- if (vsa_data) // check again, it might have gone away while we were waiting on the CS
- {
- if (vsa_length < 2)
- {
- vsa_position = 0;
- }
- char *c = vsa_data + vsa_position*vsa_entrysize;
- *(int32_t *)c=timestamp;
- memcpy(c+4,data,vsa_entrysize-4);
- if (++vsa_position >= vsa_length) vsa_position -= vsa_length;
- LeaveCriticalSection(&cs);
- return 0;
- }
- else
- {
- LeaveCriticalSection(&cs);
- return 1;
- }
- }
- void vsa_deinit(void)
- {
- EnterCriticalSection(&cs);
- if (vsa_data)
- {
- GlobalFree(vsa_data);
- vsa_data=0;
- vsa_length=0;
- }
- LeaveCriticalSection(&cs);
- }
- static char *vsa_get(int timestamp)
- {
- int i,x, closest=1000000, closest_v = -1;
- if (!vsa_data) return NULL;
- if (vsa_length<2)
- {
- return vsa_data+4;
- }
- EnterCriticalSection(&cs);
- x=last_pos;
- if (x >= vsa_length) x=0;
- for (i = 0; i < vsa_length; i ++)
- {
- int *q = (int *)(vsa_data+x*vsa_entrysize);
- int d = timestamp-*q;
- if (++x == vsa_length) x=0;
- if (d < 0) d = -d;
- if (d < closest)
- {
- closest = d;
- closest_v = x;
- }
- else if (closest<200) break;
- }
- if (closest_v >= 0)
- {
- static char data[576*4];
- last_pos=closest_v;
- memcpy(data,vsa_data+vsa_entrysize*closest_v+4,vsa_entrysize-4);
- LeaveCriticalSection(&cs);
- return data;
- }
- else
- {
- LeaveCriticalSection(&cs);
- return 0;
- }
- }
- int vsa_getmode(int *sp, int *wa)
- {
- int rv=0;
- winampVisModule *vis = GetVis();
- if (vis)
- {
- EnterCriticalSection(&cs);
- *sp=vis->spectrumNch;
- *wa=vis->waveformNch;
- rv=1;
- LeaveCriticalSection(&cs);
- ReleaseVis(vis);
- }
- else *sp=*wa=0;
- return rv;
- }
- void FillRealSamples_8Bit(unsigned char *data, const int stride, const int channels, float *samples, const float divider)
- {
- int frame,c;
- const float p = (float)channels*divider;
- for (frame = 0; frame <512; frame ++)
- {
- //done by memset - samples[x*2]=0;
- for (c=0;c<channels;c++)
- {
- samples[frame] += (float)(*data - 128);
- data+=stride; // jump to the next sample (channels are interleaved)
- }
- samples[frame] /= p;
- //done by memset - wavetrum[x*2+1] = 0.0f;
- }
- nsutil_window_Hann_F32_IP(samples, 512);
- }
- #define SA_DC_FILTER
- void FillRealSamples(char *ptr, const int stride, const int channels, float *samples, const float divider)
- {
- #ifdef SA_DC_FILTER
- float x1=0, y1=0;
- #endif
- int frame, c;
- const float p=(float)channels * divider;
- // we're calculating using only the most significant byte,
- // because we only end up with 6 bit data anyway
- // if you want full resolution, check out CVS tag BETA_2005_1122_182830, file: vis.c
- for (frame = 0;frame <512;frame++)
- {
- //done by memset - wavetrum[x*2]=0;
- float x=0;
- for (c=0;c<channels;c++)
- {
- x += (float)(*ptr);
- ptr+=stride; // jump to the next sample (channels are interleaved)
- }
- #ifdef SA_DC_FILTER
- float y = x - x1 + 0.99f * y1;
- y1=y;
- x1=x;
- #else
- float y=x;
- #endif
- y/=p;
- samples[frame]=y;
- //done by memset - wavetrum[x*2+1] = 0.0f;
- }
- nsutil_window_Hann_F32_IP(samples, 512);
- }
- void vsa_addpcmdata(void *_data_buf, int numChannels, int numBits, int ts)
- {
- char *data_buf = reinterpret_cast<char *>(_data_buf);
- // begin vis plugin stuff
- winampVisModule *vis = GetVis();
- if (vis)
- {
- __declspec(align(32)) float wavetrum[512];
- extern int vsa_add(void *data, int timestamp);
- char data[576*4*2] = {0};
- int data_offs=0;
- int y,x,spectrumChannels, waveformChannels, stride;
- spectrumChannels=min(numChannels,vis->spectrumNch);
- stride=numBits/8;
- for (y = 0; y < spectrumChannels; y ++)
- {
- if (spectrumChannels == 1) // downmix to mono, if necessary
- {
- if (numBits == 8)
- FillRealSamples_8Bit((unsigned char*)data_buf, 1, numChannels, wavetrum, 1.f);
- else
- {
- const int stride=numBits/8; // number of bytes between samples
- char *ptr = data_buf+y*stride+stride-1; // offset for little endian
- FillRealSamples(ptr, stride, numChannels, wavetrum, 1.f);
- }
- }
- else // TODO: deal with 'downmixing' to stereo if channels>2
- {
- if (numBits == 8)
- FillRealSamples_8Bit((unsigned char*)data_buf, numChannels, 1, wavetrum, 1.f);
- else
- {
- const int stride=numBits/8; // number of bytes between samples
- char *ptr = data_buf+y*stride+stride-1; // offset for little endian
- FillRealSamples(ptr, stride*numChannels, 1, wavetrum, 1.f);
- }
- }
- fft_9(wavetrum);
- {
- float la=0;
- int thisBand=0;
- for (x = 0; x < 256; x ++)
- {
- float sinT = wavetrum[x*2];
- float cosT = wavetrum[x*2+1];
- float thisValue=(float)sqrt(sinT*sinT+cosT*cosT)/16.0f;
- thisBand++;
- FASTMIN(thisValue, 255.f);
- data[data_offs++] = lrint((thisValue + la)/2.f);
- //data[data_offs++] = lrint((thisValue + thisValue + la)/3.f);
- data[data_offs++] = lrint(thisValue);
- la=thisValue;
- }
- while ((data_offs % 576)!=0)
- {
- la/=2;
- data[data_offs++]=lrint(la);
- }
- assert((data_offs % 576)==0);
- }
- }
- if (numChannels == 1 && vis->spectrumNch == 2) // upmix, if necessary
- {
- memcpy(data+data_offs,data+data_offs-576,576);
- data_offs+=576;
- }
- waveformChannels=min(numChannels,vis->waveformNch);
- if (waveformChannels == 1) // downmix to mono, if necessary
- {
- char *ptr = data_buf+stride-1; // offset for little endian
- for (x=0;x<576;x++)
- {
- __int32 mix=0;
- for (int channel=0;channel<numChannels;channel++)
- {
- mix += (*ptr);
- ptr+=stride; // jump to the next sample (channels are interleaved)
- }
- data[data_offs++] = (char)(mix / numChannels);
- }
- }
- else // TODO: deal with 'downmixing' to stereo if numChannels>2
- {
- for (y = 0; y < waveformChannels; y++)
- {
- char *ptr = data_buf+y*stride+stride-1; // offset for little endian
- for (x=0;x<576;x++)
- {
- data[data_offs++] = *ptr;
- ptr+=stride*numChannels;
- }
- }
- }
- if (numChannels == 1 && vis->waveformNch == 2)
- {
- memcpy(data+data_offs,data+data_offs-576,576);
- //data_offs+=576;
- }
- vsa_add(data,ts);
- ReleaseVis(vis);
- }
- }
- HWND hVisWindow, hPLVisWindow;
- LRESULT CALLBACK VIS_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- switch (message)
- {
- case WM_LBUTTONDOWN:
- case WM_LBUTTONUP:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONUP:
- case WM_LBUTTONDBLCLK:
- {
- RECT r1, r2;
- int xPos = GET_X_LPARAM(lParam); // horizontal position of cursor
- int yPos = GET_Y_LPARAM(lParam);
- if (hwnd == hVisWindow)
- {
- GetWindowRect(hMainWindow,&r1);
- }
- else GetWindowRect(hPLWindow,&r1);
- GetWindowRect(hwnd,&r2);
- xPos += r2.left-r1.left;
- yPos += r2.top-r1.top;
- lParam = MAKELPARAM(xPos,yPos);
- SendMessageW(hwnd == hVisWindow?hMainWindow:hPLWindow,message,wParam,lParam);
- return 0;
- }
- case WM_USER+0xebe:
- case WM_DROPFILES:
- return SendMessageW(GetParent(hwnd),message,wParam,lParam);
- case WM_CREATE:
- if (NULL != WASABI_API_APP)
- WASABI_API_APP->app_registerGlobalWindow(hwnd);
- break;
- case WM_DESTROY:
- if (NULL != WASABI_API_APP)
- WASABI_API_APP->app_unregisterGlobalWindow(hwnd);
- break;
- }
- if (FALSE != IsDirectMouseWheelMessage(message))
- {
- SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
- return TRUE;
- }
- return DefWindowProcW(hwnd,message,wParam,lParam);
- }
|