Removed unneeded audio buffer memset() for consistent behavior on all platforms.
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"
34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
35 #include "win_ce_semaphore.h"
38 #define DETECT_DEV_IMPL(typ, capstyp) \
39 static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \
40 const UINT devcount = wave##typ##GetNumDevs(); \
43 for (i = 0; i < devcount; i++) { \
44 if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
45 char *name = WIN_StringToUTF8(caps.szPname); \
54 DETECT_DEV_IMPL(Out, WAVEOUTCAPS)
55 DETECT_DEV_IMPL(In, WAVEINCAPS)
58 WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
61 DetectWaveInDevs(addfn);
63 DetectWaveOutDevs(addfn);
68 CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
69 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
71 SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
73 /* Only service "buffer is filled" messages */
77 /* Signal that we have a new buffer of data */
78 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
79 ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
81 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
86 /* The Win32 callback for filling the WAVE device */
88 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
89 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
91 SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
93 /* Only service "buffer done playing" messages */
97 /* Signal that we are done playing a buffer */
98 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
99 ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
101 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
106 SetMMerror(char *function, MMRESULT code)
109 char errbuf[MAXERRORLENGTH];
110 wchar_t werrbuf[MAXERRORLENGTH];
112 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
113 len = SDL_strlen(errbuf);
115 waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
116 WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
117 MAXERRORLENGTH - len, NULL, NULL);
119 SDL_SetError("%s", errbuf);
123 WINMM_WaitDevice(_THIS)
125 /* Wait for an audio chunk to finish */
126 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
127 WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
129 WaitForSingleObject(this->hidden->audio_sem, INFINITE);
134 WINMM_GetDeviceBuf(_THIS)
136 return (Uint8 *) (this->hidden->
137 wavebuf[this->hidden->next_buffer].lpData);
141 WINMM_PlayDevice(_THIS)
144 waveOutWrite(this->hidden->hout,
145 &this->hidden->wavebuf[this->hidden->next_buffer],
146 sizeof(this->hidden->wavebuf[0]));
147 this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
151 WINMM_WaitDone(_THIS)
157 for (i = 0; i < NUM_BUFFERS; ++i) {
158 if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
169 WINMM_CloseDevice(_THIS)
172 if (this->hidden != NULL) {
175 if (this->hidden->audio_sem) {
176 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
177 CloseSynchHandle(this->hidden->audio_sem);
179 CloseHandle(this->hidden->audio_sem);
181 this->hidden->audio_sem = 0;
184 if (this->hidden->hin) {
185 waveInClose(this->hidden->hin);
186 this->hidden->hin = 0;
189 if (this->hidden->hout) {
190 waveOutClose(this->hidden->hout);
191 this->hidden->hout = 0;
194 /* Clean up mixing buffers */
195 for (i = 0; i < NUM_BUFFERS; ++i) {
196 if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
197 waveOutUnprepareHeader(this->hidden->hout,
198 &this->hidden->wavebuf[i],
199 sizeof(this->hidden->wavebuf[i]));
200 this->hidden->wavebuf[i].dwUser = 0xFFFF;
204 if (this->hidden->mixbuf != NULL) {
205 /* Free raw mixing buffer */
206 SDL_free(this->hidden->mixbuf);
207 this->hidden->mixbuf = NULL;
210 SDL_free(this->hidden);
216 WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
218 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
219 int valid_datatype = 0;
221 WAVEFORMATEX waveformat;
222 UINT_PTR devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
226 if (devname != NULL) { /* specific device requested? */
228 const int devcount = (int) waveInGetNumDevs();
230 for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
231 result = waveInGetDevCaps(i, &caps, sizeof (caps));
232 if (result != MMSYSERR_NOERROR)
234 else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
236 else if (SDL_strcmp(devname, utf8) == 0)
237 devId = (UINT_PTR) i;
241 const int devcount = (int) waveOutGetNumDevs();
243 for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
244 result = waveOutGetDevCaps(i, &caps, sizeof (caps));
245 if (result != MMSYSERR_NOERROR)
247 else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
249 else if (SDL_strcmp(devname, utf8) == 0)
250 devId = (UINT_PTR) i;
255 if (devId == WAVE_MAPPER) {
256 SDL_SetError("Requested device not found");
261 /* Initialize all variables that we clean on shutdown */
262 this->hidden = (struct SDL_PrivateAudioData *)
263 SDL_malloc((sizeof *this->hidden));
264 if (this->hidden == NULL) {
268 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
270 /* Initialize the wavebuf structures for closing */
271 for (i = 0; i < NUM_BUFFERS; ++i)
272 this->hidden->wavebuf[i].dwUser = 0xFFFF;
274 while ((!valid_datatype) && (test_format)) {
276 this->spec.format = test_format;
277 switch (test_format) {
285 test_format = SDL_NextAudioFormat();
290 if (!valid_datatype) {
291 WINMM_CloseDevice(this);
292 SDL_SetError("Unsupported audio format");
296 /* Set basic WAVE format parameters */
297 SDL_memset(&waveformat, '\0', sizeof(waveformat));
298 waveformat.wFormatTag = WAVE_FORMAT_PCM;
299 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
301 if (this->spec.channels > 2)
302 this->spec.channels = 2; /* !!! FIXME: is this right? */
304 waveformat.nChannels = this->spec.channels;
305 waveformat.nSamplesPerSec = this->spec.freq;
306 waveformat.nBlockAlign =
307 waveformat.nChannels * (waveformat.wBitsPerSample / 8);
308 waveformat.nAvgBytesPerSec =
309 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
311 /* Check the buffer size -- minimum of 1/4 second (word aligned) */
312 if (this->spec.samples < (this->spec.freq / 4))
313 this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
315 /* Update the fragment size as size in bytes */
316 SDL_CalculateAudioSpec(&this->spec);
318 /* Open the audio device */
320 result = waveInOpen(&this->hidden->hin, devId, &waveformat,
321 (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
324 result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
325 (DWORD_PTR) FillSound, (DWORD_PTR) this,
329 if (result != MMSYSERR_NOERROR) {
330 WINMM_CloseDevice(this);
331 SetMMerror("waveOutOpen()", result);
335 /* Check the sound device we retrieved */
339 result = waveOutGetDevCaps((UINT) this->hidden->hout,
340 &caps, sizeof(caps));
341 if (result != MMSYSERR_NOERROR) {
342 WINMM_CloseDevice(this);
343 SetMMerror("waveOutGetDevCaps()", result);
346 printf("Audio device: %s\n", caps.szPname);
350 /* Create the audio buffer semaphore */
351 this->hidden->audio_sem =
352 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
353 CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
355 CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
357 if (this->hidden->audio_sem == NULL) {
358 WINMM_CloseDevice(this);
359 SDL_SetError("Couldn't create semaphore");
363 /* Create the sound buffers */
364 this->hidden->mixbuf =
365 (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
366 if (this->hidden->mixbuf == NULL) {
367 WINMM_CloseDevice(this);
371 for (i = 0; i < NUM_BUFFERS; ++i) {
372 SDL_memset(&this->hidden->wavebuf[i], 0,
373 sizeof(this->hidden->wavebuf[i]));
374 this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
375 this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
376 this->hidden->wavebuf[i].lpData =
377 (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
378 result = waveOutPrepareHeader(this->hidden->hout,
379 &this->hidden->wavebuf[i],
380 sizeof(this->hidden->wavebuf[i]));
381 if (result != MMSYSERR_NOERROR) {
382 WINMM_CloseDevice(this);
383 SetMMerror("waveOutPrepareHeader()", result);
388 return 1; /* Ready to go! */
393 WINMM_Init(SDL_AudioDriverImpl * impl)
395 /* Set the function pointers */
396 impl->DetectDevices = WINMM_DetectDevices;
397 impl->OpenDevice = WINMM_OpenDevice;
398 impl->PlayDevice = WINMM_PlayDevice;
399 impl->WaitDevice = WINMM_WaitDevice;
400 impl->WaitDone = WINMM_WaitDone;
401 impl->GetDeviceBuf = WINMM_GetDeviceBuf;
402 impl->CloseDevice = WINMM_CloseDevice;
404 return 1; /* this audio target is available. */
407 AudioBootStrap WINMM_bootstrap = {
408 "winmm", "Windows Waveform Audio", WINMM_Init, 0
411 #endif /* SDL_AUDIO_DRIVER_WINMM */
413 /* vi: set ts=4 sw=4 expandtab: */