diff win95kggui/dep/ft2play/audiodrivers/winmm/winmm.c @ 126:8e4ee43d3b81

remove submodules
author Paper <mrpapersonic@gmail.com>
date Sun, 01 Oct 2023 03:48:43 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/win95kggui/dep/ft2play/audiodrivers/winmm/winmm.c	Sun Oct 01 03:48:43 2023 -0400
@@ -0,0 +1,177 @@
+/* winmm audio driver for ft2play
+**
+** Warning: This might not be 100% thread-safe or lock-safe!
+*/
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <mmsystem.h>
+#include "../../pmp_mix.h"
+
+#define MIX_BUF_NUM 4
+
+static volatile BOOL mixerOpened, mixerBusy, mixerLocked;
+static uint8_t currBuffer;
+static int16_t *audioBuffer[MIX_BUF_NUM];
+static int32_t bufferSize;
+static HANDLE hThread, hAudioSem;
+static WAVEHDR waveBlocks[MIX_BUF_NUM];
+static HWAVEOUT hWave;
+
+static DWORD WINAPI mixThread(LPVOID lpParam)
+{
+	(void)lpParam;
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+	while (mixerOpened)
+	{
+		WAVEHDR *waveBlock = &waveBlocks[currBuffer];
+
+		if (!mixerLocked)
+		{
+			mixerBusy = true;
+			mix_UpdateBuffer((int16_t *)waveBlock->lpData, bufferSize); // pmp_mix.c function
+			mixerBusy = false;
+		}
+
+		waveOutWrite(hWave, waveBlock, sizeof (WAVEHDR));
+		currBuffer = (currBuffer + 1) % MIX_BUF_NUM;
+		WaitForSingleObject(hAudioSem, INFINITE); // wait for buffer fill request
+	}
+
+	return 0;
+}
+
+static void CALLBACK waveProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+	if (uMsg == WOM_DONE)
+		ReleaseSemaphore(hAudioSem, 1, NULL);
+
+	(void)hWaveOut;
+	(void)uMsg;
+	(void)dwInstance;
+	(void)dwParam1;
+	(void)dwParam2;
+}
+
+void lockMixer(void)
+{
+	mixerLocked = true;
+	while (mixerBusy);
+}
+
+void unlockMixer(void)
+{
+	mixerBusy = false;
+	mixerLocked = false;
+}
+
+void closeMixer(void)
+{
+	mixerOpened = false;
+	mixerBusy = false;
+
+	if (hAudioSem != NULL)
+		ReleaseSemaphore(hAudioSem, 1, NULL);
+
+	if (hThread != NULL)
+	{
+		WaitForSingleObject(hThread, INFINITE);
+		CloseHandle(hThread);
+		hThread = NULL;
+	}
+
+	if (hAudioSem != NULL)
+	{
+		CloseHandle(hAudioSem);
+		hAudioSem = NULL;
+	}
+
+	if (hWave != NULL)
+	{
+		waveOutReset(hWave);
+
+		for (int32_t i = 0; i < MIX_BUF_NUM; i++)
+		{
+			if (waveBlocks[i].dwUser != 0xFFFF)
+				waveOutUnprepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR));
+		}
+
+		waveOutClose(hWave);
+		hWave = NULL;
+	}
+
+	for (int32_t i = 0; i < MIX_BUF_NUM; i++)
+	{
+		if (audioBuffer[i] != NULL)
+		{
+			free(audioBuffer[i]);
+			audioBuffer[i] = NULL;
+		}
+	}
+}
+
+bool openMixer(int32_t mixingFrequency, int32_t mixingBufferSize)
+{
+	DWORD threadID;
+	WAVEFORMATEX wfx;
+
+	// don't unprepare headers on error
+	for (int32_t i = 0; i < MIX_BUF_NUM; i++)
+		waveBlocks[i].dwUser = 0xFFFF;
+
+	closeMixer();
+	bufferSize = mixingBufferSize;
+
+	ZeroMemory(&wfx, sizeof (wfx));
+	wfx.nSamplesPerSec = mixingFrequency;
+	wfx.wBitsPerSample = 16;
+	wfx.nChannels = 2;
+	wfx.wFormatTag = WAVE_FORMAT_PCM;
+	wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
+	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+	if (waveOutOpen(&hWave, WAVE_MAPPER, &wfx, (DWORD_PTR)&waveProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
+		goto omError;
+
+	// create semaphore for buffer fill requests
+	hAudioSem = CreateSemaphore(NULL, MIX_BUF_NUM - 1, MIX_BUF_NUM, NULL);
+	if (hAudioSem == NULL)
+		goto omError;
+
+	// allocate WinMM mix buffers
+	for (int32_t i = 0; i < MIX_BUF_NUM; i++)
+	{
+		audioBuffer[i] = (int16_t *)calloc(mixingBufferSize, wfx.nBlockAlign);
+		if (audioBuffer[i] == NULL)
+			goto omError;
+	}
+
+	// initialize WinMM mix headers
+	memset(waveBlocks, 0, sizeof (waveBlocks));
+	for (int32_t i = 0; i < MIX_BUF_NUM; i++)
+	{
+		waveBlocks[i].lpData = (LPSTR)audioBuffer[i];
+		waveBlocks[i].dwBufferLength = mixingBufferSize * wfx.nBlockAlign;
+		waveBlocks[i].dwFlags = WHDR_DONE;
+
+		if (waveOutPrepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR)
+			goto omError;
+	}
+
+	currBuffer = 0;
+	mixerOpened = true;
+
+	hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)mixThread, NULL, 0, &threadID);
+	if (hThread == NULL)
+		goto omError;
+
+	return TRUE;
+
+omError:
+	closeMixer();
+	return FALSE;
+}