aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/fmplayer.mak3
-rw-r--r--win32/main.c219
-rw-r--r--win32/toneview.c218
-rw-r--r--win32/toneview.h16
-rw-r--r--win32/x86/Makefile1
5 files changed, 424 insertions, 33 deletions
diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak
index 11f98f2..c71ef6a 100644
--- a/win32/fmplayer.mak
+++ b/win32/fmplayer.mak
@@ -20,7 +20,9 @@ LIBOPNA_OBJS=opna \
FMDSP_OBJS=fmdsp \
font_rom \
font_fmdsp_small
+TONEDATA_OBJS=tonedata
OBJBASE=main \
+ toneview \
soundout \
dsoundout \
waveout \
@@ -29,6 +31,7 @@ OBJBASE=main \
guid \
$(FMDRIVER_OBJS) \
$(LIBOPNA_OBJS) \
+ $(TONEDATA_OBJS) \
$(FMDSP_OBJS)
RESBASE=lnf
LIBBASE=user32 \
diff --git a/win32/main.c b/win32/main.c
index 16d2f3e..9cef778 100644
--- a/win32/main.c
+++ b/win32/main.c
@@ -12,10 +12,14 @@
#include "fmdsp/fmdsp.h"
#include "soundout.h"
#include "winfont.h"
+#include "version.h"
+#include "toneview.h"
enum {
ID_OPENFILE = 0x10,
ID_PAUSE,
+ ID_2X,
+ ID_TONEVIEW,
};
#define FMPLAYER_CLASSNAME L"myon_fmplayer_ym2608_win32"
@@ -55,10 +59,15 @@ static struct {
uint8_t opna_adpcm_ram[OPNA_ADPCM_RAM_SIZE];
void *ppz8_buf;
bool paused;
+ HWND mainwnd;
+ WNDPROC btn_defproc;
HWND driverinfo;
+ HWND button_2x;
const wchar_t *lastopenpath;
+ bool fmdsp_2x;
} g;
+HWND g_currentdlg;
static void opna_int_cb(void *userptr) {
struct fmdriver_work *work = (struct fmdriver_work *)userptr;
@@ -93,6 +102,11 @@ static void sound_cb(void *p, int16_t *buf, unsigned frames) {
struct opna_timer *timer = (struct opna_timer *)p;
ZeroMemory(buf, sizeof(int16_t)*frames*2);
opna_timer_mix(timer, buf, frames);
+ if (!atomic_flag_test_and_set_explicit(
+ &toneview_g.flag, memory_order_acquire)) {
+ tonedata_from_opna(&toneview_g.tonedata, &g.opna);
+ atomic_flag_clear_explicit(&toneview_g.flag, memory_order_release);
+ }
}
static void on_timer(HWND hwnd, UINT id) {
@@ -302,7 +316,9 @@ static void openfile(HWND hwnd, const wchar_t *path) {
g.driver = driver;
if (g.data) HeapFree(g.heap, 0, g.data);
g.data = data;
+ unsigned mask = opna_get_mask(&g.opna);
opna_reset(&g.opna);
+ opna_set_mask(&g.opna, mask);
if (g.drum_rom) opna_drum_set_rom(&g.opna.drum, g.drum_rom);
opna_adpcm_set_ram_256k(&g.opna.adpcm, g.opna_adpcm_ram);
opna_timer_reset(&g.opna_timer, &g.opna);
@@ -314,6 +330,7 @@ static void openfile(HWND hwnd, const wchar_t *path) {
g.work.opna = &g.opna_timer;
g.work.ppz8 = &g.ppz8;
g.work.ppz8_functbl = &ppz8_functbl;
+ WideCharToMultiByte(932, WC_NO_BEST_FIT_CHARS, path, -1, g.work.filename, sizeof(g.work.filename), 0, 0);
opna_timer_set_int_callback(&g.opna_timer, opna_int_cb, &g.work);
opna_timer_set_mix_callback(&g.opna_timer, opna_mix_cb, &g.ppz8);
if (driver_type == DRIVER_PMD) {
@@ -430,6 +447,118 @@ static void on_dropfiles(HWND hwnd, HDROP hdrop) {
}
#endif // ENABLE_WM_DROPFILES
+static void mask_set(unsigned mask, bool shift) {
+ if (shift) {
+ opna_set_mask(&g.opna, ~mask);
+ } else {
+ opna_set_mask(&g.opna, opna_get_mask(&g.opna) ^ mask);
+ }
+}
+
+static void toggle_2x(HWND hwnd) {
+ g.fmdsp_2x ^= 1;
+ RECT wr;
+ wr.left = 0;
+ wr.right = 640;
+ wr.top = 0;
+ wr.bottom = 480;
+ if (g.fmdsp_2x) {
+ wr.right = 1280;
+ wr.bottom = 880;
+ }
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ DWORD exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ AdjustWindowRectEx(&wr, style, 0, exstyle);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
+ SWP_NOZORDER | SWP_NOMOVE);
+}
+
+static bool proc_key(UINT vk, bool down, int repeat) {
+ if (down) {
+ if (VK_F1 <= vk && vk <= VK_F12) {
+ if (GetKeyState(VK_CONTROL) & 0x8000U) {
+ fmdsp_palette_set(&g.fmdsp, vk - VK_F1);
+ return true;
+ } else {
+ switch (vk) {
+ case VK_F6:
+ if (g.lastopenpath) {
+ openfile(g.mainwnd, g.lastopenpath);
+ }
+ return true;
+ case VK_F7:
+ if (g.sound) {
+ g.paused = !g.paused;
+ g.sound->pause(g.sound, g.paused);
+ }
+ return true;
+ case VK_F11:
+ fmdsp_dispstyle_set(&g.fmdsp, (g.fmdsp.style+1) % FMDSP_DISPSTYLE_CNT);
+ return true;
+ case VK_F12:
+ toggle_2x(g.mainwnd);
+ }
+ }
+ } else {
+ bool shift = GetKeyState(VK_SHIFT) & 0x8000U;
+ switch (vk) {
+ case '1':
+ mask_set(LIBOPNA_CHAN_FM_1, shift);
+ return true;
+ case '2':
+ mask_set(LIBOPNA_CHAN_FM_2, shift);
+ return true;
+ case '3':
+ mask_set(LIBOPNA_CHAN_FM_3, shift);
+ return true;
+ case '4':
+ mask_set(LIBOPNA_CHAN_FM_4, shift);
+ return true;
+ case '5':
+ mask_set(LIBOPNA_CHAN_FM_5, shift);
+ return true;
+ case '6':
+ mask_set(LIBOPNA_CHAN_FM_6, shift);
+ return true;
+ case '7':
+ mask_set(LIBOPNA_CHAN_SSG_1, shift);
+ return true;
+ case '8':
+ mask_set(LIBOPNA_CHAN_SSG_2, shift);
+ return true;
+ case '9':
+ mask_set(LIBOPNA_CHAN_SSG_3, shift);
+ return true;
+ case '0':
+ mask_set(LIBOPNA_CHAN_DRUM_ALL, shift);
+ return true;
+ case VK_OEM_MINUS:
+ mask_set(LIBOPNA_CHAN_ADPCM, shift);
+ return true;
+ case VK_OEM_PLUS:
+ opna_set_mask(&g.opna, ~opna_get_mask(&g.opna));
+ return true;
+ case VK_OEM_5:
+ opna_set_mask(&g.opna, 0);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static LRESULT CALLBACK btn_wndproc(
+ HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
+) {
+ switch (msg) {
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ if (proc_key((UINT)wParam, msg == WM_KEYDOWN, (int)(short)LOWORD(lParam))) return 0;
+ break;
+ }
+ return CallWindowProc(g.btn_defproc, hwnd, msg, wParam, lParam);
+}
+
static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
(void)cs;
HWND button = CreateWindowEx(
@@ -459,6 +588,29 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
100, 25,
hwnd, 0, g.hinst, 0
);
+ g.button_2x = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"2&x",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
+ 215, 10,
+ 30, 25,
+ hwnd, (HMENU)ID_2X, g.hinst, 0
+ );
+ HWND button_toneview = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"Tone &viewer",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD,
+ 250, 10,
+ 100, 25,
+ hwnd, (HMENU)ID_TONEVIEW, g.hinst, 0
+ );
+ g.btn_defproc = (WNDPROC)GetWindowLongPtr(button, GWLP_WNDPROC);
+ SetWindowLongPtr(button, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(pbutton, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(g.button_2x, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(button_toneview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
@@ -466,6 +618,8 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
SetWindowFont(button, font, TRUE);
SetWindowFont(pbutton, font, TRUE);
SetWindowFont(g.driverinfo, font, TRUE);
+ SetWindowFont(g.button_2x, font, TRUE);
+ SetWindowFont(button_toneview, font, TRUE);
loadrom();
loadfont();
fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0);
@@ -489,6 +643,14 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
g.paused = !g.paused;
g.sound->pause(g.sound, g.paused);
}
+ break;
+ case ID_2X:
+ toggle_2x(hwnd);
+ Button_SetCheck(g.button_2x, g.fmdsp_2x);
+ break;
+ case ID_TONEVIEW:
+ show_toneview(g.hinst, hwnd);
+ break;
}
}
@@ -531,7 +693,11 @@ static void on_paint(HWND hwnd) {
g.vram,
bi, DIB_RGB_COLORS);
SelectObject(mdc, bitmap);
- BitBlt(dc, 0, 80, 640, 400, mdc, 0, 0, SRCCOPY);
+ if (g.fmdsp_2x) {
+ StretchBlt(dc, 0, 80, 1280, 800, mdc, 0, 0, 640, 400, SRCCOPY);
+ } else {
+ BitBlt(dc, 0, 80, 640, 400, mdc, 0, 0, SRCCOPY);
+ }
DeleteDC(mdc);
DeleteObject(bitmap);
EndPaint(hwnd, &ps);
@@ -559,36 +725,20 @@ static void on_syskey(HWND hwnd, UINT vk, BOOL down, int repeat, UINT scan) {
}
static void on_key(HWND hwnd, UINT vk, BOOL down, int repeat, UINT scan) {
- if (down) {
- if (VK_F1 <= vk && vk <= VK_F12) {
- if (GetKeyState(VK_CONTROL) & 0x8000U) {
- fmdsp_palette_set(&g.fmdsp, vk - VK_F1);
- return;
- } else {
- switch (vk) {
- case VK_F6:
- if (g.lastopenpath) {
- openfile(hwnd, g.lastopenpath);
- }
- break;
- case VK_F7:
- if (g.sound) {
- g.paused = !g.paused;
- g.sound->pause(g.sound, g.paused);
- }
- break;
- case VK_F11:
- fmdsp_dispstyle_set(&g.fmdsp, (g.fmdsp.style+1) % FMDSP_DISPSTYLE_CNT);
- break;
- }
- }
+ if (!proc_key(vk, down, repeat)) {
+ if (down) {
+ FORWARD_WM_KEYDOWN(hwnd, vk, repeat, scan, DefWindowProc);
+ } else {
+ FORWARD_WM_KEYUP(hwnd, vk, repeat, scan, DefWindowProc);
}
- FORWARD_WM_KEYDOWN(hwnd, vk, repeat, scan, DefWindowProc);
- } else {
- FORWARD_WM_KEYUP(hwnd, vk, repeat, scan, DefWindowProc);
}
}
+static void on_activate(HWND hwnd, bool activate, HWND targetwnd, WINBOOL state) {
+ if (activate) g_currentdlg = hwnd;
+ else g_currentdlg = 0;
+}
+
static LRESULT CALLBACK wndproc(
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) {
@@ -607,6 +757,7 @@ static LRESULT CALLBACK wndproc(
HANDLE_MSG(hwnd, WM_KEYUP, on_key);
HANDLE_MSG(hwnd, WM_SYSKEYDOWN, on_syskey);
HANDLE_MSG(hwnd, WM_SYSKEYUP, on_syskey);
+ HANDLE_MSG(hwnd, WM_ACTIVATE, on_activate);
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
@@ -665,24 +816,26 @@ int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst,
wr.top = 0;
wr.bottom = 480;
AdjustWindowRectEx(&wr, style, 0, exStyle);
- HWND hwnd = CreateWindowEx(
+ g.mainwnd = CreateWindowEx(
exStyle,
- (wchar_t*)((uintptr_t)wcatom), L"FMPlayer/Win32",
+ (wchar_t*)((uintptr_t)wcatom), L"FMPlayer/Win32 v" FMPLAYER_VERSION_STR,
style,
CW_USEDEFAULT, CW_USEDEFAULT,
wr.right-wr.left, wr.bottom-wr.top,
0, 0, g.hinst, 0
);
- ShowWindow(hwnd, cmdshow);
+ ShowWindow(g.mainwnd, cmdshow);
if (argfile) {
- openfile(hwnd, argfile);
+ openfile(g.mainwnd, argfile);
}
MSG msg = {0};
while (GetMessage(&msg, 0, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ if (!g_currentdlg || !IsDialogMessage(g_currentdlg, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
}
return msg.wParam;
}
diff --git a/win32/toneview.c b/win32/toneview.c
new file mode 100644
index 0000000..a0a920a
--- /dev/null
+++ b/win32/toneview.c
@@ -0,0 +1,218 @@
+#include "toneview.h"
+#include <stdbool.h>
+#include <windowsx.h>
+
+enum {
+ TIMER_UPDATE = 1
+};
+
+enum {
+ ID_COPY0 = 0x10,
+ ID_COPY1,
+ ID_COPY2,
+ ID_COPY3,
+ ID_COPY4,
+ ID_COPY5,
+ ID_NORMALIZE,
+ ID_LIST,
+};
+
+struct toneview_g toneview_g = {
+ .flag = ATOMIC_FLAG_INIT
+};
+
+static struct {
+ HINSTANCE hinst;
+ HWND toneviewer;
+ HWND tonelabel[6];
+ ATOM toneviewer_class;
+ struct fmplayer_tonedata tonedata;
+ struct fmplayer_tonedata tonedata_n;
+ char strbuf[FMPLAYER_TONEDATA_STR_SIZE];
+ wchar_t strbuf_w[FMPLAYER_TONEDATA_STR_SIZE];
+ enum fmplayer_tonedata_format format;
+ bool normalize;
+ HFONT font;
+ HFONT font_mono;
+ HWND checkbox;
+ HWND formatlist;
+} g = {
+ .normalize = true
+};
+
+extern HWND g_currentdlg;
+
+static void on_destroy(HWND hwnd) {
+ for (int i = 0; i < 6; i++) {
+ DestroyWindow(g.tonelabel[i]);
+ }
+ DestroyWindow(g.checkbox);
+ DestroyWindow(g.formatlist);
+ g.toneviewer = 0;
+}
+
+enum {
+ LIST_W = 200,
+ NORMALIZE_X = 10 + LIST_W + 5,
+ NORMALIZE_W = 200,
+ TOP_H = 25,
+ TONELABEL_X = 10,
+ TONELABEL_H = 100,
+ TONELABEL_W = 300,
+ COPY_X = TONELABEL_X + TONELABEL_W + 5,
+ COPY_W = 100,
+ WIN_H = 10 + TOP_H + 5 + TONELABEL_H*6 + 5*5 + 10,
+ WIN_W = 10 + TONELABEL_W + 5 + COPY_W + 10,
+};
+
+static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
+ if (code == BN_CLICKED && ((ID_COPY0 <= id) && (id <= ID_COPY5))) {
+ int i = id - ID_COPY0;
+ HGLOBAL gmem = GlobalAlloc(GMEM_MOVEABLE, FMPLAYER_TONEDATA_STR_SIZE*sizeof(wchar_t));
+ if (!gmem) return;
+ wchar_t *buf = GlobalLock(gmem);
+ GetWindowText(g.tonelabel[i], buf, FMPLAYER_TONEDATA_STR_SIZE*sizeof(wchar_t));
+ GlobalUnlock(gmem);
+ if (!OpenClipboard(hwnd)) return;
+ EmptyClipboard();
+ SetClipboardData(CF_UNICODETEXT, gmem);
+ CloseClipboard();
+ } else if (id == ID_NORMALIZE && code == BN_CLICKED) {
+ g.normalize ^= 1;
+ Button_SetCheck(hwnd_c, g.normalize);
+ } else if (id == ID_LIST && code == CBN_SELCHANGE) {
+ g.format = ComboBox_GetCurSel(g.formatlist);
+ }
+}
+
+static bool on_create(HWND hwnd, const CREATESTRUCT *cs) {
+ RECT wr;
+ wr.left = 0;
+ wr.right = WIN_W;
+ wr.top = 0;
+ wr.bottom = WIN_H;
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ DWORD exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ AdjustWindowRectEx(&wr, style, 0, exstyle);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
+ SWP_NOZORDER | SWP_NOMOVE);
+
+ if (!g.font_mono) {
+ g.font_mono = CreateFont(
+ 16, 0, 0, 0,
+ FW_NORMAL, FALSE, FALSE, FALSE,
+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ CLEARTYPE_QUALITY, FIXED_PITCH, 0);
+ }
+
+ if (!g.font) {
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
+ g.font = CreateFontIndirect(&ncm.lfMessageFont);
+ }
+ g.formatlist = CreateWindowEx(0, L"combobox", 0,
+ WS_TABSTOP | WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST,
+ 10, 10, LIST_W, 100,
+ hwnd, (HMENU)ID_LIST, g.hinst, 0);
+ SetWindowFont(g.formatlist, g.font, TRUE);
+ ComboBox_AddString(g.formatlist, L"PMD");
+ ComboBox_AddString(g.formatlist, L"FMP");
+ ComboBox_SetCurSel(g.formatlist, 0);
+ g.checkbox = CreateWindowEx(0, L"button",
+ L"&Normalize",
+ WS_CHILD | WS_VISIBLE | BS_CHECKBOX | WS_TABSTOP,
+ NORMALIZE_X, 10, NORMALIZE_W, 25,
+ hwnd, (HMENU)ID_NORMALIZE, g.hinst, 0
+ );
+ Button_SetCheck(g.checkbox, g.normalize);
+ SetWindowFont(g.checkbox, g.font, TRUE);
+ for (int i = 0; i < 6; i++) {
+ g.tonelabel[i] = CreateWindowEx(WS_EX_CLIENTEDGE, L"static",
+ L"@ 0\n123 123",
+ WS_VISIBLE | WS_CHILD,
+ 10, 40 + (TONELABEL_H+5)*i, TONELABEL_W, TONELABEL_H,
+ hwnd, 0, g.hinst, 0);
+ SetWindowFont(g.tonelabel[i], g.font_mono, TRUE);
+ wchar_t text[] = L"Copy (& )";
+ text[7] = L'1' + i;
+ HWND copybutton = CreateWindowEx(0, L"button",
+ text,
+ WS_VISIBLE | WS_CHILD | WS_TABSTOP,
+ COPY_X, 40 + (TONELABEL_H+5)*i, 100, TONELABEL_H,
+ hwnd, (HMENU)(ID_COPY0+i), g.hinst, 0);
+ SetWindowFont(copybutton, g.font, TRUE);
+ }
+ ShowWindow(hwnd, SW_SHOW);
+ SetTimer(hwnd, TIMER_UPDATE, 16, 0);
+ return true;
+}
+
+static void on_timer(HWND hwnd, UINT id) {
+ if (id == TIMER_UPDATE) {
+ if (!atomic_flag_test_and_set_explicit(
+ &toneview_g.flag, memory_order_acquire)) {
+ g.tonedata = toneview_g.tonedata;
+ atomic_flag_clear_explicit(&toneview_g.flag, memory_order_release);
+ }
+ g.tonedata_n = g.tonedata;
+ for (int c = 0; c < 6; c++) {
+ if (g.normalize) {
+ tonedata_ch_normalize_tl(&g.tonedata_n.ch[c]);
+ }
+ tonedata_ch_string(g.format, g.strbuf, &g.tonedata_n.ch[c], 0);
+ for (int i = 0; i < FMPLAYER_TONEDATA_STR_SIZE; i++) {
+ g.strbuf_w[i] = g.strbuf[i];
+ }
+ // RedrawWindow(g.tonelabel[c], 0, 0, RDW_ERASE);
+ SetWindowText(g.tonelabel[c], g.strbuf_w);
+ }
+ }
+}
+
+static void on_activate(HWND hwnd, bool activate, HWND targetwnd, WINBOOL state) {
+ if (activate) g_currentdlg = hwnd;
+ else g_currentdlg = 0;
+}
+
+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_COMMAND, on_command);
+ HANDLE_MSG(hwnd, WM_ACTIVATE, on_activate);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void show_toneview(HINSTANCE hinst, HWND parent) {
+ g.hinst = hinst;
+ if (!g.toneviewer) {
+ if (!g.toneviewer_class) {
+ WNDCLASS wc = {0};
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = wndproc;
+ wc.hInstance = 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_toneviewer";
+ g.toneviewer_class = RegisterClass(&wc);
+ }
+ if (!g.toneviewer_class) {
+ MessageBox(parent, L"Cannot register class", L"Error", MB_ICONSTOP);
+ return;
+ }
+ g.toneviewer = CreateWindowEx(0,
+ MAKEINTATOM(g.toneviewer_class),
+ L"FMPlayer Tone Viewer",
+ WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ parent, 0, g.hinst, 0);
+ } else {
+ SetForegroundWindow(g.toneviewer);
+ }
+}
diff --git a/win32/toneview.h b/win32/toneview.h
new file mode 100644
index 0000000..32f402b
--- /dev/null
+++ b/win32/toneview.h
@@ -0,0 +1,16 @@
+#ifndef MYON_FMPLAYER_WIN32_TONEVIEW_H_INCLUDED
+#define MYON_FMPLAYER_WIN32_TONEVIEW_H_INCLUDED
+
+#include "tonedata/tonedata.h"
+#include <stdatomic.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+extern struct toneview_g {
+ struct fmplayer_tonedata tonedata;
+ atomic_flag flag;
+} toneview_g;
+
+void show_toneview(HINSTANCE hinst, HWND parent);
+
+#endif // MYON_FMPLAYER_WIN32_TONEVIEW_H_INCLUDED
diff --git a/win32/x86/Makefile b/win32/x86/Makefile
index 2f523a3..1a4c6d8 100644
--- a/win32/x86/Makefile
+++ b/win32/x86/Makefile
@@ -2,6 +2,7 @@ vpath %.c ../
vpath %.c ../../fmdriver
vpath %.c ../../libopna
vpath %.c ../../fmdsp
+vpath %.c ../../tonedata
vpath %.rc ..
include ../fmplayer.mak