2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
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.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 /* Allow access to a raw mixing buffer */
27 #include "SDL_audio_c.h"
28 #include "SDL_audiomem.h"
29 #include "SDL_sysaudio.h"
32 // We'll need the DosSetPriority() API!
33 #define INCL_DOSPROCESS
37 /* Available audio drivers */
38 static AudioBootStrap *bootstrap[] = {
39 #if SDL_AUDIO_DRIVER_OPENBSD
40 &OPENBSD_AUDIO_bootstrap,
42 #if SDL_AUDIO_DRIVER_OSS
46 #if SDL_AUDIO_DRIVER_ALSA
49 #if SDL_AUDIO_DRIVER_QNXNTO
50 &QNXNTOAUDIO_bootstrap,
52 #if SDL_AUDIO_DRIVER_SUNAUDIO
55 #if SDL_AUDIO_DRIVER_DMEDIA
58 #if SDL_AUDIO_DRIVER_ARTS
61 #if SDL_AUDIO_DRIVER_ESD
64 #if SDL_AUDIO_DRIVER_NAS
67 #if SDL_AUDIO_DRIVER_DSOUND
70 #if SDL_AUDIO_DRIVER_WAVEOUT
73 #if SDL_AUDIO_DRIVER_PAUD
76 #if SDL_AUDIO_DRIVER_BAUDIO
79 #if SDL_AUDIO_DRIVER_COREAUDIO
82 #if SDL_AUDIO_DRIVER_SNDMGR
85 #if SDL_AUDIO_DRIVER_AHI
88 #if SDL_AUDIO_DRIVER_MINT
89 &MINTAUDIO_GSXB_bootstrap,
90 &MINTAUDIO_MCSN_bootstrap,
91 &MINTAUDIO_STFA_bootstrap,
92 &MINTAUDIO_XBIOS_bootstrap,
93 &MINTAUDIO_DMA8_bootstrap,
95 #if SDL_AUDIO_DRIVER_DISK
98 #if SDL_AUDIO_DRIVER_DC
101 #if SDL_AUDIO_DRIVER_MMEAUDIO
104 #if SDL_AUDIO_DRIVER_DART
109 SDL_AudioDevice *current_audio = NULL;
111 /* Various local functions */
112 int SDL_AudioInit(const char *driver_name);
113 void SDL_AudioQuit(void);
115 #if SDL_AUDIO_DRIVER_AHI
116 static int audio_configured = 0;
119 /* The general mixing thread function */
120 int SDL_RunAudio(void *audiop)
122 SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
126 void (*fill)(void *userdata,Uint8 *stream, int len);
128 #if SDL_AUDIO_DRIVER_AHI
131 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
133 D(bug("Task audio started audio struct:<%lx>...\n",audiop));
135 D(bug("Before Openaudio..."));
136 if(audio->OpenAudio(audio, &audio->spec)==-1)
138 D(bug("Open audio failed...\n"));
141 D(bug("OpenAudio...OK\n"));
144 /* Perform any thread setup */
145 if ( audio->ThreadInit ) {
146 audio->ThreadInit(audio);
148 audio->threadid = SDL_ThreadID();
150 /* Set up the mixing function */
151 fill = audio->spec.callback;
152 udata = audio->spec.userdata;
154 #if SDL_AUDIO_DRIVER_AHI
155 audio_configured = 1;
157 D(bug("Audio configured... Checking for conversion\n"));
158 SDL_mutexP(audio->mixer_lock);
159 D(bug("Semaphore obtained...\n"));
162 if ( audio->convert.needed ) {
163 if ( audio->convert.src_format == AUDIO_U8 ) {
168 stream_len = audio->convert.len;
170 silence = audio->spec.silence;
171 stream_len = audio->spec.size;
173 stream = audio->fake_stream;
175 #if SDL_AUDIO_DRIVER_AHI
176 SDL_mutexV(audio->mixer_lock);
177 D(bug("Entering audio loop...\n"));
181 // Increase the priority of this thread to make sure that
182 // the audio will be continuous all the time!
183 #ifdef USE_DOSSETPRIORITY
185 printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
187 DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
191 /* Loop, filling the audio buffers */
192 while ( audio->enabled ) {
194 /* Wait for new current buffer to finish playing */
195 if ( stream == audio->fake_stream ) {
196 SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
198 #if SDL_AUDIO_DRIVER_AHI
201 audio->WaitAudio(audio);
204 /* Fill the current buffer with sound */
205 if ( audio->convert.needed ) {
206 if ( audio->convert.buf ) {
207 stream = audio->convert.buf;
212 stream = audio->GetAudioBuf(audio);
213 if ( stream == NULL ) {
214 stream = audio->fake_stream;
217 SDL_memset(stream, silence, stream_len);
219 if ( ! audio->paused ) {
220 SDL_mutexP(audio->mixer_lock);
221 (*fill)(udata, stream, stream_len);
222 SDL_mutexV(audio->mixer_lock);
225 /* Convert the audio if necessary */
226 if ( audio->convert.needed ) {
227 SDL_ConvertAudio(&audio->convert);
228 stream = audio->GetAudioBuf(audio);
229 if ( stream == NULL ) {
230 stream = audio->fake_stream;
232 SDL_memcpy(stream, audio->convert.buf,
233 audio->convert.len_cvt);
236 /* Ready current buffer for play and change current buffer */
237 if ( stream != audio->fake_stream ) {
238 audio->PlayAudio(audio);
239 #if SDL_AUDIO_DRIVER_AHI
240 /* AmigaOS don't have to wait the first time audio is played! */
245 /* Wait for the audio to drain.. */
246 if ( audio->WaitDone ) {
247 audio->WaitDone(audio);
250 #if SDL_AUDIO_DRIVER_AHI
251 D(bug("WaitAudio...Done\n"));
253 audio->CloseAudio(audio);
255 D(bug("CloseAudio..Done, subtask exiting...\n"));
256 audio_configured = 0;
260 printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
266 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
268 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
271 SDL_mutexP(audio->mixer_lock);
274 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
276 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
279 SDL_mutexV(audio->mixer_lock);
282 int SDL_AudioInit(const char *driver_name)
284 SDL_AudioDevice *audio;
287 /* Check to make sure we don't overwrite 'current_audio' */
288 if ( current_audio != NULL ) {
292 /* Select the proper audio driver */
295 #if SDL_AUDIO_DRIVER_ESD
296 if ( (driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL) ) {
297 /* Ahem, we know that if ESPEAKER is set, user probably wants
298 to use ESD, but don't start it if it's not already running.
299 This probably isn't the place to do this, but... Shh! :)
301 for ( i=0; bootstrap[i]; ++i ) {
302 if ( SDL_strcmp(bootstrap[i]->name, "esd") == 0 ) {
304 const char *esd_no_spawn;
306 /* Don't start ESD if it's not running */
307 esd_no_spawn = getenv("ESD_NO_SPAWN");
308 if ( esd_no_spawn == NULL ) {
309 putenv("ESD_NO_SPAWN=1");
312 if ( bootstrap[i]->available() ) {
313 audio = bootstrap[i]->create(0);
317 if ( esd_no_spawn == NULL ) {
318 unsetenv("ESD_NO_SPAWN");
324 #endif /* SDL_AUDIO_DRIVER_ESD */
325 if ( audio == NULL ) {
326 if ( driver_name != NULL ) {
327 #if 0 /* This will be replaced with a better driver selection API */
328 if ( SDL_strrchr(driver_name, ':') != NULL ) {
329 idx = atoi(SDL_strrchr(driver_name, ':')+1);
332 for ( i=0; bootstrap[i]; ++i ) {
333 if (SDL_strncmp(bootstrap[i]->name, driver_name,
334 SDL_strlen(bootstrap[i]->name)) == 0) {
335 if ( bootstrap[i]->available() ) {
336 audio=bootstrap[i]->create(idx);
342 for ( i=0; bootstrap[i]; ++i ) {
343 if ( bootstrap[i]->available() ) {
344 audio = bootstrap[i]->create(idx);
345 if ( audio != NULL ) {
351 if ( audio == NULL ) {
352 SDL_SetError("No available audio device");
353 #if 0 /* Don't fail SDL_Init() if audio isn't available.
354 SDL_OpenAudio() will handle it at that point. *sigh*
360 current_audio = audio;
361 if ( current_audio ) {
362 current_audio->name = bootstrap[i]->name;
363 if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
364 current_audio->LockAudio = SDL_LockAudio_Default;
365 current_audio->UnlockAudio = SDL_UnlockAudio_Default;
371 char *SDL_AudioDriverName(char *namebuf, int maxlen)
373 if ( current_audio != NULL ) {
374 SDL_strlcpy(namebuf, current_audio->name, maxlen);
380 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
382 SDL_AudioDevice *audio;
384 /* Start up the audio driver, if necessary */
385 if ( ! current_audio ) {
386 if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
387 (current_audio == NULL) ) {
391 audio = current_audio;
394 SDL_SetError("Audio device is already opened");
398 /* Verify some parameters */
399 if ( desired->callback == NULL ) {
400 SDL_SetError("SDL_OpenAudio() passed a NULL callback");
403 switch ( desired->channels ) {
406 case 4: /* surround */
407 case 6: /* surround with center and lfe */
410 SDL_SetError("1 (mono) and 2 (stereo) channels supported");
414 #if defined(__MACOS__) || (defined(__RISCOS__) && SDL_THREADS_DISABLED)
415 /* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
417 #if defined(__MINT__) && SDL_THREADS_DISABLED
418 /* Uses interrupt driven audio, without thread */
420 /* Create a semaphore for locking the sound buffers */
421 audio->mixer_lock = SDL_CreateMutex();
422 if ( audio->mixer_lock == NULL ) {
423 SDL_SetError("Couldn't create mixer lock");
427 #endif /* __MINT__ */
428 #endif /* __MACOS__ */
430 /* Calculate the silence and size of the audio specification */
431 SDL_CalculateAudioSpec(desired);
433 /* Open the audio subsystem */
434 SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
435 audio->convert.needed = 0;
439 #if !SDL_AUDIO_DRIVER_AHI
441 /* AmigaOS opens audio inside the main loop */
442 audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
444 if ( ! audio->opened ) {
449 D(bug("Locking semaphore..."));
450 SDL_mutexP(audio->mixer_lock);
453 audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
454 D(bug("Created thread...\n"));
456 if ( audio->thread == NULL ) {
457 SDL_mutexV(audio->mixer_lock);
459 SDL_SetError("Couldn't create audio thread");
463 while(!audio_configured)
467 /* If the audio driver changes the buffer size, accept it */
468 if ( audio->spec.samples != desired->samples ) {
469 desired->samples = audio->spec.samples;
470 SDL_CalculateAudioSpec(desired);
473 /* Allocate a fake audio memory buffer */
474 audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
475 if ( audio->fake_stream == NULL ) {
481 /* See if we need to do any conversion */
482 if ( obtained != NULL ) {
483 SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
484 } else if ( desired->freq != audio->spec.freq ||
485 desired->format != audio->spec.format ||
486 desired->channels != audio->spec.channels ) {
487 /* Build an audio conversion block */
488 if ( SDL_BuildAudioCVT(&audio->convert,
489 desired->format, desired->channels,
491 audio->spec.format, audio->spec.channels,
492 audio->spec.freq) < 0 ) {
496 if ( audio->convert.needed ) {
497 audio->convert.len = desired->size;
498 audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
499 audio->convert.len*audio->convert.len_mult);
500 if ( audio->convert.buf == NULL ) {
508 #if !SDL_AUDIO_DRIVER_AHI
509 /* Start the audio thread if necessary */
510 switch (audio->opened) {
512 /* Start the audio thread */
513 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
514 #undef SDL_CreateThread
515 audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
517 audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
519 if ( audio->thread == NULL ) {
521 SDL_SetError("Couldn't create audio thread");
527 /* The audio is now playing */
531 SDL_mutexV(audio->mixer_lock);
532 D(bug("SDL_OpenAudio USCITA...\n"));
539 SDL_audiostatus SDL_GetAudioStatus(void)
541 SDL_AudioDevice *audio = current_audio;
542 SDL_audiostatus status;
544 status = SDL_AUDIO_STOPPED;
545 if ( audio && audio->enabled ) {
546 if ( audio->paused ) {
547 status = SDL_AUDIO_PAUSED;
549 status = SDL_AUDIO_PLAYING;
555 void SDL_PauseAudio (int pause_on)
557 SDL_AudioDevice *audio = current_audio;
560 audio->paused = pause_on;
564 void SDL_LockAudio (void)
566 SDL_AudioDevice *audio = current_audio;
568 /* Obtain a lock on the mixing buffers */
569 if ( audio && audio->LockAudio ) {
570 audio->LockAudio(audio);
574 void SDL_UnlockAudio (void)
576 SDL_AudioDevice *audio = current_audio;
578 /* Release lock on the mixing buffers */
579 if ( audio && audio->UnlockAudio ) {
580 audio->UnlockAudio(audio);
584 void SDL_CloseAudio (void)
586 SDL_QuitSubSystem(SDL_INIT_AUDIO);
589 void SDL_AudioQuit(void)
591 SDL_AudioDevice *audio = current_audio;
595 if ( audio->thread != NULL ) {
596 SDL_WaitThread(audio->thread, NULL);
598 if ( audio->mixer_lock != NULL ) {
599 SDL_DestroyMutex(audio->mixer_lock);
601 if ( audio->fake_stream != NULL ) {
602 SDL_FreeAudioMem(audio->fake_stream);
604 if ( audio->convert.needed ) {
605 SDL_FreeAudioMem(audio->convert.buf);
608 #if !SDL_AUDIO_DRIVER_AHI
609 if ( audio->opened ) {
610 audio->CloseAudio(audio);
614 /* Free the driver data */
616 current_audio = NULL;
620 #define NUM_FORMATS 6
621 static int format_idx;
622 static int format_idx_sub;
623 static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
624 { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
625 { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
626 { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
627 { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
628 { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
629 { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
632 Uint16 SDL_FirstAudioFormat(Uint16 format)
634 for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
635 if ( format_list[format_idx][0] == format ) {
640 return(SDL_NextAudioFormat());
643 Uint16 SDL_NextAudioFormat(void)
645 if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
648 return(format_list[format_idx][format_idx_sub++]);
651 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
653 switch (spec->format) {
655 spec->silence = 0x80;
658 spec->silence = 0x00;
661 spec->size = (spec->format&0xFF)/8;
662 spec->size *= spec->channels;
663 spec->size *= spec->samples;