aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-08-24 02:51:44 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-08-24 02:51:44 +0900
commitad839eb8338e8b84342bf36480fbf0a7a04fa2bd (patch)
treed700dd218c17050816fd5ae0e9a23671145e375f
parentc3347df0fbc1562d2a80f7ec9d99acbc0c6f2cbd (diff)
WIN32: add config dialog
-rw-r--r--win32/configdialog.c408
-rw-r--r--win32/configdialog.h20
-rw-r--r--win32/fmplayer.mak3
-rw-r--r--win32/main.c54
4 files changed, 482 insertions, 3 deletions
diff --git a/win32/configdialog.c b/win32/configdialog.c
new file mode 100644
index 0000000..82ca5b5
--- /dev/null
+++ b/win32/configdialog.c
@@ -0,0 +1,408 @@
+#include "configdialog.h"
+#include <windowsx.h>
+#include <commctrl.h>
+#include <math.h>
+#include <wchar.h>
+#include <stdlib.h>
+
+static double mix_to_db(uint32_t mix) {
+ return 20.0 * log10((double)mix / 0x10000);
+}
+
+static uint32_t db_to_mix(double db) {
+ return round(pow(10.0, db / 20.0) * 0x10000);
+}
+
+static struct {
+ HINSTANCE hinst;
+ HWND configwnd;
+ ATOM config_class;
+ HFONT font;
+ void (*closecb)(void *);
+ void *closecbptr;
+ void (*changecb)(void *);
+ void *changecbptr;
+ HWND group_fm, group_ssg, group_ppz8;
+ HWND check_fm_hires_sin;
+ HWND check_fm_hires_env;
+ HWND radio_ssg_opna;
+ HWND radio_ssg_ymf288;
+ HWND static_volume_offset, static_volume_info;
+ HWND edit_ssg_mix;
+ HWND radio_ppz8_none, radio_ppz8_linear, radio_ppz8_sinc;
+ HWND updown_ssg_mix;
+ WNDPROC groupbox_defproc;
+ bool edit_ssg_mix_set;
+ double ssg_mix_db;
+} g;
+
+enum {
+ WIN_W = 500,
+ WIN_H = 370,
+ GROUP_X = 5,
+ GROUP_FM_Y = 5,
+ GROUP_W = 490,
+ GROUP_FM_H = 75,
+ BOX_X = 15,
+ CHECK_FM_HIRES_SIN_Y = GROUP_FM_Y + 20,
+ BOX_W = 380,
+ CHECK_H = 25,
+ CHECK_FM_HIRES_ENV_Y = CHECK_FM_HIRES_SIN_Y + CHECK_H,
+ GROUP_SSG_Y = GROUP_FM_Y+GROUP_FM_H+5,
+ GROUP_SSG_H = 170,
+ RADIO_SSG_OPNA_Y = GROUP_SSG_Y + 20,
+ STATIC_VOLUME_OFFSET_X = 25,
+ STATIC_VOLUME_OFFSET_Y = RADIO_SSG_OPNA_Y + CHECK_H + 5,
+ STATIC_VOLUME_OFFSET_W = 110,
+ STATIC_VOLUME_INFO_X = 35,
+ STATIC_VOLUME_INFO_Y = STATIC_VOLUME_OFFSET_Y + CHECK_H + 5,
+ EDIT_SSG_MIX_X = 150,
+ EDIT_SSG_MIX_Y = STATIC_VOLUME_OFFSET_Y - 5,
+ EDIT_SSG_MIX_W = 100,
+ EDIT_SSG_MIX_H = 25,
+ RADIO_SSG_YMF288_Y = STATIC_VOLUME_INFO_Y + (EDIT_SSG_MIX_H+5)*2,
+ GROUP_PPZ8_Y = GROUP_SSG_Y+GROUP_SSG_H+5,
+ GROUP_PPZ8_H = 100,
+ RADIO_PPZ8_NONE_Y = GROUP_PPZ8_Y + 20,
+ RADIO_PPZ8_LINEAR_Y = RADIO_PPZ8_NONE_Y + CHECK_H,
+ RADIO_PPZ8_SINC_Y = RADIO_PPZ8_LINEAR_Y + CHECK_H,
+};
+
+enum {
+ ID_CHECK_FM_HIRES_SIN = 0x10,
+ ID_CHECK_FM_HIRES_ENV,
+ ID_RADIO_SSG_OPNA,
+ ID_RADIO_SSG_YMF288,
+ ID_EDIT_SSG_MIX,
+ ID_RADIO_PPZ8_NONE,
+ ID_RADIO_PPZ8_LINEAR,
+ ID_RADIO_PPZ8_SINC,
+ ID_UPDOWN_SSG_MIX,
+};
+
+struct fmplayer_config fmplayer_config = {
+ .ssg_mix = 0x10000,
+ .ppz8_interp = PPZ8_INTERP_SINC,
+};
+
+extern HWND g_currentdlg;
+
+static bool groupbox_on_erasebkgnd(HWND hwnd, HDC hdc) {
+ RECT cr;
+ GetClientRect(hwnd, &cr);
+ FillRect(hdc, &cr, (HBRUSH)(COLOR_BTNFACE+1));
+ return true;
+}
+
+static LRESULT groupbox_wndproc(
+ HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
+) {
+ switch (msg) {
+ HANDLE_MSG(hwnd, WM_ERASEBKGND, groupbox_on_erasebkgnd);
+ }
+ return CallWindowProc(g.groupbox_defproc, hwnd, msg, wParam, lParam);
+}
+
+static void on_destroy(HWND hwnd) {
+ DestroyWindow(g.radio_ppz8_none);
+ DestroyWindow(g.radio_ppz8_linear);
+ DestroyWindow(g.radio_ppz8_sinc);
+ DestroyWindow(g.radio_ssg_ymf288);
+ DestroyWindow(g.updown_ssg_mix);
+ DestroyWindow(g.edit_ssg_mix);
+ DestroyWindow(g.static_volume_info);
+ DestroyWindow(g.static_volume_offset);
+ DestroyWindow(g.radio_ssg_opna);
+ DestroyWindow(g.check_fm_hires_sin);
+ DestroyWindow(g.check_fm_hires_env);
+ DestroyWindow(g.group_fm);
+ DestroyWindow(g.group_ssg);
+ DestroyWindow(g.group_ppz8);
+ g.configwnd = 0;
+ if (g.closecb) g.closecb(g.closecbptr);
+}
+
+static void update_ssg_mix(void) {
+ wchar_t buf[10];
+ swprintf(buf, sizeof(buf)/sizeof(buf[0]),
+ L"%2.2f", g.ssg_mix_db);
+ Edit_SetText(g.edit_ssg_mix, buf);
+}
+
+static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
+ switch (id) {
+ case ID_CHECK_FM_HIRES_SIN:
+ fmplayer_config.fm_hires_sin = Button_GetCheck(g.check_fm_hires_sin);
+ break;
+ case ID_CHECK_FM_HIRES_ENV:
+ fmplayer_config.fm_hires_env = Button_GetCheck(g.check_fm_hires_env);
+ break;
+ case ID_RADIO_SSG_OPNA:
+ Button_SetCheck(g.radio_ssg_opna, true);
+ Button_SetCheck(g.radio_ssg_ymf288, false);
+ fmplayer_config.ssg_ymf288 = false;
+ Edit_Enable(g.edit_ssg_mix, true);
+ EnableWindow(g.updown_ssg_mix, true);
+ break;
+ case ID_RADIO_SSG_YMF288:
+ Button_SetCheck(g.radio_ssg_opna, false);
+ Button_SetCheck(g.radio_ssg_ymf288, true);
+ fmplayer_config.ssg_ymf288 = true;
+ Edit_Enable(g.edit_ssg_mix, false);
+ EnableWindow(g.updown_ssg_mix, false);
+ break;
+ case ID_RADIO_PPZ8_NONE:
+ Button_SetCheck(g.radio_ppz8_none, true);
+ Button_SetCheck(g.radio_ppz8_linear, false);
+ Button_SetCheck(g.radio_ppz8_sinc, false);
+ fmplayer_config.ppz8_interp = PPZ8_INTERP_NONE;
+ break;
+ case ID_RADIO_PPZ8_LINEAR:
+ Button_SetCheck(g.radio_ppz8_none, false);
+ Button_SetCheck(g.radio_ppz8_linear, true);
+ Button_SetCheck(g.radio_ppz8_sinc, false);
+ fmplayer_config.ppz8_interp = PPZ8_INTERP_LINEAR;
+ break;
+ case ID_RADIO_PPZ8_SINC:
+ Button_SetCheck(g.radio_ppz8_none, false);
+ Button_SetCheck(g.radio_ppz8_linear, false);
+ Button_SetCheck(g.radio_ppz8_sinc, true);
+ fmplayer_config.ppz8_interp = PPZ8_INTERP_SINC;
+ break;
+ case ID_EDIT_SSG_MIX:
+ if (code == EN_KILLFOCUS) {
+ int len = Edit_GetTextLength(g.edit_ssg_mix) + 1;
+ if (len) {
+ wchar_t *buf = malloc(len * sizeof(buf[0]));
+ if (buf) {
+ Edit_GetText(g.edit_ssg_mix, buf, len);
+ wchar_t *endp;
+ g.ssg_mix_db = wcstod(buf, &endp);
+ if (buf == endp || *endp) {
+ g.ssg_mix_db = wcstol(buf, &endp, 0);
+ }
+ if (g.ssg_mix_db < -18.0) g.ssg_mix_db = -18.0;
+ if (g.ssg_mix_db > 18.0) g.ssg_mix_db = 18.0;
+ update_ssg_mix();
+ fmplayer_config.ssg_mix = db_to_mix(g.ssg_mix_db);
+ free(buf);
+ }
+ }
+ }
+ break;
+ }
+ g.changecb(g.changecbptr);
+}
+
+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) {
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
+ g.font = CreateFontIndirect(&ncm.lfMessageFont);
+ }
+
+ g.group_fm = CreateWindowEx(
+ 0, L"button", L"FM",
+ WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
+ GROUP_X, GROUP_FM_Y,
+ GROUP_W, GROUP_FM_H,
+ hwnd, 0, g.hinst, 0);
+ g.group_ssg = CreateWindowEx(
+ 0, L"button", L"SSG (249600 Hz to 55467 Hz resampling + DC output)",
+ WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
+ GROUP_X, GROUP_SSG_Y,
+ GROUP_W, GROUP_SSG_H,
+ hwnd, 0, g.hinst, 0);
+ g.group_ppz8 = CreateWindowEx(
+ 0, L"button", L"PPZ8 interpolation",
+ WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
+ GROUP_X, GROUP_PPZ8_Y,
+ GROUP_W, GROUP_PPZ8_H,
+ hwnd, 0, g.hinst, 0);
+ g.check_fm_hires_sin = CreateWindowEx(
+ 0, L"button", L"Enable higher resolution sine table",
+ WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP,
+ BOX_X, CHECK_FM_HIRES_SIN_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_CHECK_FM_HIRES_SIN, g.hinst, 0);
+ g.check_fm_hires_env = CreateWindowEx(
+ 0, L"button", L"Enable higher resolution envelope",
+ WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP,
+ BOX_X, CHECK_FM_HIRES_ENV_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_CHECK_FM_HIRES_ENV, g.hinst, 0);
+ g.radio_ssg_opna = CreateWindowEx(
+ 0, L"button", L"OPNA analog circuit simulation (sinc + HPF)",
+ WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON | WS_TABSTOP | WS_GROUP,
+ BOX_X, RADIO_SSG_OPNA_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_RADIO_SSG_OPNA, g.hinst, 0);
+ g.radio_ssg_ymf288 = CreateWindowEx(
+ 0, L"button", L"Bit perfect with OPN3-L aka YMF288 (average of nearest 4.5 samples)",
+ WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
+ BOX_X, RADIO_SSG_YMF288_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_RADIO_SSG_YMF288, g.hinst, 0);
+ g.static_volume_offset = CreateWindowEx(
+ 0, L"static", L"Volume offset (dB):",
+ WS_CHILD | WS_VISIBLE,
+ STATIC_VOLUME_OFFSET_X, STATIC_VOLUME_OFFSET_Y,
+ STATIC_VOLUME_OFFSET_W, CHECK_H,
+ hwnd, 0, g.hinst, 0);
+ g.static_volume_info = CreateWindowEx(
+ 0, L"static", L"PC-9801-86 / YMF288: 0.0dB (reference)\nPC-9801-26 / Speakboard: 1.6dB (not verified)",
+ WS_CHILD | WS_VISIBLE,
+ STATIC_VOLUME_INFO_X, STATIC_VOLUME_INFO_Y,
+ BOX_W, CHECK_H*2,
+ hwnd, 0, g.hinst, 0);
+ g.edit_ssg_mix = CreateWindowEx(
+ WS_EX_CLIENTEDGE, L"edit", L"",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP,
+ EDIT_SSG_MIX_X, EDIT_SSG_MIX_Y,
+ EDIT_SSG_MIX_W, EDIT_SSG_MIX_H,
+ hwnd, (HMENU)ID_EDIT_SSG_MIX, g.hinst, 0);
+ g.updown_ssg_mix = CreateWindowEx(
+ 0, UPDOWN_CLASS, L"",
+ WS_CHILD | WS_VISIBLE | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK,
+ 0, 0, 0, 0,
+ hwnd, (HMENU)ID_UPDOWN_SSG_MIX, g.hinst, 0);
+ g.radio_ppz8_none = CreateWindowEx(
+ 0, L"button", L"Nearest neighbor (ppz8.com equivalent)",
+ WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON | WS_TABSTOP | WS_GROUP,
+ BOX_X, RADIO_PPZ8_NONE_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_RADIO_PPZ8_NONE, g.hinst, 0);
+ g.radio_ppz8_linear = CreateWindowEx(
+ 0, L"button", L"Linear",
+ WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
+ BOX_X, RADIO_PPZ8_LINEAR_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_RADIO_PPZ8_LINEAR, g.hinst, 0);
+ g.radio_ppz8_sinc = CreateWindowEx(
+ 0, L"button", L"Sinc (best quality)",
+ WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
+ BOX_X, RADIO_PPZ8_SINC_Y,
+ BOX_W, CHECK_H,
+ hwnd, (HMENU)ID_RADIO_PPZ8_SINC, g.hinst, 0);
+ g.groupbox_defproc = (WNDPROC)GetWindowLongPtr(g.group_fm, GWLP_WNDPROC);
+ SetWindowLongPtr(g.group_fm, GWLP_WNDPROC, (intptr_t)groupbox_wndproc);
+ SetWindowLongPtr(g.group_ssg, GWLP_WNDPROC, (intptr_t)groupbox_wndproc);
+ SetWindowLongPtr(g.group_ppz8, GWLP_WNDPROC, (intptr_t)groupbox_wndproc);
+ SetWindowFont(g.group_fm, g.font, TRUE);
+ SetWindowFont(g.group_ssg, g.font, TRUE);
+ SetWindowFont(g.group_ppz8, g.font, TRUE);
+ SetWindowFont(g.check_fm_hires_sin, g.font, TRUE);
+ SetWindowFont(g.check_fm_hires_env, g.font, TRUE);
+ SetWindowFont(g.radio_ssg_opna, g.font, TRUE);
+ SetWindowFont(g.radio_ssg_ymf288, g.font, TRUE);
+ SetWindowFont(g.static_volume_offset, g.font, TRUE);
+ SetWindowFont(g.static_volume_info, g.font, TRUE);
+ SetWindowFont(g.edit_ssg_mix, g.font, TRUE);
+ SetWindowFont(g.radio_ppz8_none, g.font, TRUE);
+ SetWindowFont(g.radio_ppz8_linear, g.font, TRUE);
+ SetWindowFont(g.radio_ppz8_sinc, g.font, TRUE);
+
+ if (fmplayer_config.fm_hires_sin) Button_SetCheck(g.check_fm_hires_sin, true);
+ if (fmplayer_config.fm_hires_env) Button_SetCheck(g.check_fm_hires_env, true);
+
+ Button_SetCheck(fmplayer_config.ssg_ymf288 ? g.radio_ssg_ymf288 : g.radio_ssg_opna, true);
+ switch (fmplayer_config.ppz8_interp) {
+ case PPZ8_INTERP_LINEAR:
+ Button_SetCheck(g.radio_ppz8_linear, true);
+ break;
+ case PPZ8_INTERP_SINC:
+ Button_SetCheck(g.radio_ppz8_sinc, true);
+ break;
+ default:
+ Button_SetCheck(g.radio_ppz8_none, true);
+ break;
+ }
+ g.ssg_mix_db = mix_to_db(fmplayer_config.ssg_mix);
+ update_ssg_mix();
+ Edit_Enable(g.edit_ssg_mix, !fmplayer_config.ssg_ymf288);
+ EnableWindow(g.updown_ssg_mix, !fmplayer_config.ssg_ymf288);
+ ShowWindow(hwnd, SW_SHOW);
+ return true;
+}
+
+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_COMMAND, on_command);
+ HANDLE_MSG(hwnd, WM_ACTIVATE, on_activate);
+ case WM_NOTIFY:
+ {
+ const NMHDR *hdr = (NMHDR *)lParam;
+ if (hdr->idFrom == ID_UPDOWN_SSG_MIX && hdr->code == UDN_DELTAPOS) {
+ const NMUPDOWN *udnhdr = (NMUPDOWN *)hdr;
+ g.ssg_mix_db -= udnhdr->iDelta * 0.1;
+ g.ssg_mix_db = round(g.ssg_mix_db * 10.0) / 10.0;
+ if (g.ssg_mix_db < -18.0) g.ssg_mix_db = -18.0;
+ if (g.ssg_mix_db > 18.0) g.ssg_mix_db = 18.0;
+ update_ssg_mix();
+ fmplayer_config.ssg_mix = db_to_mix(g.ssg_mix_db);
+ }
+ break;
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void configdialog_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *), void *closecbptr, void (*changecb)(void *), void *changecbptr) {
+ g.closecb = closecb;
+ g.closecbptr = closecbptr;
+ g.changecb = changecb;
+ g.changecbptr = changecbptr;
+ g.hinst = hinst;
+ if (!g.configwnd) {
+ if (!g.config_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_config";
+ g.config_class = RegisterClass(&wc);
+ }
+ if (!g.config_class) {
+ MessageBox(parent, L"Cannot register class", L"Error", MB_ICONSTOP);
+ return;
+ }
+ g.configwnd = CreateWindowEx(0,
+ MAKEINTATOM(g.config_class),
+ L"FMPlayer config",
+ WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ parent, 0, g.hinst, 0);
+ } else {
+ SetForegroundWindow(g.configwnd);
+ }
+}
+
+void configdialog_close(void) {
+ if (g.configwnd) {
+ g.closecb = 0;
+ DestroyWindow(g.configwnd);
+ }
+}
diff --git a/win32/configdialog.h b/win32/configdialog.h
new file mode 100644
index 0000000..fa9b60f
--- /dev/null
+++ b/win32/configdialog.h
@@ -0,0 +1,20 @@
+#ifndef MYON_FMPLAYER_WIN32_CONFIGDIALOG_H_INCLUDED
+#define MYON_FMPLAYER_WIN32_CONFIGDIALOG_H_INCLUDED
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdbool.h>
+#include "fmdriver/ppz8.h"
+
+extern struct fmplayer_config {
+ bool fm_hires_env;
+ bool fm_hires_sin;
+ bool ssg_ymf288;
+ uint32_t ssg_mix;
+ enum ppz8_interp ppz8_interp;
+} fmplayer_config;
+
+void configdialog_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *), void *closecbptr, void (*changecb)(void *), void *changecbptr);
+void configdialog_close(void);
+
+#endif // MYON_FMPLAYER_WIN32_CONFIGDIALOG_H_INCLUDED
diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak
index d62861c..122ec56 100644
--- a/win32/fmplayer.mak
+++ b/win32/fmplayer.mak
@@ -45,7 +45,8 @@ OBJBASE=main \
$(FMDRIVER_OBJS) \
$(LIBOPNA_OBJS) \
$(TONEDATA_OBJS) \
- $(FMDSP_OBJS)
+ $(FMDSP_OBJS) \
+ configdialog
RESBASE=lnf
LIBBASE=user32 \
kernel32 \
diff --git a/win32/main.c b/win32/main.c
index c1df7a7..3519d1b 100644
--- a/win32/main.c
+++ b/win32/main.c
@@ -23,6 +23,7 @@
#include "common/fmplayer_common.h"
#include "wavesave.h"
#include "fft/fft.h"
+#include "configdialog.h"
enum {
ID_OPENFILE = 0x10,
@@ -32,6 +33,7 @@ enum {
ID_OSCILLOVIEW,
ID_ABOUT,
ID_WAVESAVE,
+ ID_CONFIG,
};
#define FMPLAYER_CLASSNAME L"myon_fmplayer_ym2608_win32"
@@ -66,8 +68,8 @@ static struct {
bool paused;
HWND mainwnd;
WNDPROC btn_defproc;
- HWND button_2x, button_toneview, button_oscilloview, button_about;
- bool toneview_on, oscilloview_on, about_on;
+ HWND button_2x, button_toneview, button_oscilloview, button_about, button_config;
+ bool toneview_on, oscilloview_on, about_on, config_on;
const wchar_t *lastopenpath;
bool fmdsp_2x;
struct oscillodata oscillodata_audiothread[LIBOPNA_OSCILLO_TRACK_COUNT];
@@ -78,8 +80,10 @@ static struct {
atomic_flag at_fftdata_flag;
struct fmplayer_fft_data at_fftdata;
struct fmplayer_fft_input_data fftdata;
+ atomic_flag opna_flag;
} g = {
.at_fftdata_flag = ATOMIC_FLAG_INIT,
+ .opna_flag = ATOMIC_FLAG_INIT,
};
HWND g_currentdlg;
@@ -87,7 +91,9 @@ HWND g_currentdlg;
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);
+ while (atomic_flag_test_and_set_explicit(&g.opna_flag, memory_order_acquire));
opna_timer_mix_oscillo(timer, buf, frames, g.oscillodata_audiothread);
+ atomic_flag_clear_explicit(&g.opna_flag, memory_order_release);
if (!atomic_flag_test_and_set_explicit(
&toneview_g.flag, memory_order_acquire)) {
tonedata_from_opna(&toneview_g.tonedata, &g.opna);
@@ -170,6 +176,11 @@ static void openfile(HWND hwnd, const wchar_t *path) {
about_set_adpcmrom_loaded(true);
}
opna_set_mask(&g.opna, mask);
+ opna_ssg_set_mix(&g.opna.ssg, fmplayer_config.ssg_mix);
+ opna_ssg_set_ymf288(&g.opna.ssg, &g.opna.resampler, fmplayer_config.ssg_ymf288);
+ ppz8_set_interpolation(&g.ppz8, fmplayer_config.ppz8_interp);
+ opna_fm_set_hires_sin(&g.opna.fm, fmplayer_config.fm_hires_sin);
+ opna_fm_set_hires_env(&g.opna.fm, fmplayer_config.fm_hires_env);
WideCharToMultiByte(932, WC_NO_BEST_FIT_CHARS, path, -1, g.work.filename, sizeof(g.work.filename), 0, 0);
fmplayer_file_load(&g.work, g.fmfile, 1);
if (!g.sound) {
@@ -504,6 +515,15 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
50, 25,
hwnd, (HMENU)ID_ABOUT, g.hinst, 0
);
+ g.button_config = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"&Config...",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
+ 460, 10,
+ 100, 25,
+ hwnd, (HMENU)ID_CONFIG, 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);
@@ -512,6 +532,7 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
SetWindowLongPtr(g.button_toneview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(g.button_oscilloview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(g.button_about, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(g.button_config, GWLP_WNDPROC, (intptr_t)btn_wndproc);
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
@@ -523,6 +544,7 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
SetWindowFont(g.button_toneview, font, TRUE);
SetWindowFont(g.button_oscilloview, font, TRUE);
SetWindowFont(g.button_about, font, TRUE);
+ SetWindowFont(g.button_config, font, TRUE);
loadfont();
fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0);
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
@@ -552,6 +574,23 @@ static void about_close_cb(void *ptr) {
Button_SetCheck(g.button_about, false);
}
+static void configdialog_close_cb(void *ptr) {
+ (void)ptr;
+ g.config_on = false;
+ Button_SetCheck(g.button_config, false);
+}
+
+static void configdialog_change_cb(void *ptr) {
+ (void)ptr;
+ while (atomic_flag_test_and_set_explicit(&g.opna_flag, memory_order_acquire));
+ opna_ssg_set_mix(&g.opna.ssg, fmplayer_config.ssg_mix);
+ opna_ssg_set_ymf288(&g.opna.ssg, &g.opna.resampler, fmplayer_config.ssg_ymf288);
+ ppz8_set_interpolation(&g.ppz8, fmplayer_config.ppz8_interp);
+ opna_fm_set_hires_sin(&g.opna.fm, fmplayer_config.fm_hires_sin);
+ opna_fm_set_hires_env(&g.opna.fm, fmplayer_config.fm_hires_env);
+ atomic_flag_clear_explicit(&g.opna_flag, memory_order_release);
+}
+
static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
(void)code;
(void)hwnd_c;
@@ -613,6 +652,17 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
}
}
break;
+ case ID_CONFIG:
+ if (!g.config_on) {
+ g.config_on = true;
+ configdialog_open(g.hinst, hwnd, configdialog_close_cb, 0, configdialog_change_cb, 0);
+ Button_SetCheck(g.button_config, true);
+ } else {
+ g.config_on = false;
+ configdialog_close();
+ Button_SetCheck(g.button_config, false);
+ }
+ break;
}
}