Home | History | Annotate | Download | only in audio
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      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.
      9 
     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.
     14 
     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
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /* Allow access to a raw mixing buffer */
     25 
     26 #include "SDL.h"
     27 #include "SDL_audio_c.h"
     28 #include "SDL_audiomem.h"
     29 #include "SDL_sysaudio.h"
     30 
     31 #ifdef __OS2__
     32 /* We'll need the DosSetPriority() API! */
     33 #define INCL_DOSPROCESS
     34 #include <os2.h>
     35 #endif
     36 
     37 /* Available audio drivers */
     38 static AudioBootStrap *bootstrap[] = {
     39 #if SDL_AUDIO_DRIVER_PULSE
     40 	&PULSE_bootstrap,
     41 #endif
     42 #if SDL_AUDIO_DRIVER_ALSA
     43 	&ALSA_bootstrap,
     44 #endif
     45 #if SDL_AUDIO_DRIVER_BSD
     46 	&BSD_AUDIO_bootstrap,
     47 #endif
     48 #if SDL_AUDIO_DRIVER_OSS
     49 	&DSP_bootstrap,
     50 	&DMA_bootstrap,
     51 #endif
     52 #if SDL_AUDIO_DRIVER_QNXNTO
     53 	&QNXNTOAUDIO_bootstrap,
     54 #endif
     55 #if SDL_AUDIO_DRIVER_SUNAUDIO
     56 	&SUNAUDIO_bootstrap,
     57 #endif
     58 #if SDL_AUDIO_DRIVER_DMEDIA
     59 	&DMEDIA_bootstrap,
     60 #endif
     61 #if SDL_AUDIO_DRIVER_ARTS
     62 	&ARTS_bootstrap,
     63 #endif
     64 #if SDL_AUDIO_DRIVER_ESD
     65 	&ESD_bootstrap,
     66 #endif
     67 #if SDL_AUDIO_DRIVER_NAS
     68 	&NAS_bootstrap,
     69 #endif
     70 #if SDL_AUDIO_DRIVER_DSOUND
     71 	&DSOUND_bootstrap,
     72 #endif
     73 #if SDL_AUDIO_DRIVER_WAVEOUT
     74 	&WAVEOUT_bootstrap,
     75 #endif
     76 #if SDL_AUDIO_DRIVER_PAUD
     77 	&Paud_bootstrap,
     78 #endif
     79 #if SDL_AUDIO_DRIVER_BAUDIO
     80 	&BAUDIO_bootstrap,
     81 #endif
     82 #if SDL_AUDIO_DRIVER_COREAUDIO
     83 	&COREAUDIO_bootstrap,
     84 #endif
     85 #if SDL_AUDIO_DRIVER_SNDMGR
     86 	&SNDMGR_bootstrap,
     87 #endif
     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,
     94 #endif
     95 #if SDL_AUDIO_DRIVER_DISK
     96 	&DISKAUD_bootstrap,
     97 #endif
     98 #if SDL_AUDIO_DRIVER_DUMMY
     99 	&DUMMYAUD_bootstrap,
    100 #endif
    101 #if SDL_AUDIO_DRIVER_DC
    102 	&DCAUD_bootstrap,
    103 #endif
    104 #if SDL_AUDIO_DRIVER_NDS
    105 	&NDSAUD_bootstrap,
    106 #endif
    107 #if SDL_AUDIO_DRIVER_MMEAUDIO
    108 	&MMEAUDIO_bootstrap,
    109 #endif
    110 #if SDL_AUDIO_DRIVER_DART
    111 	&DART_bootstrap,
    112 #endif
    113 #if SDL_AUDIO_DRIVER_EPOCAUDIO
    114 	&EPOCAudio_bootstrap,
    115 #endif
    116 	NULL
    117 };
    118 SDL_AudioDevice *current_audio = NULL;
    119 
    120 /* Various local functions */
    121 int SDL_AudioInit(const char *driver_name);
    122 void SDL_AudioQuit(void);
    123 
    124 /* The general mixing thread function */
    125 int SDLCALL SDL_RunAudio(void *audiop)
    126 {
    127 	SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
    128 	Uint8 *stream;
    129 	int    stream_len;
    130 	void  *udata;
    131 	void (SDLCALL *fill)(void *userdata,Uint8 *stream, int len);
    132 	int    silence;
    133 
    134 	/* Perform any thread setup */
    135 	if ( audio->ThreadInit ) {
    136 		audio->ThreadInit(audio);
    137 	}
    138 	audio->threadid = SDL_ThreadID();
    139 
    140 	/* Set up the mixing function */
    141 	fill  = audio->spec.callback;
    142 	udata = audio->spec.userdata;
    143 
    144 	if ( audio->convert.needed ) {
    145 		if ( audio->convert.src_format == AUDIO_U8 ) {
    146 			silence = 0x80;
    147 		} else {
    148 			silence = 0;
    149 		}
    150 		stream_len = audio->convert.len;
    151 	} else {
    152 		silence = audio->spec.silence;
    153 		stream_len = audio->spec.size;
    154 	}
    155 
    156 #ifdef __OS2__
    157         /* Increase the priority of this thread to make sure that
    158            the audio will be continuous all the time! */
    159 #ifdef USE_DOSSETPRIORITY
    160         if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO"))
    161         {
    162 #ifdef DEBUG_BUILD
    163           printf("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n", SDL_ThreadID());
    164 #endif
    165           DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
    166         }
    167         else
    168         {
    169 #ifdef DEBUG_BUILD
    170           printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
    171 #endif
    172           DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
    173         }
    174 #endif
    175 #endif
    176 
    177 	/* Loop, filling the audio buffers */
    178 	while ( audio->enabled ) {
    179 
    180 		/* Fill the current buffer with sound */
    181 		if ( audio->convert.needed ) {
    182 			if ( audio->convert.buf ) {
    183 				stream = audio->convert.buf;
    184 			} else {
    185 				continue;
    186 			}
    187 		} else {
    188 			stream = audio->GetAudioBuf(audio);
    189 			if ( stream == NULL ) {
    190 				stream = audio->fake_stream;
    191 			}
    192 		}
    193 
    194 		SDL_memset(stream, silence, stream_len);
    195 
    196 		if ( ! audio->paused ) {
    197 			SDL_mutexP(audio->mixer_lock);
    198 			(*fill)(udata, stream, stream_len);
    199 			SDL_mutexV(audio->mixer_lock);
    200 		}
    201 
    202 		/* Convert the audio if necessary */
    203 		if ( audio->convert.needed ) {
    204 			SDL_ConvertAudio(&audio->convert);
    205 			stream = audio->GetAudioBuf(audio);
    206 			if ( stream == NULL ) {
    207 				stream = audio->fake_stream;
    208 			}
    209 			SDL_memcpy(stream, audio->convert.buf,
    210 			               audio->convert.len_cvt);
    211 		}
    212 
    213 		/* Ready current buffer for play and change current buffer */
    214 		if ( stream != audio->fake_stream ) {
    215 			audio->PlayAudio(audio);
    216 		}
    217 
    218 		/* Wait for an audio buffer to become available */
    219 		if ( stream == audio->fake_stream ) {
    220 			SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
    221 		} else {
    222 			audio->WaitAudio(audio);
    223 		}
    224 	}
    225 
    226 	/* Wait for the audio to drain.. */
    227 	if ( audio->WaitDone ) {
    228 		audio->WaitDone(audio);
    229 	}
    230 
    231 #ifdef __OS2__
    232 #ifdef DEBUG_BUILD
    233         printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
    234 #endif
    235 #endif
    236 	return(0);
    237 }
    238 
    239 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
    240 {
    241 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
    242 		return;
    243 	}
    244 	SDL_mutexP(audio->mixer_lock);
    245 }
    246 
    247 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
    248 {
    249 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
    250 		return;
    251 	}
    252 	SDL_mutexV(audio->mixer_lock);
    253 }
    254 
    255 static Uint16 SDL_ParseAudioFormat(const char *string)
    256 {
    257 	Uint16 format = 0;
    258 
    259 	switch (*string) {
    260 	    case 'U':
    261 		++string;
    262 		format |= 0x0000;
    263 		break;
    264 	    case 'S':
    265 		++string;
    266 		format |= 0x8000;
    267 		break;
    268 	    default:
    269 		return 0;
    270 	}
    271 	switch (SDL_atoi(string)) {
    272 	    case 8:
    273 		string += 1;
    274 		format |= 8;
    275 		break;
    276 	    case 16:
    277 		string += 2;
    278 		format |= 16;
    279 		if ( SDL_strcmp(string, "LSB") == 0
    280 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    281 		     || SDL_strcmp(string, "SYS") == 0
    282 #endif
    283 		    ) {
    284 			format |= 0x0000;
    285 		}
    286 		if ( SDL_strcmp(string, "MSB") == 0
    287 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
    288 		     || SDL_strcmp(string, "SYS") == 0
    289 #endif
    290 		    ) {
    291 			format |= 0x1000;
    292 		}
    293 		break;
    294 	    default:
    295 		return 0;
    296 	}
    297 	return format;
    298 }
    299 
    300 int SDL_AudioInit(const char *driver_name)
    301 {
    302 	SDL_AudioDevice *audio;
    303 	int i = 0, idx;
    304 
    305 	/* Check to make sure we don't overwrite 'current_audio' */
    306 	if ( current_audio != NULL ) {
    307 		SDL_AudioQuit();
    308 	}
    309 
    310 	/* Select the proper audio driver */
    311 	audio = NULL;
    312 	idx = 0;
    313 #if SDL_AUDIO_DRIVER_ESD
    314 	if ( (driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL) ) {
    315 		/* Ahem, we know that if ESPEAKER is set, user probably wants
    316 		   to use ESD, but don't start it if it's not already running.
    317 		   This probably isn't the place to do this, but... Shh! :)
    318 		 */
    319 		for ( i=0; bootstrap[i]; ++i ) {
    320 			if ( SDL_strcasecmp(bootstrap[i]->name, "esd") == 0 ) {
    321 #ifdef HAVE_PUTENV
    322 				const char *esd_no_spawn;
    323 
    324 				/* Don't start ESD if it's not running */
    325 				esd_no_spawn = getenv("ESD_NO_SPAWN");
    326 				if ( esd_no_spawn == NULL ) {
    327 					putenv("ESD_NO_SPAWN=1");
    328 				}
    329 #endif
    330 				if ( bootstrap[i]->available() ) {
    331 					audio = bootstrap[i]->create(0);
    332 					break;
    333 				}
    334 #ifdef HAVE_UNSETENV
    335 				if ( esd_no_spawn == NULL ) {
    336 					unsetenv("ESD_NO_SPAWN");
    337 				}
    338 #endif
    339 			}
    340 		}
    341 	}
    342 #endif /* SDL_AUDIO_DRIVER_ESD */
    343 	if ( audio == NULL ) {
    344 		if ( driver_name != NULL ) {
    345 #if 0	/* This will be replaced with a better driver selection API */
    346 			if ( SDL_strrchr(driver_name, ':') != NULL ) {
    347 				idx = atoi(SDL_strrchr(driver_name, ':')+1);
    348 			}
    349 #endif
    350 			for ( i=0; bootstrap[i]; ++i ) {
    351 				if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
    352 					if ( bootstrap[i]->available() ) {
    353 						audio=bootstrap[i]->create(idx);
    354 						break;
    355 					}
    356 				}
    357 			}
    358 		} else {
    359 			for ( i=0; bootstrap[i]; ++i ) {
    360 				if ( bootstrap[i]->available() ) {
    361 					audio = bootstrap[i]->create(idx);
    362 					if ( audio != NULL ) {
    363 						break;
    364 					}
    365 				}
    366 			}
    367 		}
    368 		if ( audio == NULL ) {
    369 			SDL_SetError("No available audio device");
    370 #if 0 /* Don't fail SDL_Init() if audio isn't available.
    371          SDL_OpenAudio() will handle it at that point.  *sigh*
    372        */
    373 			return(-1);
    374 #endif
    375 		}
    376 	}
    377 	current_audio = audio;
    378 	if ( current_audio ) {
    379 		current_audio->name = bootstrap[i]->name;
    380 		if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
    381 			current_audio->LockAudio = SDL_LockAudio_Default;
    382 			current_audio->UnlockAudio = SDL_UnlockAudio_Default;
    383 		}
    384 	}
    385 	return(0);
    386 }
    387 
    388 char *SDL_AudioDriverName(char *namebuf, int maxlen)
    389 {
    390 	if ( current_audio != NULL ) {
    391 		SDL_strlcpy(namebuf, current_audio->name, maxlen);
    392 		return(namebuf);
    393 	}
    394 	return(NULL);
    395 }
    396 
    397 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
    398 {
    399 	SDL_AudioDevice *audio;
    400 	const char *env;
    401 
    402 	/* Start up the audio driver, if necessary */
    403 	if ( ! current_audio ) {
    404 		if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
    405 		     (current_audio == NULL) ) {
    406 			return(-1);
    407 		}
    408 	}
    409 	audio = current_audio;
    410 
    411 	if (audio->opened) {
    412 		SDL_SetError("Audio device is already opened");
    413 		return(-1);
    414 	}
    415 
    416 	/* Verify some parameters */
    417 	if ( desired->freq == 0 ) {
    418 		env = SDL_getenv("SDL_AUDIO_FREQUENCY");
    419 		if ( env ) {
    420 			desired->freq = SDL_atoi(env);
    421 		}
    422 	}
    423 	if ( desired->freq == 0 ) {
    424 		/* Pick some default audio frequency */
    425 		desired->freq = 22050;
    426 	}
    427 	if ( desired->format == 0 ) {
    428 		env = SDL_getenv("SDL_AUDIO_FORMAT");
    429 		if ( env ) {
    430 			desired->format = SDL_ParseAudioFormat(env);
    431 		}
    432 	}
    433 	if ( desired->format == 0 ) {
    434 		/* Pick some default audio format */
    435 		desired->format = AUDIO_S16;
    436 	}
    437 	if ( desired->channels == 0 ) {
    438 		env = SDL_getenv("SDL_AUDIO_CHANNELS");
    439 		if ( env ) {
    440 			desired->channels = (Uint8)SDL_atoi(env);
    441 		}
    442 	}
    443 	if ( desired->channels == 0 ) {
    444 		/* Pick a default number of channels */
    445 		desired->channels = 2;
    446 	}
    447 	switch ( desired->channels ) {
    448 	    case 1:	/* Mono */
    449 	    case 2:	/* Stereo */
    450 	    case 4:	/* surround */
    451 	    case 6:	/* surround with center and lfe */
    452 		break;
    453 	    default:
    454 		SDL_SetError("1 (mono) and 2 (stereo) channels supported");
    455 		return(-1);
    456 	}
    457 	if ( desired->samples == 0 ) {
    458 		env = SDL_getenv("SDL_AUDIO_SAMPLES");
    459 		if ( env ) {
    460 			desired->samples = (Uint16)SDL_atoi(env);
    461 		}
    462 	}
    463 	if ( desired->samples == 0 ) {
    464 		/* Pick a default of ~46 ms at desired frequency */
    465 		int samples = (desired->freq / 1000) * 46;
    466 		int power2 = 1;
    467 		while ( power2 < samples ) {
    468 			power2 *= 2;
    469 		}
    470 		desired->samples = power2;
    471 	}
    472 	if ( desired->callback == NULL ) {
    473 		SDL_SetError("SDL_OpenAudio() passed a NULL callback");
    474 		return(-1);
    475 	}
    476 
    477 #if SDL_THREADS_DISABLED
    478 	/* Uses interrupt driven audio, without thread */
    479 #else
    480 	/* Create a semaphore for locking the sound buffers */
    481 	audio->mixer_lock = SDL_CreateMutex();
    482 	if ( audio->mixer_lock == NULL ) {
    483 		SDL_SetError("Couldn't create mixer lock");
    484 		SDL_CloseAudio();
    485 		return(-1);
    486 	}
    487 #endif /* SDL_THREADS_DISABLED */
    488 
    489 	/* Calculate the silence and size of the audio specification */
    490 	SDL_CalculateAudioSpec(desired);
    491 
    492 	/* Open the audio subsystem */
    493 	SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
    494 	audio->convert.needed = 0;
    495 	audio->enabled = 1;
    496 	audio->paused  = 1;
    497 
    498 	audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
    499 
    500 	if ( ! audio->opened ) {
    501 		SDL_CloseAudio();
    502 		return(-1);
    503 	}
    504 
    505 	/* If the audio driver changes the buffer size, accept it */
    506 	if ( audio->spec.samples != desired->samples ) {
    507 		desired->samples = audio->spec.samples;
    508 		SDL_CalculateAudioSpec(desired);
    509 	}
    510 
    511 	/* Allocate a fake audio memory buffer */
    512 	audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
    513 	if ( audio->fake_stream == NULL ) {
    514 		SDL_CloseAudio();
    515 		SDL_OutOfMemory();
    516 		return(-1);
    517 	}
    518 
    519 	/* See if we need to do any conversion */
    520 	if ( obtained != NULL ) {
    521 		SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
    522 	} else if ( desired->freq != audio->spec.freq ||
    523                     desired->format != audio->spec.format ||
    524 	            desired->channels != audio->spec.channels ) {
    525 		/* Build an audio conversion block */
    526 		if ( SDL_BuildAudioCVT(&audio->convert,
    527 			desired->format, desired->channels,
    528 					desired->freq,
    529 			audio->spec.format, audio->spec.channels,
    530 					audio->spec.freq) < 0 ) {
    531 			SDL_CloseAudio();
    532 			return(-1);
    533 		}
    534 		if ( audio->convert.needed ) {
    535 			audio->convert.len = (int) ( ((double) audio->spec.size) /
    536                                           audio->convert.len_ratio );
    537 			audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
    538 			   audio->convert.len*audio->convert.len_mult);
    539 			if ( audio->convert.buf == NULL ) {
    540 				SDL_CloseAudio();
    541 				SDL_OutOfMemory();
    542 				return(-1);
    543 			}
    544 		}
    545 	}
    546 
    547 	/* Start the audio thread if necessary */
    548 	switch (audio->opened) {
    549 		case  1:
    550 			/* Start the audio thread */
    551 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__)
    552 #undef SDL_CreateThread
    553 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
    554 #else
    555 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
    556 #endif
    557 			if ( audio->thread == NULL ) {
    558 				SDL_CloseAudio();
    559 				SDL_SetError("Couldn't create audio thread");
    560 				return(-1);
    561 			}
    562 			break;
    563 
    564 		default:
    565 			/* The audio is now playing */
    566 			break;
    567 	}
    568 
    569 	return(0);
    570 }
    571 
    572 SDL_audiostatus SDL_GetAudioStatus(void)
    573 {
    574 	SDL_AudioDevice *audio = current_audio;
    575 	SDL_audiostatus status;
    576 
    577 	status = SDL_AUDIO_STOPPED;
    578 	if ( audio && audio->enabled ) {
    579 		if ( audio->paused ) {
    580 			status = SDL_AUDIO_PAUSED;
    581 		} else {
    582 			status = SDL_AUDIO_PLAYING;
    583 		}
    584 	}
    585 	return(status);
    586 }
    587 
    588 void SDL_PauseAudio (int pause_on)
    589 {
    590 	SDL_AudioDevice *audio = current_audio;
    591 
    592 	if ( audio ) {
    593 		audio->paused = pause_on;
    594 	}
    595 }
    596 
    597 void SDL_LockAudio (void)
    598 {
    599 	SDL_AudioDevice *audio = current_audio;
    600 
    601 	/* Obtain a lock on the mixing buffers */
    602 	if ( audio && audio->LockAudio ) {
    603 		audio->LockAudio(audio);
    604 	}
    605 }
    606 
    607 void SDL_UnlockAudio (void)
    608 {
    609 	SDL_AudioDevice *audio = current_audio;
    610 
    611 	/* Release lock on the mixing buffers */
    612 	if ( audio && audio->UnlockAudio ) {
    613 		audio->UnlockAudio(audio);
    614 	}
    615 }
    616 
    617 void SDL_CloseAudio (void)
    618 {
    619 	SDL_QuitSubSystem(SDL_INIT_AUDIO);
    620 }
    621 
    622 void SDL_AudioQuit(void)
    623 {
    624 	SDL_AudioDevice *audio = current_audio;
    625 
    626 	if ( audio ) {
    627 		audio->enabled = 0;
    628 		if ( audio->thread != NULL ) {
    629 			SDL_WaitThread(audio->thread, NULL);
    630 		}
    631 		if ( audio->mixer_lock != NULL ) {
    632 			SDL_DestroyMutex(audio->mixer_lock);
    633 		}
    634 		if ( audio->fake_stream != NULL ) {
    635 			SDL_FreeAudioMem(audio->fake_stream);
    636 		}
    637 		if ( audio->convert.needed ) {
    638 			SDL_FreeAudioMem(audio->convert.buf);
    639 
    640 		}
    641 		if ( audio->opened ) {
    642 			audio->CloseAudio(audio);
    643 			audio->opened = 0;
    644 		}
    645 		/* Free the driver data */
    646 		audio->free(audio);
    647 		current_audio = NULL;
    648 	}
    649 }
    650 
    651 #define NUM_FORMATS	6
    652 static int format_idx;
    653 static int format_idx_sub;
    654 static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
    655  { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
    656  { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
    657  { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
    658  { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
    659  { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
    660  { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
    661 };
    662 
    663 Uint16 SDL_FirstAudioFormat(Uint16 format)
    664 {
    665 	for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
    666 		if ( format_list[format_idx][0] == format ) {
    667 			break;
    668 		}
    669 	}
    670 	format_idx_sub = 0;
    671 	return(SDL_NextAudioFormat());
    672 }
    673 
    674 Uint16 SDL_NextAudioFormat(void)
    675 {
    676 	if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
    677 		return(0);
    678 	}
    679 	return(format_list[format_idx][format_idx_sub++]);
    680 }
    681 
    682 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
    683 {
    684 	switch (spec->format) {
    685 		case AUDIO_U8:
    686 			spec->silence = 0x80;
    687 			break;
    688 		default:
    689 			spec->silence = 0x00;
    690 			break;
    691 	}
    692 	spec->size = (spec->format&0xFF)/8;
    693 	spec->size *= spec->channels;
    694 	spec->size *= spec->samples;
    695 }
    696 
    697 void SDL_Audio_SetCaption(const char *caption)
    698 {
    699 	if ((current_audio) && (current_audio->SetCaption)) {
    700 		current_audio->SetCaption(current_audio, caption);
    701 	}
    702 }
    703 
    704