zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_winmm.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
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.
8 
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:
12 
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.
20 */
21 #include "SDL_config.h"
22 
23 #if SDL_AUDIO_DRIVER_WINMM
24 
25 /* Allow access to a raw mixing buffer */
26 
27 #include "../../core/windows/SDL_windows.h"
28 #include <mmsystem.h>
29 
30 #include "SDL_timer.h"
31 #include "SDL_audio.h"
32 #include "../SDL_audio_c.h"
33 #include "SDL_winmm.h"
34 
35 #ifndef WAVE_FORMAT_IEEE_FLOAT
36 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
37 #endif
38 
39 #define DETECT_DEV_IMPL(typ, capstyp) \
40 static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \
41  const UINT devcount = wave##typ##GetNumDevs(); \
42  capstyp caps; \
43  UINT i; \
44  for (i = 0; i < devcount; i++) { \
45  if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
46  char *name = WIN_StringToUTF8(caps.szPname); \
47  if (name != NULL) { \
48  addfn(name); \
49  SDL_free(name); \
50  } \
51  } \
52  } \
53 }
54 
55 DETECT_DEV_IMPL(Out, WAVEOUTCAPS)
56 DETECT_DEV_IMPL(In, WAVEINCAPS)
57 
58 static void
59 WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
60 {
61  if (iscapture) {
62  DetectWaveInDevs(addfn);
63  } else {
64  DetectWaveOutDevs(addfn);
65  }
66 }
67 
68 static void CALLBACK
69 CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
70  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
71 {
72  SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
73 
74  /* Only service "buffer is filled" messages */
75  if (uMsg != WIM_DATA)
76  return;
77 
78  /* Signal that we have a new buffer of data */
79  ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
80 }
81 
82 
83 /* The Win32 callback for filling the WAVE device */
84 static void CALLBACK
85 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
86  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
87 {
88  SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
89 
90  /* Only service "buffer done playing" messages */
91  if (uMsg != WOM_DONE)
92  return;
93 
94  /* Signal that we are done playing a buffer */
95  ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
96 }
97 
98 static int
99 SetMMerror(char *function, MMRESULT code)
100 {
101  size_t len;
102  char errbuf[MAXERRORLENGTH];
103  wchar_t werrbuf[MAXERRORLENGTH];
104 
105  SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
106  len = SDL_strlen(errbuf);
107 
108  waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
109  WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
110  MAXERRORLENGTH - len, NULL, NULL);
111 
112  return SDL_SetError("%s", errbuf);
113 }
114 
115 static void
116 WINMM_WaitDevice(_THIS)
117 {
118  /* Wait for an audio chunk to finish */
119  WaitForSingleObject(this->hidden->audio_sem, INFINITE);
120 }
121 
122 static Uint8 *
123 WINMM_GetDeviceBuf(_THIS)
124 {
125  return (Uint8 *) (this->hidden->
126  wavebuf[this->hidden->next_buffer].lpData);
127 }
128 
129 static void
130 WINMM_PlayDevice(_THIS)
131 {
132  /* Queue it up */
133  waveOutWrite(this->hidden->hout,
134  &this->hidden->wavebuf[this->hidden->next_buffer],
135  sizeof(this->hidden->wavebuf[0]));
136  this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
137 }
138 
139 static void
140 WINMM_WaitDone(_THIS)
141 {
142  int i, left;
143 
144  do {
145  left = NUM_BUFFERS;
146  for (i = 0; i < NUM_BUFFERS; ++i) {
147  if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
148  --left;
149  }
150  }
151  if (left > 0) {
152  SDL_Delay(100);
153  }
154  } while (left > 0);
155 }
156 
157 static void
158 WINMM_CloseDevice(_THIS)
159 {
160  /* Close up audio */
161  if (this->hidden != NULL) {
162  int i;
163 
164  if (this->hidden->audio_sem) {
165  CloseHandle(this->hidden->audio_sem);
166  this->hidden->audio_sem = 0;
167  }
168 
169  /* Clean up mixing buffers */
170  for (i = 0; i < NUM_BUFFERS; ++i) {
171  if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
172  waveOutUnprepareHeader(this->hidden->hout,
173  &this->hidden->wavebuf[i],
174  sizeof(this->hidden->wavebuf[i]));
175  this->hidden->wavebuf[i].dwUser = 0xFFFF;
176  }
177  }
178 
179  /* Free raw mixing buffer */
180  SDL_free(this->hidden->mixbuf);
181  this->hidden->mixbuf = NULL;
182 
183  if (this->hidden->hin) {
184  waveInClose(this->hidden->hin);
185  this->hidden->hin = 0;
186  }
187 
188  if (this->hidden->hout) {
189  waveOutClose(this->hidden->hout);
190  this->hidden->hout = 0;
191  }
192 
193  SDL_free(this->hidden);
194  this->hidden = NULL;
195  }
196 }
197 
198 static SDL_bool
199 PrepWaveFormat(_THIS, UINT_PTR devId, WAVEFORMATEX *pfmt, const int iscapture)
200 {
201  SDL_zerop(pfmt);
202 
203  if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
205  } else {
206  pfmt->wFormatTag = WAVE_FORMAT_PCM;
207  }
208  pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
209 
210  pfmt->nChannels = this->spec.channels;
211  pfmt->nSamplesPerSec = this->spec.freq;
212  pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
213  pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
214 
215  if (iscapture) {
216  return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
217  } else {
218  return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
219  }
220 }
221 
222 static int
223 WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
224 {
225  SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
226  int valid_datatype = 0;
227  MMRESULT result;
228  WAVEFORMATEX waveformat;
229  UINT_PTR devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
230  char *utf8 = NULL;
231  int i;
232 
233  if (devname != NULL) { /* specific device requested? */
234  if (iscapture) {
235  const int devcount = (int) waveInGetNumDevs();
236  WAVEINCAPS caps;
237  for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
238  result = waveInGetDevCaps(i, &caps, sizeof (caps));
239  if (result != MMSYSERR_NOERROR)
240  continue;
241  else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
242  continue;
243  else if (SDL_strcmp(devname, utf8) == 0)
244  devId = (UINT_PTR) i;
245  SDL_free(utf8);
246  }
247  } else {
248  const int devcount = (int) waveOutGetNumDevs();
249  WAVEOUTCAPS caps;
250  for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
251  result = waveOutGetDevCaps(i, &caps, sizeof (caps));
252  if (result != MMSYSERR_NOERROR)
253  continue;
254  else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
255  continue;
256  else if (SDL_strcmp(devname, utf8) == 0)
257  devId = (UINT_PTR) i;
258  SDL_free(utf8);
259  }
260  }
261 
262  if (devId == WAVE_MAPPER) {
263  return SDL_SetError("Requested device not found");
264  }
265  }
266 
267  /* Initialize all variables that we clean on shutdown */
268  this->hidden = (struct SDL_PrivateAudioData *)
269  SDL_malloc((sizeof *this->hidden));
270  if (this->hidden == NULL) {
271  return SDL_OutOfMemory();
272  }
273  SDL_memset(this->hidden, 0, (sizeof *this->hidden));
274 
275  /* Initialize the wavebuf structures for closing */
276  for (i = 0; i < NUM_BUFFERS; ++i)
277  this->hidden->wavebuf[i].dwUser = 0xFFFF;
278 
279  if (this->spec.channels > 2)
280  this->spec.channels = 2; /* !!! FIXME: is this right? */
281 
282  /* Check the buffer size -- minimum of 1/4 second (word aligned) */
283  if (this->spec.samples < (this->spec.freq / 4))
284  this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
285 
286  while ((!valid_datatype) && (test_format)) {
287  switch (test_format) {
288  case AUDIO_U8:
289  case AUDIO_S16:
290  case AUDIO_S32:
291  case AUDIO_F32:
292  this->spec.format = test_format;
293  if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
294  valid_datatype = 1;
295  } else {
296  test_format = SDL_NextAudioFormat();
297  }
298  break;
299 
300  default:
301  test_format = SDL_NextAudioFormat();
302  break;
303  }
304  }
305 
306  if (!valid_datatype) {
307  WINMM_CloseDevice(this);
308  return SDL_SetError("Unsupported audio format");
309  }
310 
311  /* Update the fragment size as size in bytes */
312  SDL_CalculateAudioSpec(&this->spec);
313 
314  /* Open the audio device */
315  if (iscapture) {
316  result = waveInOpen(&this->hidden->hin, devId, &waveformat,
317  (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
318  CALLBACK_FUNCTION);
319  } else {
320  result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
321  (DWORD_PTR) FillSound, (DWORD_PTR) this,
322  CALLBACK_FUNCTION);
323  }
324 
325  if (result != MMSYSERR_NOERROR) {
326  WINMM_CloseDevice(this);
327  return SetMMerror("waveOutOpen()", result);
328  }
329 #ifdef SOUND_DEBUG
330  /* Check the sound device we retrieved */
331  {
332  WAVEOUTCAPS caps;
333 
334  result = waveOutGetDevCaps((UINT) this->hidden->hout,
335  &caps, sizeof(caps));
336  if (result != MMSYSERR_NOERROR) {
337  WINMM_CloseDevice(this);
338  return SetMMerror("waveOutGetDevCaps()", result);
339  }
340  printf("Audio device: %s\n", caps.szPname);
341  }
342 #endif
343 
344  /* Create the audio buffer semaphore */
345  this->hidden->audio_sem =
346  CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
347  if (this->hidden->audio_sem == NULL) {
348  WINMM_CloseDevice(this);
349  return SDL_SetError("Couldn't create semaphore");
350  }
351 
352  /* Create the sound buffers */
353  this->hidden->mixbuf =
354  (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
355  if (this->hidden->mixbuf == NULL) {
356  WINMM_CloseDevice(this);
357  return SDL_OutOfMemory();
358  }
359  for (i = 0; i < NUM_BUFFERS; ++i) {
360  SDL_memset(&this->hidden->wavebuf[i], 0,
361  sizeof(this->hidden->wavebuf[i]));
362  this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
363  this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
364  this->hidden->wavebuf[i].lpData =
365  (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
366  result = waveOutPrepareHeader(this->hidden->hout,
367  &this->hidden->wavebuf[i],
368  sizeof(this->hidden->wavebuf[i]));
369  if (result != MMSYSERR_NOERROR) {
370  WINMM_CloseDevice(this);
371  return SetMMerror("waveOutPrepareHeader()", result);
372  }
373  }
374 
375  return 0; /* Ready to go! */
376 }
377 
378 
379 static int
380 WINMM_Init(SDL_AudioDriverImpl * impl)
381 {
382  /* Set the function pointers */
383  impl->DetectDevices = WINMM_DetectDevices;
384  impl->OpenDevice = WINMM_OpenDevice;
385  impl->PlayDevice = WINMM_PlayDevice;
386  impl->WaitDevice = WINMM_WaitDevice;
387  impl->WaitDone = WINMM_WaitDone;
388  impl->GetDeviceBuf = WINMM_GetDeviceBuf;
389  impl->CloseDevice = WINMM_CloseDevice;
390 
391  return 1; /* this audio target is available. */
392 }
393 
395  "winmm", "Windows Waveform Audio", WINMM_Init, 0
396 };
397 
398 #endif /* SDL_AUDIO_DRIVER_WINMM */
399 
400 /* vi: set ts=4 sw=4 expandtab: */
void(* CloseDevice)(_THIS)
Definition: SDL_sysaudio.h:45
#define NUM_BUFFERS
Definition: alstream.c:48
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
Definition: SDL_audio.c:1226
WORD nChannels
Definition: audiodefs.h:43
void(* SDL_AddAudioDevice)(const char *name)
Definition: SDL_sysaudio.h:34
GLint left
Definition: glew.h:7291
void(* WaitDevice)(_THIS)
Definition: SDL_sysaudio.h:41
#define NULL
Definition: ftobjs.h:61
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
Definition: SDL_string.c:1277
DWORD nAvgBytesPerSec
Definition: audiodefs.h:45
SDL_bool
Definition: SDL_stdinc.h:116
Uint8 *(* GetDeviceBuf)(_THIS)
Definition: SDL_sysaudio.h:43
DECLSPEC void SDLCALL SDL_free(void *mem)
Uint16 SDL_AudioFormat
Audio format flags.
Definition: SDL_audio.h:64
GLenum GLsizei len
Definition: glew.h:7035
void(* WaitDone)(_THIS)
Definition: SDL_sysaudio.h:44
typedef UINT(WINAPI *PFNWGLGETCONTEXTGPUIDAMDPROC)(HGLRC hglrc)
if(!yyg->yy_init)
AudioBootStrap WINMM_bootstrap
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
Definition: SDL_sysaudio.h:39
SDL_AudioFormat SDL_NextAudioFormat(void)
Definition: SDL_audio.c:1238
#define SDL_AUDIO_ISFLOAT(x)
Definition: SDL_audio.h:76
void(* PlayDevice)(_THIS)
Definition: SDL_sysaudio.h:42
#define AUDIO_U8
Definition: SDL_audio.h:89
void(* DetectDevices)(int iscapture, SDL_AddAudioDevice addfn)
Definition: SDL_sysaudio.h:38
GLuint64EXT * result
Definition: glew.h:12708
int
Definition: SDL_systhread.c:37
#define _THIS
#define SDL_AUDIO_BITSIZE(x)
Definition: SDL_audio.h:75
#define AUDIO_S32
Definition: SDL_audio.h:105
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
Wait a specified number of milliseconds before returning.
Definition: SDL_systimer.c:70
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:41
WORD nBlockAlign
Definition: audiodefs.h:46
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
Definition: SDL_audio.c:1247
#define WAVE_FORMAT_PCM
Definition: makehrtf.c:177
DWORD nSamplesPerSec
Definition: audiodefs.h:44
DECLSPEC size_t SDLCALL SDL_strlen(const char *str)
Definition: SDL_string.c:389
Definition: inftrees.h:24
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
#define WAVE_FORMAT_IEEE_FLOAT
Definition: winmm.c:34
WORD wBitsPerSample
Definition: audiodefs.h:47
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
WORD wFormatTag
Definition: audiodefs.h:42
#define SDL_zerop(x)
Definition: SDL_stdinc.h:255
#define AUDIO_S16
Definition: SDL_audio.h:96
#define AUDIO_F32
Definition: SDL_audio.h:114
int i
Definition: pngrutil.c:1377