src/audio/SDL_audio.c
author Sam Lantinga
Sat, 31 Dec 2011 09:16:08 -0500
branchSDL-1.2
changeset 6137 4720145f848b
parent 4547 963f939494a1
child 6353 dfcbd0d9209c
permissions -rw-r--r--
Happy New Year!
     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@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