diff options
Diffstat (limited to 'win32/waveout.c')
-rw-r--r-- | win32/waveout.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/win32/waveout.c b/win32/waveout.c new file mode 100644 index 0000000..9c96483 --- /dev/null +++ b/win32/waveout.c @@ -0,0 +1,100 @@ +#include "waveout.h" + +struct waveout_state { + HWAVEOUT wo; + DWORD firstout; + sound_callback cbfunc; + void *userptr; + WAVEHDR waveheaders[4]; + 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)); +} + +struct waveout_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, + sizeof(struct waveout_state)); + if (!waveout) { + MessageBoxW(hwnd, L"cannot allocate memory for WaveOut", L"Error", MB_ICONSTOP); + goto err; + } + waveout->wavebuf = HeapAlloc(heap, HEAP_ZERO_MEMORY, sectlen*4); + if (!waveout->wavebuf) { + MessageBoxW(hwnd, L"cannot allocate buffer memory for WaveOut", L"Error", MB_ICONSTOP); + goto err_waveout; + } + WAVEFORMATEX format; + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 2; + format.nSamplesPerSec = srate; + format.wBitsPerSample = 16; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + format.cbSize = 0; + HRESULT hr; + hr = waveOutOpen(&waveout->wo, WAVE_MAPPER, &format, + (DWORD_PTR)waveout_cbproc, (DWORD_PTR)waveout, CALLBACK_FUNCTION); + if (hr != MMSYSERR_NOERROR) { + MessageBoxW(hwnd, L"cannot WaveOutOpen", L"Error", MB_ICONSTOP); + goto err_wavebuf; + } + for (int i = 0; i < 4; i++) { + WAVEHDR *wh = &waveout->waveheaders[i]; + wh->lpData = ((char *)waveout->wavebuf) + sectlen*i; + wh->dwBufferLength = sectlen; + wh->dwFlags = 0; + waveOutPrepareHeader(waveout->wo, wh, sizeof(*wh)); + } + waveout->firstout = 1; + 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); + } + } +} + +void waveout_delete(struct waveout_state *waveout) { + if (!waveout) return; + waveout_pause(waveout, 1); + for (int i = 0; i < 4; i++) { + WAVEHDR *wh = &waveout->waveheaders[i]; + waveOutUnprepareHeader(waveout->wo, wh, sizeof(*wh)); + } + HANDLE heap = GetProcessHeap(); + HeapFree(heap, 0, waveout->wavebuf); + HeapFree(heap, 0, waveout); +} |