aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakamichi Horikawa <takamichiho@gmail.com>2017-01-26 20:32:26 +0900
committerTakamichi Horikawa <takamichiho@gmail.com>2017-01-26 20:32:26 +0900
commitfc1ea6ee5b5135e70e1a0e9b2737f6189b740691 (patch)
tree53f206e2f77e3450f8c0def24c488ef19ac3a72d
parent49ecf760ec6e8b145850be6f3b13020502e10eb4 (diff)
refactor win32 sound output and improve stability under load
-rw-r--r--win32/dsoundout.c77
-rw-r--r--win32/dsoundout.h6
-rw-r--r--win32/main.c34
-rw-r--r--win32/soundout.c41
-rw-r--r--win32/soundout.h5
-rw-r--r--win32/waveout.c166
-rw-r--r--win32/waveout.h6
7 files changed, 212 insertions, 123 deletions
diff --git a/win32/dsoundout.c b/win32/dsoundout.c
index 0f7ebc4..2581c8a 100644
--- a/win32/dsoundout.c
+++ b/win32/dsoundout.c
@@ -3,6 +3,7 @@
#include <dsound.h>
struct dsound_state {
+ struct sound_state soundout;
IDirectSound8 *ds;
DWORD sectlen;
IDirectSoundBuffer *dsbuf;
@@ -69,7 +70,32 @@ static DWORD WINAPI bufupdatethread(LPVOID p) {
}
}
-struct dsound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
+static void dsound_pause(struct sound_state *state, int pause) {
+ struct dsound_state *dsound = (struct dsound_state *)state;
+ if (pause) {
+ dsound->playing = 0;
+ WaitForSingleObject(dsound->mtx_cbproc, INFINITE);
+ ReleaseMutex(dsound->mtx_cbproc);
+ } else {
+ dsound->playing = 1;
+ dsound->dsbuf->lpVtbl->Play(dsound->dsbuf, 0, 0, DSBPLAY_LOOPING);
+ }
+}
+
+static void dsound_free(struct sound_state *state) {
+ struct dsound_state *dsound = (struct dsound_state *)state;
+ dsound_pause(state, 1);
+ dsound->terminate = 1;
+ SetEvent(dsound->e_posnotf);
+ WaitForSingleObject(dsound->t_update, INFINITE);
+ CloseHandle(dsound->mtx_cbproc);
+ dsound->dsbuf->lpVtbl->Release(dsound->dsbuf);
+ dsound->ds->lpVtbl->Release(dsound->ds);
+ HeapFree(GetProcessHeap(), 0, dsound);
+}
+
+
+struct sound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
sound_callback cbfunc, void *userptr) {
HANDLE heap = GetProcessHeap();
struct dsound_state *dsound = HeapAlloc(heap, HEAP_ZERO_MEMORY,
@@ -87,7 +113,6 @@ struct dsound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
&IID_IDirectSound8,
(void **)&dsound->ds);
if (hr != S_OK) {
- MessageBoxW(hwnd, L"cannot create instance of DirectSound8", L"Error", MB_ICONSTOP);
goto err_dsound;
}
hr = dsound->ds->lpVtbl->Initialize(dsound->ds, 0);
@@ -127,15 +152,24 @@ struct dsound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
goto err_dsbuf;
}
- dsound->e_posnotf = CreateEventW(NULL, FALSE, FALSE, L"SNDNOTF");
+ dsound->mtx_cbproc = CreateMutexW(0, FALSE, 0);
+ if (!dsound->mtx_cbproc) {
+ goto err_dsnotf;
+ }
+ dsound->e_posnotf = CreateEventW(NULL, FALSE, FALSE, 0);
+ if (!dsound->e_posnotf) {
+ goto err_mtx;
+ }
dsound->t_update = CreateThread(NULL, 0, bufupdatethread, dsound, 0, NULL);
+ if (!dsound->t_update) {
+ goto err_event;
+ }
SetThreadPriority(dsound->t_update, THREAD_PRIORITY_HIGHEST);
dsound->sectlen = sectlen;
dsound->playing = 0;
dsound->terminate = 0;
dsound->cbfunc = cbfunc;
dsound->userptr = userptr;
- dsound->mtx_cbproc = CreateMutexW(0, FALSE, 0);
DSBPOSITIONNOTIFY posnotf[4] = {
@@ -146,7 +180,17 @@ struct dsound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
};
dsnotf->lpVtbl->SetNotificationPositions(dsnotf, 4, posnotf);
dsnotf->lpVtbl->Release(dsnotf);
- return dsound;
+ dsound->soundout.pause = dsound_pause;
+ dsound->soundout.free = dsound_free;
+ dsound->soundout.apiname = L"DirectSound";
+ return (struct sound_state *)dsound;
+
+err_event:
+ CloseHandle(dsound->e_posnotf);
+err_mtx:
+ CloseHandle(dsound->mtx_cbproc);
+err_dsnotf:
+ dsnotf->lpVtbl->Release(dsnotf);
err_dsbuf:
dsound->dsbuf->lpVtbl->Release(dsound->dsbuf);
err_ds:
@@ -156,26 +200,3 @@ err_dsound:
err:
return 0;
}
-
-void dsound_pause(struct dsound_state *dsound, int pause) {
- if (pause) {
- dsound->playing = 0;
- WaitForSingleObject(dsound->mtx_cbproc, INFINITE);
- ReleaseMutex(dsound->mtx_cbproc);
- } else {
- dsound->playing = 1;
- dsound->dsbuf->lpVtbl->Play(dsound->dsbuf, 0, 0, DSBPLAY_LOOPING);
- }
-}
-
-void dsound_delete(struct dsound_state *dsound) {
- if (!dsound) return;
- dsound_pause(dsound, 1);
- dsound->terminate = 1;
- SetEvent(dsound->e_posnotf);
- WaitForSingleObject(dsound->t_update, INFINITE);
- CloseHandle(dsound->mtx_cbproc);
- dsound->dsbuf->lpVtbl->Release(dsound->dsbuf);
- dsound->ds->lpVtbl->Release(dsound->ds);
- HeapFree(GetProcessHeap(), 0, dsound);
-}
diff --git a/win32/dsoundout.h b/win32/dsoundout.h
index 10482e6..0a96889 100644
--- a/win32/dsoundout.h
+++ b/win32/dsoundout.h
@@ -3,11 +3,7 @@
#include "soundout.h"
-struct dsound_state;
-
-struct dsound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
+struct sound_state *dsound_init(HWND hwnd, unsigned srate, unsigned sectlen,
sound_callback cbfunc, void *userptr);
-void dsound_delete(struct dsound_state *dsound);
-void dsound_pause(struct dsound_state *dsound, int pause);
#endif // MYON_DSOUNDOUT_H_INCLUDED
diff --git a/win32/main.c b/win32/main.c
index d4caf05..07ef1bd 100644
--- a/win32/main.c
+++ b/win32/main.c
@@ -14,13 +14,14 @@
enum {
ID_OPENFILE = 0x10,
- TIMER_FMDSP = 1,
+ ID_PAUSE,
};
#define FMPLAYER_CLASSNAME L"myon_fmplayer_ym2608_win32"
#define FMPLAYER_CDSTAG 0xFD809800UL
enum {
+ TIMER_FMDSP = 1,
SRATE = 55467,
SECTLEN = 4096,
PPZ8MIX = 0xa000,
@@ -46,6 +47,8 @@ static struct {
void *drum_rom;
uint8_t opna_adpcm_ram[OPNA_ADPCM_RAM_SIZE];
void *ppz8_buf;
+ bool paused;
+ HWND driverinfo;
} g;
@@ -292,10 +295,12 @@ static void openfile(HWND hwnd, const wchar_t *path) {
if (!g.sound) {
g.sound = sound_init(hwnd, SRATE, SECTLEN,
sound_cb, &g.opna_timer);
+ SetWindowText(g.driverinfo, g.sound->apiname);
}
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
if (!g.sound) goto err_fmp;
g.sound->pause(g.sound, 0);
+ g.paused = false;
CloseHandle(file);
return;
err_fmp:
@@ -393,11 +398,31 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
40, 25,
hwnd, (HMENU)ID_OPENFILE, g.hinst, 0
);
+ HWND pbutton = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"&Pause",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD,
+ 55, 10,
+ 50, 25,
+ hwnd, (HMENU)ID_PAUSE, g.hinst, 0
+ );
+ g.driverinfo = CreateWindowEx(
+ 0,
+ L"STATIC",
+ L"",
+ WS_VISIBLE | WS_CHILD,
+ 110, 15,
+ 100, 25,
+ hwnd, 0, g.hinst, 0
+ );
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
HFONT font = CreateFontIndirect(&ncm.lfMessageFont);
SetWindowFont(button, font, TRUE);
+ SetWindowFont(pbutton, font, TRUE);
+ SetWindowFont(g.driverinfo, font, TRUE);
loadrom();
loadfont();
fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0);
@@ -416,12 +441,17 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
case ID_OPENFILE:
openfiledialog(hwnd);
break;
+ case ID_PAUSE:
+ if (g.sound) {
+ g.paused = !g.paused;
+ g.sound->pause(g.sound, g.paused);
+ }
}
}
static void on_destroy(HWND hwnd) {
(void)hwnd;
- if (g.sound) g.sound->delete(g.sound);
+ if (g.sound) g.sound->free(g.sound);
if (g.fmp) HeapFree(g.heap, 0, g.fmp);
if (g.drum_rom) HeapFree(g.heap, 0, g.drum_rom);
if (g.ppz8_buf) HeapFree(g.heap, 0, g.ppz8_buf);
diff --git a/win32/soundout.c b/win32/soundout.c
index bb57bc1..7f04e16 100644
--- a/win32/soundout.c
+++ b/win32/soundout.c
@@ -2,43 +2,16 @@
#include "dsoundout.h"
#include "waveout.h"
-static void soundout_dsound_pause(struct sound_state *state, int pause) {
- dsound_pause((struct dsound_state *)state->driver_state, pause);
-}
-
-static void soundout_dsound_delete(struct sound_state *state) {
- dsound_delete((struct dsound_state *)state->driver_state);
- HeapFree(GetProcessHeap(), 0, state);
-}
-
-static void soundout_waveout_pause(struct sound_state *state, int pause) {
- waveout_pause((struct waveout_state *)state->driver_state, pause);
-}
-
-static void soundout_waveout_delete(struct sound_state *state) {
- waveout_delete((struct waveout_state *)state->driver_state);
- HeapFree(GetProcessHeap(), 0, state);
-}
-
struct sound_state *sound_init(HWND hwnd, unsigned srate, unsigned sectlen,
sound_callback cbfunc, void *userptr) {
- HANDLE heap = GetProcessHeap();
- struct sound_state *sound = HeapAlloc(heap, 0, sizeof(struct sound_state));
- if (!sound) return 0;
- struct dsound_state *dsound = dsound_init(hwnd, srate, sectlen, cbfunc, userptr);
- if (dsound) {
- sound->driver_state = dsound;
- sound->pause = soundout_dsound_pause;
- sound->delete = soundout_dsound_delete;
- return sound;
+ struct sound_state *state;
+ state = dsound_init(hwnd, srate, sectlen, cbfunc, userptr);
+ if (state) {
+ return state;
}
- struct waveout_state *waveout = waveout_init(hwnd, srate, sectlen, cbfunc, userptr);
- if (waveout) {
- sound->driver_state = waveout;
- sound->pause = soundout_waveout_pause;
- sound->delete = soundout_waveout_delete;
- return sound;
+ state = waveout_init(hwnd, srate, sectlen, cbfunc, userptr);
+ if (state) {
+ return state;
}
- HeapFree(heap, 0, sound);
return 0;
}
diff --git a/win32/soundout.h b/win32/soundout.h
index edfa501..93b0286 100644
--- a/win32/soundout.h
+++ b/win32/soundout.h
@@ -6,10 +6,9 @@
typedef void (*sound_callback)(void *userdata, int16_t *buf, unsigned frames);
struct sound_state {
- void *driver_state;
void (*pause)(struct sound_state *state, int pause);
- void (*delete)(struct sound_state *state);
- void *userptr;
+ void (*free)(struct sound_state *state);
+ const wchar_t *apiname;
};
struct sound_state *sound_init(HWND hwnd, unsigned srate, unsigned sectlen,
diff --git a/win32/waveout.c b/win32/waveout.c
index 9c96483..8827eec 100644
--- a/win32/waveout.c
+++ b/win32/waveout.c
@@ -1,27 +1,98 @@
#include "waveout.h"
+enum {
+ HDRCNT = 4
+};
+
struct waveout_state {
+ struct sound_state soundout;
HWAVEOUT wo;
+ HANDLE t_update;
+ HANDLE e_waveout;
+ HANDLE mtx_cbproc;
DWORD firstout;
+ DWORD paused;
+ DWORD terminate;
sound_callback cbfunc;
void *userptr;
- WAVEHDR waveheaders[4];
+ WAVEHDR waveheaders[HDRCNT];
+ DWORD nextout;
int16_t *wavebuf;
};
-static void CALLBACK waveout_cbproc(HWAVEOUT wo, UINT msg,
- DWORD_PTR instance,
- DWORD_PTR p1, DWORD_PTR p2) {
- (void)wo;
- (void)p2;
- if (msg != WOM_DONE) return;
- struct waveout_state *waveout = (struct waveout_state *)instance;
- WAVEHDR *wh = (WAVEHDR *)p1;
- waveout->cbfunc(waveout->userptr, (int16_t *)wh->lpData, wh->dwBufferLength/4);
- waveOutWrite(waveout->wo, wh, sizeof(*wh));
+static DWORD CALLBACK bufupdatethread(void *p) {
+ struct waveout_state *waveout = (struct waveout_state *)p;
+ for (;;) {
+ WaitForSingleObject(waveout->e_waveout, INFINITE);
+ if (waveout->terminate) ExitThread(0);
+ int i, whi;
+ for (i = 0;; i = (i+1)%HDRCNT) {
+ whi = (i + waveout->nextout) % HDRCNT;
+ WAVEHDR *wh = &waveout->waveheaders[whi];
+ if (!(wh->dwFlags & WHDR_DONE)) break;
+ //wh->dwFlags &= ~WHDR_DONE;
+
+ if (WaitForSingleObject(waveout->mtx_cbproc, 0) == WAIT_OBJECT_0) {
+ if (!waveout->paused) {
+ waveout->cbfunc(waveout->userptr,
+ (int16_t *)wh->lpData, wh->dwBufferLength/4);
+ } else {
+ ZeroMemory(wh->lpData, wh->dwBufferLength);
+ }
+ ReleaseMutex(waveout->mtx_cbproc);
+ } else {
+ ZeroMemory(wh->lpData, wh->dwBufferLength);
+ }
+ waveOutWrite(waveout->wo, wh, sizeof(*wh));
+ }
+ waveout->nextout = whi;
+ }
}
-struct waveout_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
+static void waveout_pause(struct sound_state *state, int pause) {
+ struct waveout_state *waveout = (struct waveout_state *)state;
+ if (pause) {
+ WaitForSingleObject(waveout->mtx_cbproc, INFINITE);
+ waveout->paused = 1;
+ ReleaseMutex(waveout->mtx_cbproc);
+ } else {
+ if (waveout->firstout) {
+ WaitForSingleObject(waveout->mtx_cbproc, INFINITE);
+ waveout->firstout = 0;
+ waveout->paused = 0;
+ waveOutReset(waveout->wo);
+ for (int i = 0; i < HDRCNT; i++) {
+ WAVEHDR *wh = &waveout->waveheaders[i];
+ waveout->cbfunc(waveout->userptr,
+ (int16_t *)wh->lpData, wh->dwBufferLength/4);
+ waveOutWrite(waveout->wo, wh, sizeof(*wh));
+ }
+ ReleaseMutex(waveout->mtx_cbproc);
+ } else {
+ waveout->paused = 0;
+ }
+ }
+}
+
+static void waveout_free(struct sound_state *state) {
+ struct waveout_state *waveout = (struct waveout_state *)state;
+ waveout->terminate = 1;
+ SetEvent(waveout->e_waveout);
+ WaitForSingleObject(waveout->t_update, INFINITE);
+ waveOutReset(waveout->wo);
+ for (int i = 0; i < HDRCNT; i++) {
+ WAVEHDR *wh = &waveout->waveheaders[i];
+ waveOutUnprepareHeader(waveout->wo, wh, sizeof(*wh));
+ }
+ waveOutClose(waveout->wo);
+ CloseHandle(waveout->mtx_cbproc);
+ CloseHandle(waveout->e_waveout);
+ HANDLE heap = GetProcessHeap();
+ HeapFree(heap, 0, waveout->wavebuf);
+ HeapFree(heap, 0, waveout);
+}
+
+struct sound_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
sound_callback cbfunc, void *userptr) {
HANDLE heap = GetProcessHeap();
struct waveout_state *waveout = HeapAlloc(heap, HEAP_ZERO_MEMORY,
@@ -30,10 +101,20 @@ struct waveout_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
MessageBoxW(hwnd, L"cannot allocate memory for WaveOut", L"Error", MB_ICONSTOP);
goto err;
}
- waveout->wavebuf = HeapAlloc(heap, HEAP_ZERO_MEMORY, sectlen*4);
+ waveout->e_waveout = CreateEventW(0, FALSE, FALSE, 0);
+ if (!waveout->e_waveout) {
+ MessageBoxW(hwnd, L"cannot create event for WaveOut", L"Error", MB_ICONSTOP);
+ goto err_waveout;
+ }
+ waveout->mtx_cbproc = CreateMutexW(0, FALSE, 0);
+ if (!waveout->mtx_cbproc) {
+ MessageBoxW(hwnd, L"cannot create mutex for WaveOut", L"Error", MB_ICONSTOP);
+ goto err_event;
+ }
+ waveout->wavebuf = HeapAlloc(heap, HEAP_ZERO_MEMORY, sectlen*HDRCNT);
if (!waveout->wavebuf) {
MessageBoxW(hwnd, L"cannot allocate buffer memory for WaveOut", L"Error", MB_ICONSTOP);
- goto err_waveout;
+ goto err_mtx;
}
WAVEFORMATEX format;
format.wFormatTag = WAVE_FORMAT_PCM;
@@ -45,12 +126,12 @@ struct waveout_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
format.cbSize = 0;
HRESULT hr;
hr = waveOutOpen(&waveout->wo, WAVE_MAPPER, &format,
- (DWORD_PTR)waveout_cbproc, (DWORD_PTR)waveout, CALLBACK_FUNCTION);
+ (DWORD_PTR)waveout->e_waveout, 0, CALLBACK_EVENT);
if (hr != MMSYSERR_NOERROR) {
MessageBoxW(hwnd, L"cannot WaveOutOpen", L"Error", MB_ICONSTOP);
goto err_wavebuf;
}
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < HDRCNT; i++) {
WAVEHDR *wh = &waveout->waveheaders[i];
wh->lpData = ((char *)waveout->wavebuf) + sectlen*i;
wh->dwBufferLength = sectlen;
@@ -58,43 +139,36 @@ struct waveout_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
waveOutPrepareHeader(waveout->wo, wh, sizeof(*wh));
}
waveout->firstout = 1;
+ waveout->paused = 1;
+ waveout->terminate = 0;
waveout->cbfunc = cbfunc;
waveout->userptr = userptr;
- return waveout;
-
-err_wavebuf:
- HeapFree(heap, 0, waveout->wavebuf);
-err_waveout:
- HeapFree(heap, 0, waveout);
-err:
- return 0;
-}
-
-void waveout_pause(struct waveout_state *waveout, int pause) {
- if (pause) {
- waveOutPause(waveout->wo);
- } else {
- if (waveout->firstout) {
- waveout->firstout = 0;
- for (int i = 0; i < 4; i++) {
- WAVEHDR *wh = &waveout->waveheaders[i];
- waveout->cbfunc(waveout->userptr, (int16_t *)wh->lpData, wh->dwBufferLength/4);
- waveOutWrite(waveout->wo, wh, sizeof(*wh));
- }
- } else {
- waveOutRestart(waveout->wo);
- }
+ waveout->t_update = CreateThread(0, 0, bufupdatethread, waveout, 0, 0);
+ if (!waveout->t_update) {
+ MessageBoxW(hwnd, L"cannot create thread for Waveout", L"Error", MB_ICONSTOP);
+ goto err_waveoutopen;
}
-}
+ SetThreadPriority(waveout->t_update, THREAD_PRIORITY_HIGHEST);
+ waveout->soundout.pause = waveout_pause;
+ waveout->soundout.free = waveout_free;
+ waveout->soundout.apiname = L"WinMM";
+ return (struct sound_state *)waveout;
-void waveout_delete(struct waveout_state *waveout) {
- if (!waveout) return;
- waveout_pause(waveout, 1);
- for (int i = 0; i < 4; i++) {
+err_waveoutopen:
+ waveOutReset(waveout->wo);
+ for (int i = 0; i < HDRCNT; i++) {
WAVEHDR *wh = &waveout->waveheaders[i];
waveOutUnprepareHeader(waveout->wo, wh, sizeof(*wh));
}
- HANDLE heap = GetProcessHeap();
+ waveOutClose(waveout->wo);
+err_wavebuf:
HeapFree(heap, 0, waveout->wavebuf);
+err_mtx:
+ CloseHandle(waveout->mtx_cbproc);
+err_event:
+ CloseHandle(waveout->e_waveout);
+err_waveout:
HeapFree(heap, 0, waveout);
+err:
+ return 0;
}
diff --git a/win32/waveout.h b/win32/waveout.h
index ff33b01..d8c4c3a 100644
--- a/win32/waveout.h
+++ b/win32/waveout.h
@@ -3,11 +3,7 @@
#include "soundout.h"
-struct waveout_state;
-
-struct waveout_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
+struct sound_state *waveout_init(HWND hwnd, unsigned srate, unsigned sectlen,
sound_callback cbfunc, void *userptr);
-void waveout_delete(struct waveout_state *waveout);
-void waveout_pause(struct waveout_state *waveout, int pause);
#endif // MYON_WAVEOUT_H_INCLUDED