aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--win32/amd64/Makefile6
-rw-r--r--win32/fmplayer.mak10
-rw-r--r--win32/guid.c4
-rw-r--r--win32/main.c2
-rw-r--r--win32/uc.c36
-rw-r--r--win32/wasapiout.c279
-rw-r--r--win32/wasapiout.h10
-rw-r--r--win32/x86/Makefile6
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)