Removed Windows CE support from SDL 2.0.
It's a long-dead platform, and we don't have any way to build for, test, or
maintain it, so there's no sense in doing acrobatics to support it.
If you need Windows CE support, use SDL 1.2. If you need Windows Phone support,
send SDL 2.0 patches for the newer Windows Mobile platform.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_config.h"
23 #if SDL_AUDIO_DRIVER_WINMM
25 /* Allow access to a raw mixing buffer */
27 #include "../../core/windows/SDL_windows.h"
30 #include "SDL_timer.h"
31 #include "SDL_audio.h"
32 #include "../SDL_audio_c.h"
33 #include "SDL_winmm.h"
35 #define DETECT_DEV_IMPL(typ, capstyp) \
36 static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \
37 const UINT devcount = wave##typ##GetNumDevs(); \
40 for (i = 0; i < devcount; i++) { \
41 if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
42 char *name = WIN_StringToUTF8(caps.szPname); \
51 DETECT_DEV_IMPL(Out, WAVEOUTCAPS)
52 DETECT_DEV_IMPL(In, WAVEINCAPS)
55 WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
58 DetectWaveInDevs(addfn);
60 DetectWaveOutDevs(addfn);
65 CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
66 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
68 SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
70 /* Only service "buffer is filled" messages */
74 /* Signal that we have a new buffer of data */
75 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
79 /* The Win32 callback for filling the WAVE device */
81 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
82 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
84 SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
86 /* Only service "buffer done playing" messages */
90 /* Signal that we are done playing a buffer */
91 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
95 SetMMerror(char *function, MMRESULT code)
98 char errbuf[MAXERRORLENGTH];
99 wchar_t werrbuf[MAXERRORLENGTH];
101 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
102 len = SDL_strlen(errbuf);
104 waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
105 WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
106 MAXERRORLENGTH - len, NULL, NULL);
108 SDL_SetError("%s", errbuf);
112 WINMM_WaitDevice(_THIS)
114 /* Wait for an audio chunk to finish */
115 WaitForSingleObject(this->hidden->audio_sem, INFINITE);
119 WINMM_GetDeviceBuf(_THIS)
121 return (Uint8 *) (this->hidden->
122 wavebuf[this->hidden->next_buffer].lpData);
126 WINMM_PlayDevice(_THIS)
129 waveOutWrite(this->hidden->hout,
130 &this->hidden->wavebuf[this->hidden->next_buffer],
131 sizeof(this->hidden->wavebuf[0]));
132 this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
136 WINMM_WaitDone(_THIS)
142 for (i = 0; i < NUM_BUFFERS; ++i) {
143 if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
154 WINMM_CloseDevice(_THIS)
157 if (this->hidden != NULL) {
160 if (this->hidden->audio_sem) {
161 CloseHandle(this->hidden->audio_sem);
162 this->hidden->audio_sem = 0;
165 if (this->hidden->hin) {
166 waveInClose(this->hidden->hin);
167 this->hidden->hin = 0;
170 if (this->hidden->hout) {
171 waveOutClose(this->hidden->hout);
172 this->hidden->hout = 0;
175 /* Clean up mixing buffers */
176 for (i = 0; i < NUM_BUFFERS; ++i) {
177 if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
178 waveOutUnprepareHeader(this->hidden->hout,
179 &this->hidden->wavebuf[i],
180 sizeof(this->hidden->wavebuf[i]));
181 this->hidden->wavebuf[i].dwUser = 0xFFFF;
185 if (this->hidden->mixbuf != NULL) {
186 /* Free raw mixing buffer */
187 SDL_free(this->hidden->mixbuf);
188 this->hidden->mixbuf = NULL;
191 SDL_free(this->hidden);
197 WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
199 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
200 int valid_datatype = 0;
202 WAVEFORMATEX waveformat;
203 UINT_PTR devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
207 if (devname != NULL) { /* specific device requested? */
209 const int devcount = (int) waveInGetNumDevs();
211 for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
212 result = waveInGetDevCaps(i, &caps, sizeof (caps));
213 if (result != MMSYSERR_NOERROR)
215 else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
217 else if (SDL_strcmp(devname, utf8) == 0)
218 devId = (UINT_PTR) i;
222 const int devcount = (int) waveOutGetNumDevs();
224 for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
225 result = waveOutGetDevCaps(i, &caps, sizeof (caps));
226 if (result != MMSYSERR_NOERROR)
228 else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
230 else if (SDL_strcmp(devname, utf8) == 0)
231 devId = (UINT_PTR) i;
236 if (devId == WAVE_MAPPER) {
237 SDL_SetError("Requested device not found");
242 /* Initialize all variables that we clean on shutdown */
243 this->hidden = (struct SDL_PrivateAudioData *)
244 SDL_malloc((sizeof *this->hidden));
245 if (this->hidden == NULL) {
249 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
251 /* Initialize the wavebuf structures for closing */
252 for (i = 0; i < NUM_BUFFERS; ++i)
253 this->hidden->wavebuf[i].dwUser = 0xFFFF;
255 while ((!valid_datatype) && (test_format)) {
257 this->spec.format = test_format;
258 switch (test_format) {
266 test_format = SDL_NextAudioFormat();
271 if (!valid_datatype) {
272 WINMM_CloseDevice(this);
273 SDL_SetError("Unsupported audio format");
277 /* Set basic WAVE format parameters */
278 SDL_memset(&waveformat, '\0', sizeof(waveformat));
279 waveformat.wFormatTag = WAVE_FORMAT_PCM;
280 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
282 if (this->spec.channels > 2)
283 this->spec.channels = 2; /* !!! FIXME: is this right? */
285 waveformat.nChannels = this->spec.channels;
286 waveformat.nSamplesPerSec = this->spec.freq;
287 waveformat.nBlockAlign =
288 waveformat.nChannels * (waveformat.wBitsPerSample / 8);
289 waveformat.nAvgBytesPerSec =
290 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
292 /* Check the buffer size -- minimum of 1/4 second (word aligned) */
293 if (this->spec.samples < (this->spec.freq / 4))
294 this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
296 /* Update the fragment size as size in bytes */
297 SDL_CalculateAudioSpec(&this->spec);
299 /* Open the audio device */
301 result = waveInOpen(&this->hidden->hin, devId, &waveformat,
302 (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
305 result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
306 (DWORD_PTR) FillSound, (DWORD_PTR) this,
310 if (result != MMSYSERR_NOERROR) {
311 WINMM_CloseDevice(this);
312 SetMMerror("waveOutOpen()", result);
316 /* Check the sound device we retrieved */
320 result = waveOutGetDevCaps((UINT) this->hidden->hout,
321 &caps, sizeof(caps));
322 if (result != MMSYSERR_NOERROR) {
323 WINMM_CloseDevice(this);
324 SetMMerror("waveOutGetDevCaps()", result);
327 printf("Audio device: %s\n", caps.szPname);
331 /* Create the audio buffer semaphore */
332 this->hidden->audio_sem =
333 CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
334 if (this->hidden->audio_sem == NULL) {
335 WINMM_CloseDevice(this);
336 SDL_SetError("Couldn't create semaphore");
340 /* Create the sound buffers */
341 this->hidden->mixbuf =
342 (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
343 if (this->hidden->mixbuf == NULL) {
344 WINMM_CloseDevice(this);
348 for (i = 0; i < NUM_BUFFERS; ++i) {
349 SDL_memset(&this->hidden->wavebuf[i], 0,
350 sizeof(this->hidden->wavebuf[i]));
351 this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
352 this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
353 this->hidden->wavebuf[i].lpData =
354 (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
355 result = waveOutPrepareHeader(this->hidden->hout,
356 &this->hidden->wavebuf[i],
357 sizeof(this->hidden->wavebuf[i]));
358 if (result != MMSYSERR_NOERROR) {
359 WINMM_CloseDevice(this);
360 SetMMerror("waveOutPrepareHeader()", result);
365 return 1; /* Ready to go! */
370 WINMM_Init(SDL_AudioDriverImpl * impl)
372 /* Set the function pointers */
373 impl->DetectDevices = WINMM_DetectDevices;
374 impl->OpenDevice = WINMM_OpenDevice;
375 impl->PlayDevice = WINMM_PlayDevice;
376 impl->WaitDevice = WINMM_WaitDevice;
377 impl->WaitDone = WINMM_WaitDone;
378 impl->GetDeviceBuf = WINMM_GetDeviceBuf;
379 impl->CloseDevice = WINMM_CloseDevice;
381 return 1; /* this audio target is available. */
384 AudioBootStrap WINMM_bootstrap = {
385 "winmm", "Windows Waveform Audio", WINMM_Init, 0
388 #endif /* SDL_AUDIO_DRIVER_WINMM */
390 /* vi: set ts=4 sw=4 expandtab: */