This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_dibaudio.c
328 lines (281 loc) · 9.69 KB
1
/*
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Simple DirectMedia Layer
Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_config.h"
22
23
24
/* Allow access to a raw mixing buffer */
25
#include "../../core/windows/SDL_windows.h"
26
27
28
#include <mmsystem.h>
#include "SDL_timer.h"
29
#include "SDL_audio.h"
30
#include "../SDL_audio_c.h"
31
#include "SDL_dibaudio.h"
32
33
34
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
#include "win_ce_semaphore.h"
#endif
35
36
37
38
39
40
41
42
#if defined(_WIN32_WCE)
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
#elif defined(WIN64)
#define WINDOWS_OS_NAME "Win64"
#else
#define WINDOWS_OS_NAME "Win32"
#endif
43
44
/* The Win32 callback for filling the WAVE device */
45
46
47
static void CALLBACK
FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD dwParam1, DWORD dwParam2)
48
{
49
SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
50
51
52
53
/* Only service "buffer done playing" messages */
if (uMsg != WOM_DONE)
return;
54
55
/* Signal that we are done playing a buffer */
56
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
57
ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
58
#else
59
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
60
#endif
61
62
}
63
64
static void
SetMMerror(char *function, MMRESULT code)
65
{
66
67
68
size_t len;
char errbuf[MAXERRORLENGTH];
wchar_t werrbuf[MAXERRORLENGTH];
69
70
71
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
len = SDL_strlen(errbuf);
72
73
74
75
waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
MAXERRORLENGTH - len, NULL, NULL);
76
77
SDL_SetError("%s", errbuf);
78
79
80
}
/* Set high priority for the audio thread */
81
static void
82
WINWAVEOUT_ThreadInit(_THIS)
83
{
84
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
85
86
}
87
void
88
WINWAVEOUT_WaitDevice(_THIS)
89
{
90
/* Wait for an audio chunk to finish */
91
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
92
WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
93
#else
94
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
95
#endif
96
97
}
98
Uint8 *
99
WINWAVEOUT_GetDeviceBuf(_THIS)
100
{
101
102
return (Uint8 *) (this->hidden->
wavebuf[this->hidden->next_buffer].lpData);
103
104
}
105
void
106
WINWAVEOUT_PlayDevice(_THIS)
107
{
108
/* Queue it up */
109
110
waveOutWrite(this->hidden->sound,
&this->hidden->wavebuf[this->hidden->next_buffer],
111
sizeof(this->hidden->wavebuf[0]));
112
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
113
114
}
115
void
116
WINWAVEOUT_WaitDone(_THIS)
117
{
118
119
120
121
122
int i, left;
do {
left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) {
123
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
124
125
126
127
128
129
--left;
}
}
if (left > 0) {
SDL_Delay(100);
}
130
} while (left > 0);
131
132
}
133
void
134
WINWAVEOUT_CloseDevice(_THIS)
135
{
136
/* Close up audio */
137
138
139
140
if (this->hidden != NULL) {
int i;
if (this->hidden->audio_sem) {
141
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
142
CloseSynchHandle(this->hidden->audio_sem);
143
#else
144
CloseHandle(this->hidden->audio_sem);
145
#endif
146
147
this->hidden->audio_sem = 0;
}
148
149
150
151
if (this->hidden->sound) {
waveOutClose(this->hidden->sound);
this->hidden->sound = 0;
152
}
153
154
155
156
157
158
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->sound,
&this->hidden->wavebuf[i],
159
sizeof(this->hidden->wavebuf[i]));
160
161
162
163
164
165
166
167
168
169
170
171
this->hidden->wavebuf[i].dwUser = 0xFFFF;
}
}
if (this->hidden->mixbuf != NULL) {
/* Free raw mixing buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
172
}
173
174
}
175
int
176
WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
177
{
178
179
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
180
181
MMRESULT result;
WAVEFORMATEX waveformat;
182
183
184
185
int i;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
186
SDL_malloc((sizeof *this->hidden));
187
188
189
190
191
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
192
193
194
/* Initialize the wavebuf structures for closing */
for (i = 0; i < NUM_BUFFERS; ++i)
195
196
197
198
this->hidden->wavebuf[i].dwUser = 0xFFFF;
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
199
this->spec.format = test_format;
200
switch (test_format) {
201
202
203
204
205
206
207
208
209
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
break; /* valid. */
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
210
211
212
213
214
215
216
217
}
}
if (!valid_datatype) {
WINWAVEOUT_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return 0;
}
218
219
/* Set basic WAVE format parameters */
220
SDL_memset(&waveformat, '\0', sizeof(waveformat));
221
waveformat.wFormatTag = WAVE_FORMAT_PCM;
222
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
223
224
if (this->spec.channels > 2)
225
this->spec.channels = 2; /* !!! FIXME: is this right? */
226
227
228
waveformat.nChannels = this->spec.channels;
waveformat.nSamplesPerSec = this->spec.freq;
229
230
231
232
233
234
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
235
236
if (this->spec.samples < (this->spec.freq / 4))
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
237
238
/* Update the fragment size as size in bytes */
239
SDL_CalculateAudioSpec(&this->spec);
240
241
/* Open the audio device */
242
result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
243
244
245
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
246
WINWAVEOUT_CloseDevice(this);
247
SetMMerror("waveOutOpen()", result);
248
return 0;
249
}
250
#ifdef SOUND_DEBUG
251
252
253
254
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
255
256
result = waveOutGetDevCaps((UINT) this->hidden->sound,
&caps, sizeof(caps));
257
if (result != MMSYSERR_NOERROR) {
258
WINWAVEOUT_CloseDevice(this);
259
SetMMerror("waveOutGetDevCaps()", result);
260
return 0;
261
262
263
}
printf("Audio device: %s\n", caps.szPname);
}
264
265
#endif
266
/* Create the audio buffer semaphore */
267
this->hidden->audio_sem =
268
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
269
CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
270
#else
271
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
272
#endif
273
274
if (this->hidden->audio_sem == NULL) {
WINWAVEOUT_CloseDevice(this);
275
SDL_SetError("Couldn't create semaphore");
276
return 0;
277
278
279
}
/* Create the sound buffers */
280
281
this->hidden->mixbuf =
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
282
if (this->hidden->mixbuf == NULL) {
283
284
285
WINWAVEOUT_CloseDevice(this);
SDL_OutOfMemory();
return 0;
286
287
}
for (i = 0; i < NUM_BUFFERS; ++i) {
288
SDL_memset(&this->hidden->wavebuf[i], '\0',
289
sizeof(this->hidden->wavebuf[i]));
290
291
292
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
293
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
294
295
result = waveOutPrepareHeader(this->hidden->sound,
&this->hidden->wavebuf[i],
296
sizeof(this->hidden->wavebuf[i]));
297
if (result != MMSYSERR_NOERROR) {
298
WINWAVEOUT_CloseDevice(this);
299
SetMMerror("waveOutPrepareHeader()", result);
300
return 0;
301
302
303
}
}
304
return 1; /* Ready to go! */
305
}
306
307
308
static int
309
WINWAVEOUT_Init(SDL_AudioDriverImpl * impl)
310
311
312
313
314
315
316
317
318
{
/* Set the function pointers */
impl->OpenDevice = WINWAVEOUT_OpenDevice;
impl->ThreadInit = WINWAVEOUT_ThreadInit;
impl->PlayDevice = WINWAVEOUT_PlayDevice;
impl->WaitDevice = WINWAVEOUT_WaitDevice;
impl->WaitDone = WINWAVEOUT_WaitDone;
impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf;
impl->CloseDevice = WINWAVEOUT_CloseDevice;
319
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */
320
321
return 1; /* this audio target is available. */
322
323
324
325
326
327
}
AudioBootStrap WINWAVEOUT_bootstrap = {
"waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0
};
328
/* vi: set ts=4 sw=4 expandtab: */