This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_dibaudio.c
338 lines (290 loc) · 9.78 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2009 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
/* Allow access to a raw mixing buffer */
26
27
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
28
29
30
#include <mmsystem.h>
#include "SDL_timer.h"
31
#include "SDL_audio.h"
32
#include "../SDL_audio_c.h"
33
#include "SDL_dibaudio.h"
34
35
36
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
#include "win_ce_semaphore.h"
#endif
38
39
40
41
42
43
44
#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
45
46
/* The Win32 callback for filling the WAVE device */
47
48
49
static void CALLBACK
FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD dwParam1, DWORD dwParam2)
51
SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
53
54
55
/* Only service "buffer done playing" messages */
if (uMsg != WOM_DONE)
return;
57
/* Signal that we are done playing a buffer */
58
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
59
ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
61
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
63
64
}
65
66
static void
SetMMerror(char *function, MMRESULT code)
68
69
size_t len;
char errbuf[MAXERRORLENGTH];
70
#ifdef _WIN32_WCE
71
wchar_t werrbuf[MAXERRORLENGTH];
74
75
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
len = SDL_strlen(errbuf);
76
77
#ifdef _WIN32_WCE
78
79
80
81
/* UNICODE version */
waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
MAXERRORLENGTH - len, NULL, NULL);
83
waveOutGetErrorText(code, errbuf + len, (UINT) (MAXERRORLENGTH - len));
86
SDL_SetError("%s", errbuf);
87
88
89
}
/* Set high priority for the audio thread */
91
WINWAVEOUT_ThreadInit(_THIS)
93
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
94
95
}
97
WINWAVEOUT_WaitDevice(_THIS)
99
/* Wait for an audio chunk to finish */
100
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
101
WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
103
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
105
106
}
108
WINWAVEOUT_GetDeviceBuf(_THIS)
109
{
110
111
return (Uint8 *) (this->hidden->
wavebuf[this->hidden->next_buffer].lpData);
112
113
}
115
WINWAVEOUT_PlayDevice(_THIS)
116
{
117
/* Queue it up */
118
119
waveOutWrite(this->hidden->sound,
&this->hidden->wavebuf[this->hidden->next_buffer],
120
sizeof(this->hidden->wavebuf[0]));
121
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
122
123
}
125
WINWAVEOUT_WaitDone(_THIS)
126
{
127
128
129
130
131
int i, left;
do {
left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) {
132
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
133
134
135
136
137
138
--left;
}
}
if (left > 0) {
SDL_Delay(100);
}
139
} while (left > 0);
140
141
}
143
WINWAVEOUT_CloseDevice(_THIS)
144
{
145
/* Close up audio */
146
147
148
149
if (this->hidden != NULL) {
int i;
if (this->hidden->audio_sem) {
150
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
151
CloseSynchHandle(this->hidden->audio_sem);
153
CloseHandle(this->hidden->audio_sem);
155
156
this->hidden->audio_sem = 0;
}
158
159
160
if (this->hidden->sound) {
waveOutClose(this->hidden->sound);
this->hidden->sound = 0;
162
163
164
165
166
167
/* 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],
168
sizeof(this->hidden->wavebuf[i]));
169
170
171
172
173
174
175
176
177
178
179
180
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;
182
183
}
185
WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
186
{
187
188
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
189
190
MMRESULT result;
WAVEFORMATEX waveformat;
191
192
193
194
int i;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
195
SDL_malloc((sizeof *this->hidden));
196
197
198
199
200
if (this->hidden == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
201
202
203
/* Initialize the wavebuf structures for closing */
for (i = 0; i < NUM_BUFFERS; ++i)
204
205
206
207
this->hidden->wavebuf[i].dwUser = 0xFFFF;
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
208
this->spec.format = test_format;
209
switch (test_format) {
210
211
212
213
214
215
216
217
218
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
break; /* valid. */
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
219
220
221
222
223
224
225
226
}
}
if (!valid_datatype) {
WINWAVEOUT_CloseDevice(this);
SDL_SetError("Unsupported audio format");
return 0;
}
227
228
/* Set basic WAVE format parameters */
229
SDL_memset(&waveformat, '\0', sizeof(waveformat));
230
waveformat.wFormatTag = WAVE_FORMAT_PCM;
231
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
233
if (this->spec.channels > 2)
234
this->spec.channels = 2; /* !!! FIXME: is this right? */
235
236
237
waveformat.nChannels = this->spec.channels;
waveformat.nSamplesPerSec = this->spec.freq;
238
239
240
241
242
243
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
244
245
if (this->spec.samples < (this->spec.freq / 4))
this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
246
247
/* Update the fragment size as size in bytes */
248
SDL_CalculateAudioSpec(&this->spec);
249
250
/* Open the audio device */
251
result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
252
253
254
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
255
WINWAVEOUT_CloseDevice(this);
256
SetMMerror("waveOutOpen()", result);
259
#ifdef SOUND_DEBUG
260
261
262
263
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
264
265
result = waveOutGetDevCaps((UINT) this->hidden->sound,
&caps, sizeof(caps));
266
if (result != MMSYSERR_NOERROR) {
267
WINWAVEOUT_CloseDevice(this);
268
SetMMerror("waveOutGetDevCaps()", result);
270
271
272
}
printf("Audio device: %s\n", caps.szPname);
}
273
274
#endif
275
/* Create the audio buffer semaphore */
276
this->hidden->audio_sem =
277
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
278
CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
280
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
282
283
if (this->hidden->audio_sem == NULL) {
WINWAVEOUT_CloseDevice(this);
284
SDL_SetError("Couldn't create semaphore");
286
287
288
}
/* Create the sound buffers */
289
290
this->hidden->mixbuf =
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
291
if (this->hidden->mixbuf == NULL) {
292
293
294
WINWAVEOUT_CloseDevice(this);
SDL_OutOfMemory();
return 0;
295
296
}
for (i = 0; i < NUM_BUFFERS; ++i) {
297
SDL_memset(&this->hidden->wavebuf[i], '\0',
298
sizeof(this->hidden->wavebuf[i]));
299
300
301
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
302
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
303
304
result = waveOutPrepareHeader(this->hidden->sound,
&this->hidden->wavebuf[i],
305
sizeof(this->hidden->wavebuf[i]));
306
if (result != MMSYSERR_NOERROR) {
307
WINWAVEOUT_CloseDevice(this);
308
SetMMerror("waveOutPrepareHeader()", result);
313
return 1; /* Ready to go! */
314
}
318
WINWAVEOUT_Init(SDL_AudioDriverImpl * impl)
319
320
321
322
323
324
325
326
327
{
/* 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;
328
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */
330
/* !!! FIXME: not right for device enum? */
331
332
333
334
335
336
337
return 1;
}
AudioBootStrap WINWAVEOUT_bootstrap = {
"waveout", WINDOWS_OS_NAME " WaveOut", WINWAVEOUT_Init, 0
};
338
/* vi: set ts=4 sw=4 expandtab: */