Mercurial > codedump
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; +}