/* Spectrum Analyzer */ #include "Main.h" #include #include "../nu/threadname.h" static int last_pos; typedef struct sa_l { int timestamp; unsigned char data[2*75]; char which; } sa_l; static int sa_fps = 76; static sa_l *sa_bufs; static int sa_position; static int sa_length, sa_size; static CRITICAL_SECTION cs; void sa_init(int numframes) { EnterCriticalSection(&cs); sa_length=0; if (numframes < 1) numframes = 1; if (numframes > sa_size) { free(sa_bufs); sa_bufs = (sa_l *)calloc(numframes, sizeof(sa_l)); sa_size=numframes; } sa_position = 0; sa_length = numframes; last_pos = 0; LeaveCriticalSection(&cs); } void sa_deinit(void) { EnterCriticalSection(&cs); //if (sa_bufs) // { // free(sa_bufs); // sa_bufs = 0; sa_length = 0; //} LeaveCriticalSection(&cs); } int sa_add(char *values, int timestamp, int csa) { EnterCriticalSection(&cs); if (!sa_bufs || sa_length == 0) { LeaveCriticalSection(&cs); return 1; } if (sa_length == 1) { sa_position = 0; } if (csa == 3) csa = 1; // dont let it happen unless it has a high bit set csa &= 0x7fffffff; sa_bufs[sa_position].timestamp = timestamp; sa_bufs[sa_position].which = (char)csa; if (csa & 1) { memcpy(sa_bufs[sa_position].data, values, 75); values += 75; } else memset(sa_bufs[sa_position].data, 0, 75); if (csa & 2) memcpy(sa_bufs[sa_position].data + 75, values, 75); else memset(sa_bufs[sa_position].data + 75, 0, 75); sa_position++; if (sa_position >= sa_length) sa_position -= sa_length; LeaveCriticalSection(&cs); return 0; } char *sa_get(int timestamp, int csa, char data[75*2+8]) { static int sa_pos; int closest = 1000000, closest_v = -1; EnterCriticalSection(&cs); if (!sa_bufs || sa_length==0) { LeaveCriticalSection(&cs); return 0; } if (sa_length == 1) { memcpy(data, sa_bufs[0].data, 75*2); LeaveCriticalSection(&cs); return (data); } int i = last_pos; for (int x = 0; x < sa_length; x ++) { if (i >= sa_length) i = 0; int d = timestamp - sa_bufs[i].timestamp; if (d < 0) d = -d; if (d < closest) { closest = d; closest_v = i; } else if (closest <= 6) break; i++; } if (closest < 400 && closest_v >= 0 && sa_bufs[closest_v].which & csa) { sa_pos = 0; last_pos = closest_v; memcpy(data, sa_bufs[closest_v].data, 75*2); LeaveCriticalSection(&cs); return data; } if (closest_v < 0 || !(sa_bufs[closest_v].which & csa) || closest > 400) { memset(data, 0, 75); data[(sa_pos % 150) >= 75 ? 149 - (sa_pos % 150) : (sa_pos % 150)] = 15; for (int x = 0; x < 75; x ++) data[x + 75] = (char) (int) (7.0 * sin((sa_pos + x) * 0.1)); sa_pos++; LeaveCriticalSection(&cs); return data; } LeaveCriticalSection(&cs); return 0; } volatile int sa_override; void export_sa_setreq(int want) { EnterCriticalSection(&cs); sa_override = want; LeaveCriticalSection(&cs); } char *export_sa_get_deprecated() { static char data[75*2 + 8]; int now = in_getouttime(); char *p = sa_get(now, 3, data); if (!p) memset(data, 0, 75*2); return data; } char *export_sa_get(char data[75*2 + 8]) { try { int now = in_getouttime(); char *p = sa_get(now, 3, data); if (!p) memset(data, 0, 75*2); } catch(...) {} return data; } #pragma optimize("", off) // for some reason, optimizations are breaking the case statement in bivis_thread #define KILL_EVENT 0 #define BLANK_EVENT 1 #define ON_EVENT 2 #define NUM_EVENTS 3 #define saKillEvent saEvents[0] #define saBlankEvent saEvents[1] #define saOnEvent saEvents[2] HANDLE saEvents[NUM_EVENTS] = {0}; static int SA_Wait() { if (WaitForSingleObject(saKillEvent, 16) == WAIT_OBJECT_0) return KILL_EVENT; if (WaitForSingleObject(saBlankEvent, 0) == WAIT_OBJECT_0) return BLANK_EVENT; return WaitForMultipleObjects(NUM_EVENTS, saEvents, FALSE, INFINITE)-WAIT_OBJECT_0; } static DWORD WINAPI bivis_thread(void *none) { int cycleCount=0; __int8 data[75*2 + 8] = {0}; SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); SetThreadName((DWORD)-1, "Classic Viz"); while (1) { switch(SA_Wait()) { case KILL_EVENT: return 0; case BLANK_EVENT: draw_sa(NULL, 1); break; case ON_EVENT: { int draw=0; if (++cycleCount < config_saref) draw=0; else { cycleCount=0; draw=1; } if (config_sa && !paused && playing && !config_minimized && (config_mw_open || (config_pe_open && config_pe_width >= 350 && config_pe_height != 14)) && (!config_disvis || !vis_running())) { int a = in_getouttime(); int t = config_sa; //if ((config_windowshade&&config_mw_open) && t == 1) t=4; char *c = sa_get(a, t, data); if (c) { if (t == 2) c += 75; else memset(c + 75, 0, 4); draw_sa((unsigned char*)c, draw); } } } break; } } return 0; } #pragma optimize("", on) HANDLE saThread=0; void SpectralAnalyzer_Create() { DWORD threadId = 0; InitializeCriticalSection(&cs); saKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL); saBlankEvent= CreateEvent(NULL, FALSE, FALSE, NULL); saOnEvent = CreateEvent(NULL, TRUE, FALSE, NULL); saThread = (HANDLE) CreateThread(NULL, 256*1024, (LPTHREAD_START_ROUTINE) bivis_thread, 0, 0, &threadId); //cut: done on thread - SetThreadPriority(saThread, THREAD_PRIORITY_HIGHEST); sa_length=sa_size=0; VU_Create(); } void SpectralAnalyzer_Destroy() { VU_Destroy(); SetEvent(saKillEvent); WaitForSingleObject(saThread, INFINITE); CloseHandle(saThread); saThread = 0; CloseHandle(saKillEvent); CloseHandle(saBlankEvent); CloseHandle(saOnEvent); DeleteCriticalSection(&cs); free(sa_bufs); sa_bufs=0; sa_size=0; } volatile int sa_curmode; /* @param mode -1==shutdown 0==none, 1==spectral analyzer, 2==oscilloscope */ void sa_setthread(int mode) { if (mode == -1) mode=0; sa_curmode = mode; if (mode) { SetEvent(saOnEvent); } else { ResetEvent(saOnEvent); SetEvent(saBlankEvent); } }