aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/oscilloview.c139
-rw-r--r--win32/oscilloview.h19
2 files changed, 158 insertions, 0 deletions
diff --git a/win32/oscilloview.c b/win32/oscilloview.c
new file mode 100644
index 0000000..9759cc1
--- /dev/null
+++ b/win32/oscilloview.c
@@ -0,0 +1,139 @@
+#include "oscilloview.h"
+#include <mmsystem.h>
+#include <shellapi.h>
+#include <windowsx.h>
+
+enum {
+ TIMER_UPDATE = 1
+};
+
+struct oscilloview oscilloview_g = {
+ .flag = ATOMIC_FLAG_INIT
+};
+
+enum {
+ VIEW_SAMPLES = 1024,
+ VIEW_SKIP = 2,
+};
+
+static struct {
+ HINSTANCE hinst;
+ HWND parent;
+ HWND oscilloview;
+ ATOM oscilloview_class;
+ struct oscillodata oscillodata[LIBOPNA_OSCILLO_TRACK_COUNT];
+ UINT mmtimer;
+} g;
+
+static void on_destroy(HWND hwnd) {
+ g.oscilloview = 0;
+ timeKillEvent(g.mmtimer);
+}
+
+static void CALLBACK mmtimer_cb(UINT timerid, UINT msg,
+ DWORD_PTR userptr,
+ DWORD_PTR dw1, DWORD_PTR dw2) {
+ PostMessage(g.oscilloview, WM_USER, 0, 0);
+}
+
+static bool on_create(HWND hwnd, const CREATESTRUCT *cs) {
+ ShowWindow(hwnd, SW_SHOW);
+ //SetTimer(hwnd, TIMER_UPDATE, 16, 0);
+ g.mmtimer = timeSetEvent(16, 16, mmtimer_cb, 0, TIME_PERIODIC);
+ DragAcceptFiles(hwnd, TRUE);
+ return true;
+}
+
+static void draw_track(HDC dc,
+ int x, int y, int w, int h,
+ const struct oscillodata *data) {
+ int start = OSCILLO_SAMPLE_COUNT - VIEW_SAMPLES;
+ start -= (data->offset >> OSCILLO_OFFSET_SHIFT);
+ if (start < 0) start = 0;
+ MoveToEx(dc, x, y + h/2.0 - (data->buf[start] / 16384.0) * h/2, 0);
+ for (int i = 0; i < (VIEW_SAMPLES / VIEW_SKIP); i++) {
+ LineTo(dc, (double)x + ((i)*w)/(VIEW_SAMPLES / VIEW_SKIP), y + h/2.0 - (data->buf[start + i*VIEW_SKIP] / 16384.0) * h/2);
+ }
+}
+
+static void on_paint(HWND hwnd) {
+ RECT cr;
+ GetClientRect(hwnd, &cr);
+ PAINTSTRUCT ps;
+ HDC dc = BeginPaint(hwnd, &ps);
+ HDC mdc = CreateCompatibleDC(dc);
+ HBITMAP bitmap = CreateCompatibleBitmap(dc, cr.right, cr.bottom);
+ SelectObject(mdc, bitmap);
+
+ FillRect(mdc, &cr, GetStockObject(BLACK_BRUSH));
+ SelectObject(mdc, GetStockObject(WHITE_PEN));
+ int width = cr.right / 3;
+ int height = cr.bottom / 3;
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ draw_track(mdc, x*width, y*height, width, height, &g.oscillodata[x*3+y]);
+ }
+ }
+
+ BitBlt(dc, 0, 0, cr.right, cr.bottom, mdc, 0, 0, SRCCOPY);
+ SelectObject(mdc, 0);
+ DeleteObject(bitmap);
+ DeleteDC(mdc);
+ EndPaint(hwnd, &ps);
+}
+
+static LRESULT CALLBACK wndproc(
+ HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
+) {
+ switch (msg) {
+ HANDLE_MSG(hwnd, WM_DESTROY, on_destroy);
+ HANDLE_MSG(hwnd, WM_CREATE, on_create);
+ //HANDLE_MSG(hwnd, WM_TIMER, on_timer);
+ HANDLE_MSG(hwnd, WM_PAINT, on_paint);
+ case WM_ERASEBKGND:
+ return 1;
+ case WM_USER:
+ if (!atomic_flag_test_and_set_explicit(
+ &oscilloview_g.flag, memory_order_acquire)) {
+ memcpy(g.oscillodata,
+ oscilloview_g.oscillodata,
+ sizeof(oscilloview_g.oscillodata));
+ atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);
+ }
+ InvalidateRect(hwnd, 0, FALSE);
+ return 0;
+ case WM_DROPFILES:
+ return SendMessage(g.parent, msg, wParam, lParam);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void show_oscilloview(HINSTANCE hinst, HWND parent) {
+ g.hinst = hinst;
+ g.parent = parent;
+ if (!g.oscilloview) {
+ if (!g.oscilloview_class) {
+ WNDCLASS wc = {0};
+ wc.style = 0;
+ wc.lpfnWndProc = wndproc;
+ wc.hInstance = g.hinst;
+ wc.hIcon = LoadIcon(g.hinst, MAKEINTRESOURCE(1));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ wc.lpszClassName = L"myon_fmplayer_ym2608_oscilloviewer";
+ g.oscilloview_class = RegisterClass(&wc);
+ }
+ if (!g.oscilloview_class) {
+ MessageBox(parent, L"Cannot register oscilloviewer class", L"Error", MB_ICONSTOP);
+ return;
+ }
+ g.oscilloview = CreateWindowEx(0,
+ MAKEINTATOM(g.oscilloview_class),
+ L"FMPlayer Oscilloview",
+ WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_SIZEBOX | WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ parent, 0, g.hinst, 0);
+ } else {
+ SetForegroundWindow(g.oscilloview);
+ }
+}
diff --git a/win32/oscilloview.h b/win32/oscilloview.h
new file mode 100644
index 0000000..8849830
--- /dev/null
+++ b/win32/oscilloview.h
@@ -0,0 +1,19 @@
+#ifndef MYON_FMPLAYER_WIN32_OSCILLOVIEW_H_INCLUDED
+#define MYON_FMPLAYER_WIN32_OSCILLOVIEW_H_INCLUDED
+
+#include "libopna/opna.h"
+#include "oscillo/oscillo.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdatomic.h>
+
+extern struct oscilloview {
+ atomic_flag flag;
+ struct oscillodata oscillodata[LIBOPNA_OSCILLO_TRACK_COUNT];
+} oscilloview_g;
+
+void show_oscilloview(HINSTANCE hinst, HWND parent);
+
+#endif // MYON_FMPLAYER_WIN32_OSCILLOVIEW_H_INCLUDED
+