2
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2004 Sam Lantinga
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 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
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public
16
License along with this library; if not, write to the Free
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
/* Allow access to a raw mixing buffer */
32
#include "Our_SDL_audio.h"
33
#include "SDL_audio_c.h"
34
#include "SDL_audiomem.h"
35
#include "SDL_sysaudio.h"
37
/* Available audio drivers */
38
static AudioBootStrap *bootstrap[] = {
39
#ifdef OPENBSD_AUDIO_SUPPORT
40
&OPENBSD_AUDIO_bootstrap_ours,
49
#ifdef QNXNTOAUDIO_SUPPORT
50
&QNXNTOAUDIO_bootstrap_ours,
52
#ifdef SUNAUDIO_SUPPORT
53
&SUNAUDIO_bootstrap_ours,
56
&DMEDIA_bootstrap_ours,
59
&ARTSC_bootstrap_ours,
68
&DSOUND_bootstrap_ours,
71
&WAVEOUT_bootstrap_ours,
74
&BAUDIO_bootstrap_ours,
79
#if defined(macintosh) || TARGET_API_MAC_CARBON
80
&SNDMGR_bootstrap_ours,
88
#ifdef MMEAUDIO_SUPPORT
89
&MMEAUDIO_bootstrap_ours,
91
#ifdef MINTAUDIO_SUPPORT
92
&MINTAUDIO_GSXB_bootstrap_ours,
93
&MINTAUDIO_MCSN_bootstrap_ours,
94
&MINTAUDIO_STFA_bootstrap_ours,
95
&MINTAUDIO_XBIOS_bootstrap_ours,
96
&MINTAUDIO_DMA8_bootstrap_ours,
98
#ifdef DISKAUD_SUPPORT
99
&DISKAUD_bootstrap_ours,
102
&DCAUD_bootstrap_ours,
104
#ifdef DRENDERER_SUPPORT
105
&DRENDERER_bootstrap_ours,
109
SDL_AudioDevice *current_audio = NULL;
111
/* Various local functions */
114
static int audio_configured = 0;
117
/* The general mixing thread function */
118
static int SDL_RunAudio(void *audiop)
120
SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
124
void (*fill)(void *userdata,Uint8 *stream, int len);
129
/* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
131
D(bug("Task audio started audio struct:<%lx>...\n",audiop));
133
D(bug("Before Openaudio..."));
134
if(audio->OpenAudio(audio, &audio->spec)==-1)
136
D(bug("Open audio failed...\n"));
139
D(bug("OpenAudio...OK\n"));
142
/* Perform any thread setup */
143
if ( audio->ThreadInit ) {
144
audio->ThreadInit(audio);
146
audio->threadid = SDL_ThreadID();
148
/* Set up the mixing function */
149
fill = audio->spec.callback;
150
udata = audio->spec.userdata;
153
audio_configured = 1;
155
D(bug("Audio configured... Checking for conversion\n"));
156
SDL_mutexP(audio->mixer_lock);
157
D(bug("Semaphore obtained...\n"));
160
if ( audio->convert.needed ) {
161
if ( audio->convert.src_format == AUDIO_U8 ) {
166
stream_len = audio->convert.len;
168
silence = audio->spec.silence;
169
stream_len = audio->spec.size;
172
stream = audio->GetAudioBuf(audio);
175
stream = audio->fake_stream;
178
SDL_mutexV(audio->mixer_lock);
179
D(bug("Entering audio loop...\n"));
183
/* Loop, filling the audio buffers */
184
while ( audio->enabled ) {
186
/* Wait for new current buffer to finish playing */
187
if ( stream == audio->fake_stream ) {
188
SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
193
audio->WaitAudio(audio);
196
/* Fill the current buffer with sound */
197
if ( audio->convert.needed ) {
198
if ( audio->convert.buf ) {
199
stream = audio->convert.buf;
204
stream = audio->GetAudioBuf(audio);
205
if ( stream == NULL ) {
206
stream = audio->fake_stream;
209
memset(stream, silence, stream_len);
211
if ( ! audio->paused ) {
212
SDL_mutexP(audio->mixer_lock);
213
(*fill)(udata, stream, stream_len);
214
SDL_mutexV(audio->mixer_lock);
217
/* Convert the audio if necessary */
218
if ( audio->convert.needed ) {
219
Our_SDL_ConvertAudio(&audio->convert);
220
stream = audio->GetAudioBuf(audio);
221
if ( stream == NULL ) {
222
stream = audio->fake_stream;
224
memcpy(stream, audio->convert.buf,
225
audio->convert.len_cvt);
228
/* Ready current buffer for play and change current buffer */
229
if ( stream != audio->fake_stream ) {
230
audio->PlayAudio(audio);
232
/* AmigaOS don't have to wait the first time audio is played! */
237
/* Wait for the audio to drain.. */
238
if ( audio->WaitDone ) {
239
audio->WaitDone(audio);
243
D(bug("WaitAudio...Done\n"));
245
audio->CloseAudio(audio);
247
D(bug("CloseAudio..Done, subtask exiting...\n"));
248
audio_configured = 0;
253
static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
255
if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
258
SDL_mutexP(audio->mixer_lock);
261
static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
263
if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
266
SDL_mutexV(audio->mixer_lock);
269
int Our_SDL_AudioInit(const char *driver_name)
271
SDL_AudioDevice *audio;
274
/* Check to make sure we don't overwrite 'current_audio' */
275
if ( current_audio != NULL ) {
279
/* Select the proper audio driver */
283
if ( (driver_name == NULL) && (getenv("ESPEAKER") != NULL) ) {
284
/* Ahem, we know that if ESPEAKER is set, user probably wants
285
to use ESD, but don't start it if it's not already running.
286
This probably isn't the place to do this, but... Shh! :)
288
for ( i=0; bootstrap[i]; ++i ) {
289
if ( strcmp(bootstrap[i]->name, "esd") == 0 ) {
290
const char *esd_no_spawn;
292
/* Don't start ESD if it's not running */
293
esd_no_spawn = getenv("ESD_NO_SPAWN");
294
if ( esd_no_spawn == NULL ) {
295
putenv("ESD_NO_SPAWN=1");
297
if ( bootstrap[i]->available() ) {
298
audio = bootstrap[i]->create(0);
301
#ifdef linux /* No unsetenv() on most platforms */
302
if ( esd_no_spawn == NULL ) {
303
unsetenv("ESD_NO_SPAWN");
310
if ( audio == NULL ) {
311
if ( driver_name != NULL ) {
312
#if 0 /* This will be replaced with a better driver selection API */
313
if ( strrchr(driver_name, ':') != NULL ) {
314
idx = atoi(strrchr(driver_name, ':')+1);
317
for ( i=0; bootstrap[i]; ++i ) {
318
if (strncmp(bootstrap[i]->name, driver_name,
319
strlen(bootstrap[i]->name)) == 0) {
320
if ( bootstrap[i]->available() ) {
321
audio=bootstrap[i]->create(idx);
327
for ( i=0; bootstrap[i]; ++i ) {
328
if ( bootstrap[i]->available() ) {
329
audio = bootstrap[i]->create(idx);
330
if ( audio != NULL ) {
336
if ( audio == NULL ) {
337
SDL_SetError("No available audio device");
338
#if 0 /* Don't fail SDL_Init() if audio isn't available.
339
SDL_OpenAudio() will handle it at that point. *sigh*
345
current_audio = audio;
346
if ( current_audio ) {
347
current_audio->name = bootstrap[i]->name;
348
if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
349
current_audio->LockAudio = SDL_LockAudio_Default;
350
current_audio->UnlockAudio = SDL_UnlockAudio_Default;
356
char *Our_SDL_AudioDriverName(char *namebuf, int maxlen)
358
if ( current_audio != NULL ) {
359
strncpy(namebuf, current_audio->name, maxlen-1);
360
namebuf[maxlen-1] = '\0';
366
int Our_SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
368
SDL_AudioDevice *audio;
370
/* Start up the audio driver, if necessary */
371
if ( ! current_audio ) {
372
if ((Our_SDL_AudioInit(getenv("SDL_AUDIODRIVER")) < 0) ||
373
(current_audio == NULL) ) {
377
audio = current_audio;
380
SDL_SetError("Audio device is already opened");
384
/* Verify some parameters */
385
if ( desired->callback == NULL ) {
386
SDL_SetError("SDL_OpenAudio() passed a NULL callback");
389
switch ( desired->channels ) {
392
case 4: /* surround */
393
case 6: /* surround */
396
SDL_SetError("1 (mono) and 2 (stereo) channels supported");
400
#if defined(macintosh) || (defined(__riscos__) && !defined(DISABLE_THREADS))
401
/* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
403
#if defined(__MINT__) && !defined(ENABLE_THREADS)
404
/* Uses interrupt driven audio, without thread */
406
/* Create a semaphore for locking the sound buffers */
407
audio->mixer_lock = SDL_CreateMutex();
408
if ( audio->mixer_lock == NULL ) {
409
SDL_SetError("Couldn't create mixer lock");
410
Our_SDL_CloseAudio();
413
#endif /* __MINT__ */
414
#endif /* macintosh */
416
/* Calculate the silence and size of the audio specification */
417
SDL_CalculateAudioSpec(desired);
419
/* Open the audio subsystem */
420
memcpy(&audio->spec, desired, sizeof(audio->spec));
421
audio->convert.needed = 0;
427
/* AmigaOS opens audio inside the main loop */
428
audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
430
if ( ! audio->opened ) {
435
D(bug("Locking semaphore..."));
436
SDL_mutexP(audio->mixer_lock);
438
audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
439
D(bug("Created thread...\n"));
441
if ( audio->thread == NULL ) {
442
SDL_mutexV(audio->mixer_lock);
443
Our_SDL_CloseAudio();
444
SDL_SetError("Couldn't create audio thread");
448
while(!audio_configured)
452
/* If the audio driver changes the buffer size, accept it */
453
if ( audio->spec.samples != desired->samples ) {
454
desired->samples = audio->spec.samples;
455
SDL_CalculateAudioSpec(desired);
458
/* Allocate a fake audio memory buffer */
459
audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
460
if ( audio->fake_stream == NULL ) {
461
Our_SDL_CloseAudio();
466
/* See if we need to do any conversion */
467
if ( obtained != NULL ) {
468
memcpy(obtained, &audio->spec, sizeof(audio->spec));
469
} else if ( desired->freq != audio->spec.freq ||
470
desired->format != audio->spec.format ||
471
desired->channels != audio->spec.channels ) {
473
if (desired->format == AUDIO_FORMAT_HW_AC3) {
476
/* Build an audio conversion block */
477
if ( SDL_BuildAudioCVT(&audio->convert,
478
desired->format, desired->channels,
480
audio->spec.format, audio->spec.channels,
481
audio->spec.freq) < 0 ) {
482
Our_SDL_CloseAudio();
485
if ( audio->convert.needed ) {
486
audio->convert.len = desired->size;
487
audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
488
audio->convert.len*audio->convert.len_mult);
489
if ( audio->convert.buf == NULL ) {
490
Our_SDL_CloseAudio();
498
/* Start the audio thread if necessary */
499
switch (audio->opened) {
501
/* Start the audio thread */
502
audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
503
if ( audio->thread == NULL ) {
504
Our_SDL_CloseAudio();
505
SDL_SetError("Couldn't create audio thread");
511
/* The audio is now playing */
515
SDL_mutexV(audio->mixer_lock);
516
D(bug("SDL_OpenAudio USCITA...\n"));
523
SDL_audiostatus Our_SDL_GetAudioStatus(void)
525
SDL_AudioDevice *audio = current_audio;
526
SDL_audiostatus status;
528
status = SDL_AUDIO_STOPPED;
529
if ( audio && audio->enabled ) {
530
if ( audio->paused ) {
531
status = SDL_AUDIO_PAUSED;
533
status = SDL_AUDIO_PLAYING;
539
void Our_SDL_PauseAudio (int pause_on)
541
SDL_AudioDevice *audio = current_audio;
544
audio->paused = pause_on;
548
void Our_SDL_LockAudio (void)
550
SDL_AudioDevice *audio = current_audio;
552
/* Obtain a lock on the mixing buffers */
553
if ( audio && audio->LockAudio ) {
554
audio->LockAudio(audio);
558
void Our_SDL_UnlockAudio (void)
560
SDL_AudioDevice *audio = current_audio;
562
/* Release lock on the mixing buffers */
563
if ( audio && audio->UnlockAudio ) {
564
audio->UnlockAudio(audio);
568
void Our_SDL_CloseAudio (void)
572
int Our_SDL_HasAudioDelay (void)
574
SDL_AudioDevice *audio = current_audio;
576
if (audio && audio->AudioDelay != NULL) {
582
int Our_SDL_AudioDelay (void)
584
SDL_AudioDevice *audio = current_audio;
585
if (audio && audio->AudioDelay != NULL) {
586
return (audio->AudioDelay(audio));
593
void Our_SDL_AudioQuit(void)
595
SDL_AudioDevice *audio = current_audio;
599
if ( audio->thread != NULL ) {
600
SDL_WaitThread(audio->thread, NULL);
602
if ( audio->mixer_lock != NULL ) {
603
SDL_DestroyMutex(audio->mixer_lock);
605
if ( audio->fake_stream != NULL ) {
606
SDL_FreeAudioMem(audio->fake_stream);
608
if ( audio->convert.needed ) {
609
SDL_FreeAudioMem(audio->convert.buf);
613
if ( audio->opened ) {
614
audio->CloseAudio(audio);
618
/* Free the driver data */
619
if (audio->free) audio->free(audio);
620
current_audio = NULL;
624
#define NUM_FORMATS 6
625
static int format_idx;
626
static int format_idx_sub;
627
static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
628
{ AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
629
{ AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
630
{ AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
631
{ AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
632
{ AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
633
{ AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
636
Uint16 SDL_FirstAudioFormat(Uint16 format)
638
for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
639
if ( format_list[format_idx][0] == format ) {
644
return(SDL_NextAudioFormat());
647
Uint16 SDL_NextAudioFormat(void)
649
if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
652
return(format_list[format_idx][format_idx_sub++]);
655
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
657
switch (spec->format) {
659
spec->silence = 0x80;
662
spec->silence = 0x00;
665
if (spec->format == AUDIO_FORMAT_HW_AC3) {
666
spec->size = 256 * 6 * 2 * 2;
668
spec->size = (spec->format&0xFF)/8;
669
spec->size *= spec->channels;
670
spec->size *= spec->samples;