Mercurial > codedump
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 125:5cc85ef3a675 | 126:8e4ee43d3b81 |
|---|---|
| 1 /* winmm audio driver for ft2play | |
| 2 ** | |
| 3 ** Warning: This might not be 100% thread-safe or lock-safe! | |
| 4 */ | |
| 5 | |
| 6 #define WIN32_LEAN_AND_MEAN | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 #include <stdbool.h> | |
| 10 #include <stdlib.h> | |
| 11 #include <windows.h> | |
| 12 #include <mmsystem.h> | |
| 13 #include "../../pmp_mix.h" | |
| 14 | |
| 15 #define MIX_BUF_NUM 4 | |
| 16 | |
| 17 static volatile BOOL mixerOpened, mixerBusy, mixerLocked; | |
| 18 static uint8_t currBuffer; | |
| 19 static int16_t *audioBuffer[MIX_BUF_NUM]; | |
| 20 static int32_t bufferSize; | |
| 21 static HANDLE hThread, hAudioSem; | |
| 22 static WAVEHDR waveBlocks[MIX_BUF_NUM]; | |
| 23 static HWAVEOUT hWave; | |
| 24 | |
| 25 static DWORD WINAPI mixThread(LPVOID lpParam) | |
| 26 { | |
| 27 (void)lpParam; | |
| 28 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); | |
| 29 while (mixerOpened) | |
| 30 { | |
| 31 WAVEHDR *waveBlock = &waveBlocks[currBuffer]; | |
| 32 | |
| 33 if (!mixerLocked) | |
| 34 { | |
| 35 mixerBusy = true; | |
| 36 mix_UpdateBuffer((int16_t *)waveBlock->lpData, bufferSize); // pmp_mix.c function | |
| 37 mixerBusy = false; | |
| 38 } | |
| 39 | |
| 40 waveOutWrite(hWave, waveBlock, sizeof (WAVEHDR)); | |
| 41 currBuffer = (currBuffer + 1) % MIX_BUF_NUM; | |
| 42 WaitForSingleObject(hAudioSem, INFINITE); // wait for buffer fill request | |
| 43 } | |
| 44 | |
| 45 return 0; | |
| 46 } | |
| 47 | |
| 48 static void CALLBACK waveProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) | |
| 49 { | |
| 50 if (uMsg == WOM_DONE) | |
| 51 ReleaseSemaphore(hAudioSem, 1, NULL); | |
| 52 | |
| 53 (void)hWaveOut; | |
| 54 (void)uMsg; | |
| 55 (void)dwInstance; | |
| 56 (void)dwParam1; | |
| 57 (void)dwParam2; | |
| 58 } | |
| 59 | |
| 60 void lockMixer(void) | |
| 61 { | |
| 62 mixerLocked = true; | |
| 63 while (mixerBusy); | |
| 64 } | |
| 65 | |
| 66 void unlockMixer(void) | |
| 67 { | |
| 68 mixerBusy = false; | |
| 69 mixerLocked = false; | |
| 70 } | |
| 71 | |
| 72 void closeMixer(void) | |
| 73 { | |
| 74 mixerOpened = false; | |
| 75 mixerBusy = false; | |
| 76 | |
| 77 if (hAudioSem != NULL) | |
| 78 ReleaseSemaphore(hAudioSem, 1, NULL); | |
| 79 | |
| 80 if (hThread != NULL) | |
| 81 { | |
| 82 WaitForSingleObject(hThread, INFINITE); | |
| 83 CloseHandle(hThread); | |
| 84 hThread = NULL; | |
| 85 } | |
| 86 | |
| 87 if (hAudioSem != NULL) | |
| 88 { | |
| 89 CloseHandle(hAudioSem); | |
| 90 hAudioSem = NULL; | |
| 91 } | |
| 92 | |
| 93 if (hWave != NULL) | |
| 94 { | |
| 95 waveOutReset(hWave); | |
| 96 | |
| 97 for (int32_t i = 0; i < MIX_BUF_NUM; i++) | |
| 98 { | |
| 99 if (waveBlocks[i].dwUser != 0xFFFF) | |
| 100 waveOutUnprepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)); | |
| 101 } | |
| 102 | |
| 103 waveOutClose(hWave); | |
| 104 hWave = NULL; | |
| 105 } | |
| 106 | |
| 107 for (int32_t i = 0; i < MIX_BUF_NUM; i++) | |
| 108 { | |
| 109 if (audioBuffer[i] != NULL) | |
| 110 { | |
| 111 free(audioBuffer[i]); | |
| 112 audioBuffer[i] = NULL; | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 bool openMixer(int32_t mixingFrequency, int32_t mixingBufferSize) | |
| 118 { | |
| 119 DWORD threadID; | |
| 120 WAVEFORMATEX wfx; | |
| 121 | |
| 122 // don't unprepare headers on error | |
| 123 for (int32_t i = 0; i < MIX_BUF_NUM; i++) | |
| 124 waveBlocks[i].dwUser = 0xFFFF; | |
| 125 | |
| 126 closeMixer(); | |
| 127 bufferSize = mixingBufferSize; | |
| 128 | |
| 129 ZeroMemory(&wfx, sizeof (wfx)); | |
| 130 wfx.nSamplesPerSec = mixingFrequency; | |
| 131 wfx.wBitsPerSample = 16; | |
| 132 wfx.nChannels = 2; | |
| 133 wfx.wFormatTag = WAVE_FORMAT_PCM; | |
| 134 wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8); | |
| 135 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; | |
| 136 | |
| 137 if (waveOutOpen(&hWave, WAVE_MAPPER, &wfx, (DWORD_PTR)&waveProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) | |
| 138 goto omError; | |
| 139 | |
| 140 // create semaphore for buffer fill requests | |
| 141 hAudioSem = CreateSemaphore(NULL, MIX_BUF_NUM - 1, MIX_BUF_NUM, NULL); | |
| 142 if (hAudioSem == NULL) | |
| 143 goto omError; | |
| 144 | |
| 145 // allocate WinMM mix buffers | |
| 146 for (int32_t i = 0; i < MIX_BUF_NUM; i++) | |
| 147 { | |
| 148 audioBuffer[i] = (int16_t *)calloc(mixingBufferSize, wfx.nBlockAlign); | |
| 149 if (audioBuffer[i] == NULL) | |
| 150 goto omError; | |
| 151 } | |
| 152 | |
| 153 // initialize WinMM mix headers | |
| 154 memset(waveBlocks, 0, sizeof (waveBlocks)); | |
| 155 for (int32_t i = 0; i < MIX_BUF_NUM; i++) | |
| 156 { | |
| 157 waveBlocks[i].lpData = (LPSTR)audioBuffer[i]; | |
| 158 waveBlocks[i].dwBufferLength = mixingBufferSize * wfx.nBlockAlign; | |
| 159 waveBlocks[i].dwFlags = WHDR_DONE; | |
| 160 | |
| 161 if (waveOutPrepareHeader(hWave, &waveBlocks[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR) | |
| 162 goto omError; | |
| 163 } | |
| 164 | |
| 165 currBuffer = 0; | |
| 166 mixerOpened = true; | |
| 167 | |
| 168 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)mixThread, NULL, 0, &threadID); | |
| 169 if (hThread == NULL) | |
| 170 goto omError; | |
| 171 | |
| 172 return TRUE; | |
| 173 | |
| 174 omError: | |
| 175 closeMixer(); | |
| 176 return FALSE; | |
| 177 } |
