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 }