aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/SA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Winamp/SA.cpp')
-rw-r--r--Src/Winamp/SA.cpp314
1 files changed, 314 insertions, 0 deletions
diff --git a/Src/Winamp/SA.cpp b/Src/Winamp/SA.cpp
new file mode 100644
index 00000000..251e0c45
--- /dev/null
+++ b/Src/Winamp/SA.cpp
@@ -0,0 +1,314 @@
+/*
+Spectrum Analyzer
+*/
+
+#include "Main.h"
+#include <math.h>
+#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);
+ }
+} \ No newline at end of file