diff options
-rw-r--r-- | win32/amd64/Makefile | 6 | ||||
-rw-r--r-- | win32/fmplayer.mak | 10 | ||||
-rw-r--r-- | win32/guid.c | 4 | ||||
-rw-r--r-- | win32/main.c | 2 | ||||
-rw-r--r-- | win32/uc.c | 36 | ||||
-rw-r--r-- | win32/wasapiout.c | 279 | ||||
-rw-r--r-- | win32/wasapiout.h | 10 | ||||
-rw-r--r-- | win32/x86/Makefile | 6 |
8 files changed, 305 insertions, 48 deletions
diff --git a/win32/amd64/Makefile b/win32/amd64/Makefile index 5769d7b..d3b0130 100644 --- a/win32/amd64/Makefile +++ b/win32/amd64/Makefile @@ -6,7 +6,7 @@ vpath %.rc .. include ../fmplayer.mak -OBJS=$(addsuffix .o,$(OBJBASE) uc $(RESBASE)) +OBJS=$(addsuffix .o,$(OBJBASE) $(RESBASE)) ARCH=x86_64 PREFIX=$(ARCH)-w64-mingw32- CC=$(PREFIX)gcc @@ -14,9 +14,7 @@ WINDRES=$(PREFIX)windres STRIP=$(PREFIX)strip CFLAGS=-std=c99 -Os -Wall -Wextra -pedantic -I../.. \ $(addprefix -D,$(DEFINES)) -LIBS=-nostdlib -s -Wl,-eentry \ - -Wl,--subsystem,windows \ - -lgcc -lntdll \ +LIBS=-s -mwindows -municode \ $(addprefix -l,$(LIBBASE)) $(TARGET): $(OBJS) diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak index 146b5b8..431be9f 100644 --- a/win32/fmplayer.mak +++ b/win32/fmplayer.mak @@ -16,12 +16,16 @@ LIBOPNA_OBJS=opna \ opnadrum \ opnaadpcm FMDSP_OBJS=fmdsp \ - font_rom + font_rom \ + font_fmdsp_small OBJBASE=main \ soundout \ dsoundout \ waveout \ + srcloader \ + wasapiout \ winfont \ + guid \ $(FMDRIVER_OBJS) \ $(LIBOPNA_OBJS) \ $(FMDSP_OBJS) @@ -29,11 +33,11 @@ RESBASE=lnf LIBBASE=user32 \ kernel32 \ ole32 \ - dxguid \ uuid \ comdlg32 \ gdi32 \ shlwapi \ winmm \ - shell32 + shell32 \ + ksuser diff --git a/win32/guid.c b/win32/guid.c new file mode 100644 index 0000000..80843aa --- /dev/null +++ b/win32/guid.c @@ -0,0 +1,4 @@ +#define INITGUID +#include <dsound.h> +#include <mmdeviceapi.h> +#include <audioclient.h> diff --git a/win32/main.c b/win32/main.c index 5add23f..7cf8494 100644 --- a/win32/main.c +++ b/win32/main.c @@ -427,7 +427,7 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) { loadfont(); fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0); fmdsp_vram_init(&g.fmdsp, &g.work, g.vram); - SetTimer(hwnd, TIMER_FMDSP, 50, 0); + SetTimer(hwnd, TIMER_FMDSP, 16, 0); #ifdef ENABLE_WM_DROPFILES DragAcceptFiles(hwnd, TRUE); #endif diff --git a/win32/uc.c b/win32/uc.c deleted file mode 100644 index 70d2e85..0000000 --- a/win32/uc.c +++ /dev/null @@ -1,36 +0,0 @@ -#include <string.h> -#include <windows.h> - -int memcmp(const void *s1, const void *s2, size_t n) { - size_t i = RtlCompareMemory(s1, s2, n); - if (i == n) return 0; - return ((const unsigned char *)s1)[i] - ((const unsigned char *)s2)[i]; -} - -void *memset(void *s, int c, size_t n) { - RtlFillMemory(s, n, c); - return s; -} - -void *memcpy(void *dest, const void *src, size_t n) { - RtlCopyMemory(dest, src, n); - return dest; -} - -void *memmove(void *dest, const void *src, size_t n) { - RtlMoveMemory(dest, src, n); - return dest; -} - -int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst, - wchar_t *cmdline, int cmdshow); - -DWORD CALLBACK entry(void *ptr) { - (void)ptr; - STARTUPINFO si; - GetStartupInfo(&si); - int cmdshow = si.wShowWindow; - if (si.dwFlags & STARTF_USESHOWWINDOW) cmdshow = SW_SHOWNORMAL; - DWORD ret = wWinMain(GetModuleHandle(0), 0, 0, cmdshow); - ExitProcess(ret); -} diff --git a/win32/wasapiout.c b/win32/wasapiout.c new file mode 100644 index 0000000..42c0bc0 --- /dev/null +++ b/win32/wasapiout.c @@ -0,0 +1,279 @@ +#include "wasapiout.h" +//#include "srcloader.h" +#include <windows.h> +#include <mmdeviceapi.h> +#include <audioclient.h> + +enum { + SRCBUFFRAMES = 256, +}; + +struct wasapi_state { + struct sound_state soundout; + IAudioClient *ac; + IAudioRenderClient *rc; + HANDLE t_update; + HANDLE e_update; + HANDLE mtx_cbproc; + sound_callback cbfunc; + void *userptr; + int16_t *buf_i; + float *buf_f; +// SRC_STATE *src; + DWORD terminate; + DWORD paused; + unsigned buf_frames; + unsigned buf_used_frames; + UINT32 wasapi_buf_frames; +// unsigned srate; +// double src_ratio; +}; + +static DWORD CALLBACK bufupdatethread(void *p) { + struct wasapi_state *wasapiout = (struct wasapi_state *)p; + for (;;) { + WaitForSingleObject(wasapiout->e_update, INFINITE); + if (wasapiout->terminate) ExitThread(0); + int16_t *outbuf; + while (SUCCEEDED(wasapiout->rc->lpVtbl->GetBuffer(wasapiout->rc, + wasapiout->wasapi_buf_frames, (BYTE **)&outbuf))) { + int silence = 1; + if (WaitForSingleObject(wasapiout->mtx_cbproc, 0) == WAIT_OBJECT_0) { + if (!wasapiout->paused) { + silence = 0; +/* + ZeroMemory(wasapiout->buf_i, wasapiout->wasapi_buf_frames*4); + wasapiout->cbfunc( + wasapiout->userptr, + wasapiout->buf_i, + wasapiout->wasapi_buf_frames); +*/ + ZeroMemory(wasapiout->buf_i, wasapiout->wasapi_buf_frames*4); + wasapiout->cbfunc( + wasapiout->userptr, + outbuf, + wasapiout->wasapi_buf_frames); + } + ReleaseMutex(wasapiout->mtx_cbproc); + } + if (!silence) { + //g_src.src_short_to_float_array(wasapiout->buf_i, outbuf, wasapiout->wasapi_buf_frames*2); + } + wasapiout->rc->lpVtbl->ReleaseBuffer(wasapiout->rc, + wasapiout->wasapi_buf_frames, + silence ? AUDCLNT_BUFFERFLAGS_SILENT : 0); + } + } +} + +static void wasapi_pause(struct sound_state *state, int pause) { + struct wasapi_state *wasapiout = (struct wasapi_state *)state; + if (pause) { + //wasapiout->ac->lpVtbl->Stop(wasapiout->ac); + WaitForSingleObject(wasapiout->mtx_cbproc, INFINITE); + wasapiout->paused = 1; + ReleaseMutex(wasapiout->mtx_cbproc); + } else { + wasapiout->paused = 0; + //wasapiout->ac->lpVtbl->Start(wasapiout->ac); + } +} + +static void wasapi_free(struct sound_state *state) { + struct wasapi_state *wasapiout = (struct wasapi_state *)state; + HANDLE heap = GetProcessHeap(); + wasapiout->terminate = 1; + SetEvent(wasapiout->e_update); + WaitForSingleObject(wasapiout->t_update, INFINITE); + wasapiout->ac->lpVtbl->Stop(wasapiout->ac); + wasapiout->rc->lpVtbl->Release(wasapiout->rc); + wasapiout->ac->lpVtbl->Release(wasapiout->ac); + HeapFree(heap, 0, wasapiout->buf_f); + HeapFree(heap, 0, wasapiout->buf_i); + CloseHandle(wasapiout->mtx_cbproc); + CloseHandle(wasapiout->e_update); +// g_src.src_delete(wasapiout->src); + HeapFree(heap, 0, wasapiout); +} + +struct sound_state *wasapi_init(HWND hwnd, unsigned srate, unsigned sectlen, + sound_callback cbfunc, void *userptr) { + if (sectlen % (sizeof(int16_t)*2)) goto err; + unsigned sectframes = sectlen / (sizeof(int16_t)*2); +/* + src_load(); + if (!g_src.dll) goto err; +*/ + HANDLE heap = GetProcessHeap(); + if (!heap) { + MessageBoxW(hwnd, L"Cannot get process heap for wasapi", L"Error", MB_ICONSTOP); + goto err; + } + struct wasapi_state *wasapiout = HeapAlloc(heap, HEAP_ZERO_MEMORY, + sizeof(struct wasapi_state)); + if (!wasapiout) { + MessageBoxW(hwnd, L"Cannot allocate memory for wasapi", L"Error", MB_ICONSTOP); + goto err; + } +/* + { + int e; + wasapiout->src = g_src.src_new(SRC_SINC_BEST_QUALITY, 2, &e); + } + if (!wasapiout->src) { + MessageBoxW(hwnd, L"WASAPI failed to create samplerate converter", L"Error", + MB_ICONSTOP); + goto err_wasapiout; + } +*/ + CoInitializeEx(0, COINIT_MULTITHREADED); + HRESULT hr; + IMMDeviceEnumerator *mmde; + hr = CoCreateInstance( + &CLSID_MMDeviceEnumerator, + 0, + CLSCTX_ALL, + &IID_IMMDeviceEnumerator, + (void **)&mmde); + if (FAILED(hr)) { + goto err_src; + } + IMMDevice *mmdev; + hr = mmde->lpVtbl->GetDefaultAudioEndpoint(mmde, eRender, eMultimedia, &mmdev); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI GetDefaultEndpoint failed", L"Error", MB_ICONSTOP); + goto err_mmde; + } + hr = mmdev->lpVtbl->Activate( + mmdev, &IID_IAudioClient, CLSCTX_ALL, 0, (void **)&wasapiout->ac); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI cannot get IAudioClient", L"Error", + MB_ICONSTOP); + goto err_mmdev; + } + wasapiout->e_update = CreateEventW(0, FALSE, FALSE, 0); + if (!wasapiout->e_update) { + MessageBoxW(hwnd, L"WASAPI CreateEvent failed", L"Error", MB_ICONSTOP); + goto err_ac; + } + wasapiout->mtx_cbproc = CreateMutexW(0, FALSE, 0); + if (!wasapiout->mtx_cbproc) { + MessageBoxW(hwnd, L"WASAPI CreateMutex failed", L"Error", MB_ICONSTOP); + goto err_event; + } + DWORD mixsrate; + { + WAVEFORMATEX *mixfmt; + hr = wasapiout->ac->lpVtbl->GetMixFormat(wasapiout->ac, &mixfmt); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI GetMixFormat failed", L"Error", MB_ICONSTOP); + goto err_mtx; + } + mixsrate = mixfmt->nSamplesPerSec; + CoTaskMemFree(mixfmt); + } + WAVEFORMATEXTENSIBLE format = {0}; + format.Format.wFormatTag = WAVE_FORMAT_PCM; + format.Format.nChannels = 2; + format.Format.nSamplesPerSec = srate; + format.Format.wBitsPerSample = 16; + format.Format.nBlockAlign = + format.Format.nChannels * format.Format.wBitsPerSample / 8; + format.Format.nAvgBytesPerSec = + format.Format.nSamplesPerSec * format.Format.nBlockAlign; + format.Format.cbSize = 0;//sizeof(format)-sizeof(format.Format); + format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample; + format.dwChannelMask = (1<<format.Format.nChannels)-1; + format.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + + hr = wasapiout->ac->lpVtbl->Initialize( + wasapiout->ac, AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | 0x80000000, + 0, 0, &format.Format, 0); + if (FAILED(hr)) { + wchar_t str[] = L"0x : WASAPI IAudioClient Initialize failed"; + for (int i = 0; i < 8; i++) { + wchar_t c = (hr >> ((7-i)*4)) & 0xf; + c += L'0'; + if (c > L'9') c += (L'A' - L'0'); + str[2+i] = c; + } + MessageBoxW(hwnd, str, L"Error", + MB_ICONSTOP); + goto err_mtx; + } + hr = wasapiout->ac->lpVtbl->SetEventHandle( + wasapiout->ac, wasapiout->e_update); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI cannot set event handle", L"Error", MB_ICONSTOP); + goto err_mtx; + } + hr = wasapiout->ac->lpVtbl->GetBufferSize( + wasapiout->ac, &wasapiout->wasapi_buf_frames); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI GetBufferSize failed", L"Error", MB_ICONSTOP); + goto err_mtx; + } + wasapiout->wasapi_buf_frames /= 4; + wasapiout->buf_i = HeapAlloc(heap, HEAP_ZERO_MEMORY, + sizeof(int16_t)*wasapiout->wasapi_buf_frames*2); + if (!wasapiout->buf_i) { + MessageBoxW(hwnd, L"WASAPI buffer allocation failed", L"Error", MB_ICONSTOP); + goto err_mtx; + } + wasapiout->buf_f = HeapAlloc(heap, HEAP_ZERO_MEMORY, + sizeof(float)*sectframes*2); + if (!wasapiout->buf_f) { + MessageBoxW(hwnd, L"WASAPI buffer allocation failed", L"Error", MB_ICONSTOP); + goto err_buf_i; + } + hr = wasapiout->ac->lpVtbl->GetService( + wasapiout->ac, &IID_IAudioRenderClient, (void **)&wasapiout->rc); + if (FAILED(hr)) { + MessageBoxW(hwnd, L"WASAPI cannot get IAudioRenderClient", L"Error", + MB_ICONSTOP); + goto err_buf_f; + } + wasapiout->terminate = 0; + wasapiout->paused = 1; + wasapiout->cbfunc = cbfunc; + wasapiout->userptr = userptr; + wasapiout->buf_frames = sectframes; + wasapiout->buf_used_frames = 0; + wasapiout->t_update = CreateThread(0, 0, bufupdatethread, wasapiout, 0, 0); + if (!wasapiout->t_update) { + MessageBoxW(hwnd, L"WASAPI CreateThread error", L"Error", MB_ICONSTOP); + goto err_rc; + } + SetThreadPriority(wasapiout->t_update, THREAD_PRIORITY_HIGHEST); + wasapiout->soundout.pause = wasapi_pause; + wasapiout->soundout.free = wasapi_free; + wasapiout->soundout.apiname = L"WASAPI"; + mmdev->lpVtbl->Release(mmdev); + mmde->lpVtbl->Release(mmde); + wasapiout->ac->lpVtbl->Start(wasapiout->ac); + return &wasapiout->soundout; + +err_rc: + wasapiout->rc->lpVtbl->Release(wasapiout->rc); +err_buf_f: + HeapFree(heap, 0, wasapiout->buf_f); +err_buf_i: + HeapFree(heap, 0, wasapiout->buf_i); +err_mtx: + CloseHandle(wasapiout->mtx_cbproc); +err_event: + CloseHandle(wasapiout->e_update); +err_ac: + wasapiout->ac->lpVtbl->Release(wasapiout->ac); +err_mmdev: + mmdev->lpVtbl->Release(mmdev); +err_mmde: + mmde->lpVtbl->Release(mmde); +err_src: +// g_src.src_delete(wasapiout->src); +err_wasapiout: + HeapFree(heap, 0, wasapiout); +err: + return 0; +} diff --git a/win32/wasapiout.h b/win32/wasapiout.h new file mode 100644 index 0000000..eab9cff --- /dev/null +++ b/win32/wasapiout.h @@ -0,0 +1,10 @@ +#ifndef MYON_WASAPIOUT_H_INCLUDED +#define MYON_WASAPIOUT_H_INCLUDED + +#include "soundout.h" + +struct sound_state *wasapi_init(HWND hwnd, unsigned srate, unsigned sectlen, + sound_callback cbfunc, void *userptr); + +#endif // MYON_WASAPIOUT_H_INCLUDED + diff --git a/win32/x86/Makefile b/win32/x86/Makefile index 752db91..2f523a3 100644 --- a/win32/x86/Makefile +++ b/win32/x86/Makefile @@ -6,7 +6,7 @@ vpath %.rc .. include ../fmplayer.mak -OBJS=$(addsuffix .o,$(OBJBASE) uc $(RESBASE)) +OBJS=$(addsuffix .o,$(OBJBASE) $(RESBASE)) ARCH=i686 PREFIX=$(ARCH)-w64-mingw32- CC=$(PREFIX)gcc @@ -15,9 +15,7 @@ STRIP=$(PREFIX)strip CFLAGS=-std=c99 -Os -Wall -Wextra -pedantic -I../.. \ $(addprefix -D,$(DEFINES)) \ -march=i586 -LIBS=-nostdlib -s -Wl,-e_entry@4 \ - -Wl,--subsystem,windows \ - -lgcc -lntdll \ +LIBS=-s -mwindows -municode \ $(addprefix -l,$(LIBBASE)) $(TARGET): $(OBJS) |