src/audio/SDL_audio.c
author Sam Lantinga
Tue, 21 Feb 2006 18:29:39 +0000
changeset 1408 ceb5c2fec4f1
parent 1406 39ca9a4b22f3
child 1442 e3242177fe4a
permissions -rw-r--r--
Fixed some preprocessor mangling
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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_OPENBSD
    40 	&OPENBSD_AUDIO_bootstrap,
    41 #endif
    42 #if SDL_AUDIO_DRIVER_OSS
    43 	&DSP_bootstrap,
    44 	&DMA_bootstrap,
    45 #endif
    46 #if SDL_AUDIO_DRIVER_ALSA
    47 	&ALSA_bootstrap,
    48 #endif
    49 #if SDL_AUDIO_DRIVER_QNXNTO
    50 	&QNXNTOAUDIO_bootstrap,
    51 #endif
    52 #if SDL_AUDIO_DRIVER_SUNAUDIO
    53 	&SUNAUDIO_bootstrap,
    54 #endif
    55 #if SDL_AUDIO_DRIVER_DMEDIA
    56 	&DMEDIA_bootstrap,
    57 #endif
    58 #if SDL_AUDIO_DRIVER_ARTS
    59 	&ARTS_bootstrap,
    60 #endif
    61 #if SDL_AUDIO_DRIVER_ESD
    62 	&ESD_bootstrap,
    63 #endif
    64 #if SDL_AUDIO_DRIVER_NAS
    65 	&NAS_bootstrap,
    66 #endif
    67 #if SDL_AUDIO_DRIVER_DSOUND
    68 	&DSOUND_bootstrap,
    69 #endif
    70 #if SDL_AUDIO_DRIVER_WAVEOUT
    71 	&WAVEOUT_bootstrap,
    72 #endif
    73 #if SDL_AUDIO_DRIVER_PAUD
    74 	&Paud_bootstrap,
    75 #endif
    76 #if SDL_AUDIO_DRIVER_BAUDIO
    77 	&BAUDIO_bootstrap,
    78 #endif
    79 #if SDL_AUDIO_DRIVER_COREAUDIO
    80 	&COREAUDIO_bootstrap,
    81 #endif
    82 #if SDL_AUDIO_DRIVER_SNDMGR
    83 	&SNDMGR_bootstrap,
    84 #endif
    85 #if SDL_AUDIO_DRIVER_AHI
    86 	&AHI_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_DC
    99 	&DCAUD_bootstrap,
   100 #endif
   101 #if SDL_AUDIO_DRIVER_MMEAUDIO
   102 	&MMEAUDIO_bootstrap,
   103 #endif
   104 #if SDL_AUDIO_DRIVER_DART
   105 	&DART_bootstrap,
   106 #endif
   107 	NULL
   108 };
   109 SDL_AudioDevice *current_audio = NULL;
   110 
   111 /* Various local functions */
   112 int SDL_AudioInit(const char *driver_name);
   113 void SDL_AudioQuit(void);
   114 
   115 #if SDL_AUDIO_DRIVER_AHI
   116 static int audio_configured = 0;
   117 #endif
   118 
   119 /* The general mixing thread function */
   120 int SDL_RunAudio(void *audiop)
   121 {
   122 	SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
   123 	Uint8 *stream;
   124 	int    stream_len;
   125 	void  *udata;
   126 	void (*fill)(void *userdata,Uint8 *stream, int len);
   127 	int    silence;
   128 #if SDL_AUDIO_DRIVER_AHI
   129 	int started = 0;
   130 
   131 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
   132 
   133 	D(bug("Task audio started audio struct:<%lx>...\n",audiop));
   134 
   135 	D(bug("Before Openaudio..."));
   136 	if(audio->OpenAudio(audio, &audio->spec)==-1)
   137 	{
   138 		D(bug("Open audio failed...\n"));
   139 		return(-1);
   140 	}
   141 	D(bug("OpenAudio...OK\n"));
   142 #endif
   143 
   144 	/* Perform any thread setup */
   145 	if ( audio->ThreadInit ) {
   146 		audio->ThreadInit(audio);
   147 	}
   148 	audio->threadid = SDL_ThreadID();
   149 
   150 	/* Set up the mixing function */
   151 	fill  = audio->spec.callback;
   152 	udata = audio->spec.userdata;
   153 
   154 #if SDL_AUDIO_DRIVER_AHI
   155 	audio_configured = 1;
   156 
   157 	D(bug("Audio configured... Checking for conversion\n"));
   158 	SDL_mutexP(audio->mixer_lock);
   159 	D(bug("Semaphore obtained...\n"));
   160 #endif
   161 
   162 	if ( audio->convert.needed ) {
   163 		if ( audio->convert.src_format == AUDIO_U8 ) {
   164 			silence = 0x80;
   165 		} else {
   166 			silence = 0;
   167 		}
   168 		stream_len = audio->convert.len;
   169 	} else {
   170 		silence = audio->spec.silence;
   171 		stream_len = audio->spec.size;
   172 	}
   173 	stream = audio->fake_stream;
   174 
   175 #if SDL_AUDIO_DRIVER_AHI
   176 	SDL_mutexV(audio->mixer_lock);
   177 	D(bug("Entering audio loop...\n"));
   178 #endif
   179 
   180 #ifdef __OS2__
   181         // Increase the priority of this thread to make sure that
   182         // the audio will be continuous all the time!
   183 #ifdef USE_DOSSETPRIORITY
   184 #ifdef DEBUG_BUILD
   185         printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
   186 #endif
   187         DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
   188 #endif
   189 #endif
   190 
   191 	/* Loop, filling the audio buffers */
   192 	while ( audio->enabled ) {
   193 
   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);
   197 		} else {
   198 #if SDL_AUDIO_DRIVER_AHI
   199 			if ( started > 1 )
   200 #endif
   201 			audio->WaitAudio(audio);
   202 		}
   203 
   204 		/* Fill the current buffer with sound */
   205 		if ( audio->convert.needed ) {
   206 			if ( audio->convert.buf ) {
   207 				stream = audio->convert.buf;
   208 			} else {
   209 				continue;
   210 			}
   211 		} else {
   212 			stream = audio->GetAudioBuf(audio);
   213 			if ( stream == NULL ) {
   214 				stream = audio->fake_stream;
   215 			}
   216 		}
   217 		SDL_memset(stream, silence, stream_len);
   218 
   219 		if ( ! audio->paused ) {
   220 			SDL_mutexP(audio->mixer_lock);
   221 			(*fill)(udata, stream, stream_len);
   222 			SDL_mutexV(audio->mixer_lock);
   223 		}
   224 
   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;
   231 			}
   232 			SDL_memcpy(stream, audio->convert.buf,
   233 			               audio->convert.len_cvt);
   234 		}
   235 
   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! */
   241 			started++;
   242 #endif
   243 		}
   244 	}
   245 	/* Wait for the audio to drain.. */
   246 	if ( audio->WaitDone ) {
   247 		audio->WaitDone(audio);
   248 	}
   249 
   250 #if SDL_AUDIO_DRIVER_AHI
   251 	D(bug("WaitAudio...Done\n"));
   252 
   253 	audio->CloseAudio(audio);
   254 
   255 	D(bug("CloseAudio..Done, subtask exiting...\n"));
   256 	audio_configured = 0;
   257 #endif
   258 #ifdef __OS2__
   259 #ifdef DEBUG_BUILD
   260         printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
   261 #endif
   262 #endif
   263 	return(0);
   264 }
   265 
   266 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
   267 {
   268 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   269 		return;
   270 	}
   271 	SDL_mutexP(audio->mixer_lock);
   272 }
   273 
   274 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
   275 {
   276 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   277 		return;
   278 	}
   279 	SDL_mutexV(audio->mixer_lock);
   280 }
   281 
   282 int SDL_AudioInit(const char *driver_name)
   283 {
   284 	SDL_AudioDevice *audio;
   285 	int i = 0, idx;
   286 
   287 	/* Check to make sure we don't overwrite 'current_audio' */
   288 	if ( current_audio != NULL ) {
   289 		SDL_AudioQuit();
   290 	}
   291 
   292 	/* Select the proper audio driver */
   293 	audio = NULL;
   294 	idx = 0;
   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! :)
   300 		 */
   301 		for ( i=0; bootstrap[i]; ++i ) {
   302 			if ( SDL_strcmp(bootstrap[i]->name, "esd") == 0 ) {
   303 #ifdef HAVE_PUTENV
   304 				const char *esd_no_spawn;
   305 
   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");
   310 				}
   311 #endif
   312 				if ( bootstrap[i]->available() ) {
   313 					audio = bootstrap[i]->create(0);
   314 					break;
   315 				}
   316 #ifdef HAVE_UNSETENV
   317 				if ( esd_no_spawn == NULL ) {
   318 					unsetenv("ESD_NO_SPAWN");
   319 				}
   320 #endif
   321 			}
   322 		}
   323 	}
   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);
   330 			}
   331 #endif
   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);
   337 						break;
   338 					}
   339 				}
   340 			}
   341 		} else {
   342 			for ( i=0; bootstrap[i]; ++i ) {
   343 				if ( bootstrap[i]->available() ) {
   344 					audio = bootstrap[i]->create(idx);
   345 					if ( audio != NULL ) {
   346 						break;
   347 					}
   348 				}
   349 			}
   350 		}
   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*
   355        */
   356 			return(-1);
   357 #endif
   358 		}
   359 	}
   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;
   366 		}
   367 	}
   368 	return(0);
   369 }
   370 
   371 char *SDL_AudioDriverName(char *namebuf, int maxlen)
   372 {
   373 	if ( current_audio != NULL ) {
   374 		SDL_strlcpy(namebuf, current_audio->name, maxlen);
   375 		return(namebuf);
   376 	}
   377 	return(NULL);
   378 }
   379 
   380 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
   381 {
   382 	SDL_AudioDevice *audio;
   383 
   384 	/* Start up the audio driver, if necessary */
   385 	if ( ! current_audio ) {
   386 		if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
   387 		     (current_audio == NULL) ) {
   388 			return(-1);
   389 		}
   390 	}
   391 	audio = current_audio;
   392 
   393 	if (audio->opened) {
   394 		SDL_SetError("Audio device is already opened");
   395 		return(-1);
   396 	}
   397 
   398 	/* Verify some parameters */
   399 	if ( desired->callback == NULL ) {
   400 		SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   401 		return(-1);
   402 	}
   403 	switch ( desired->channels ) {
   404 	    case 1:	/* Mono */
   405 	    case 2:	/* Stereo */
   406 	    case 4:	/* surround */
   407 	    case 6:	/* surround with center and lfe */
   408 		break;
   409 	    default:
   410 		SDL_SetError("1 (mono) and 2 (stereo) channels supported");
   411 		return(-1);
   412 	}
   413 
   414 #if defined(__MACOS__) || (defined(__RISCOS__) && SDL_THREADS_DISABLED)
   415 	/* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
   416 #else
   417 #if defined(__MINT__) && SDL_THREADS_DISABLED
   418 	/* Uses interrupt driven audio, without thread */
   419 #else
   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");
   424 		SDL_CloseAudio();
   425 		return(-1);
   426 	}
   427 #endif /* __MINT__ */
   428 #endif /* __MACOS__ */
   429 
   430 	/* Calculate the silence and size of the audio specification */
   431 	SDL_CalculateAudioSpec(desired);
   432 
   433 	/* Open the audio subsystem */
   434 	SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
   435 	audio->convert.needed = 0;
   436 	audio->enabled = 1;
   437 	audio->paused  = 1;
   438 
   439 #if !SDL_AUDIO_DRIVER_AHI
   440 
   441 /* AmigaOS opens audio inside the main loop */
   442 	audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
   443 
   444 	if ( ! audio->opened ) {
   445 		SDL_CloseAudio();
   446 		return(-1);
   447 	}
   448 #else
   449 	D(bug("Locking semaphore..."));
   450 	SDL_mutexP(audio->mixer_lock);
   451 
   452 
   453 	audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   454 	D(bug("Created thread...\n"));
   455 
   456 	if ( audio->thread == NULL ) {
   457 		SDL_mutexV(audio->mixer_lock);
   458 		SDL_CloseAudio();
   459 		SDL_SetError("Couldn't create audio thread");
   460 		return(-1);
   461 	}
   462 
   463 	while(!audio_configured)
   464 		SDL_Delay(100);
   465 #endif
   466 
   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);
   471 	}
   472 
   473 	/* Allocate a fake audio memory buffer */
   474 	audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
   475 	if ( audio->fake_stream == NULL ) {
   476 		SDL_CloseAudio();
   477 		SDL_OutOfMemory();
   478 		return(-1);
   479 	}
   480 
   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,
   490 					desired->freq,
   491 			audio->spec.format, audio->spec.channels,
   492 					audio->spec.freq) < 0 ) {
   493 			SDL_CloseAudio();
   494 			return(-1);
   495 		}
   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 ) {
   501 				SDL_CloseAudio();
   502 				SDL_OutOfMemory();
   503 				return(-1);
   504 			}
   505 		}
   506 	}
   507 
   508 #if !SDL_AUDIO_DRIVER_AHI
   509 	/* Start the audio thread if necessary */
   510 	switch (audio->opened) {
   511 		case  1:
   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);
   516 #else
   517 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   518 #endif
   519 			if ( audio->thread == NULL ) {
   520 				SDL_CloseAudio();
   521 				SDL_SetError("Couldn't create audio thread");
   522 				return(-1);
   523 			}
   524 			break;
   525 
   526 		default:
   527 			/* The audio is now playing */
   528 			break;
   529 	}
   530 #else
   531 	SDL_mutexV(audio->mixer_lock);
   532 	D(bug("SDL_OpenAudio USCITA...\n"));
   533 
   534 #endif
   535 
   536 	return(0);
   537 }
   538 
   539 SDL_audiostatus SDL_GetAudioStatus(void)
   540 {
   541 	SDL_AudioDevice *audio = current_audio;
   542 	SDL_audiostatus status;
   543 
   544 	status = SDL_AUDIO_STOPPED;
   545 	if ( audio && audio->enabled ) {
   546 		if ( audio->paused ) {
   547 			status = SDL_AUDIO_PAUSED;
   548 		} else {
   549 			status = SDL_AUDIO_PLAYING;
   550 		}
   551 	}
   552 	return(status);
   553 }
   554 
   555 void SDL_PauseAudio (int pause_on)
   556 {
   557 	SDL_AudioDevice *audio = current_audio;
   558 
   559 	if ( audio ) {
   560 		audio->paused = pause_on;
   561 	}
   562 }
   563 
   564 void SDL_LockAudio (void)
   565 {
   566 	SDL_AudioDevice *audio = current_audio;
   567 
   568 	/* Obtain a lock on the mixing buffers */
   569 	if ( audio && audio->LockAudio ) {
   570 		audio->LockAudio(audio);
   571 	}
   572 }
   573 
   574 void SDL_UnlockAudio (void)
   575 {
   576 	SDL_AudioDevice *audio = current_audio;
   577 
   578 	/* Release lock on the mixing buffers */
   579 	if ( audio && audio->UnlockAudio ) {
   580 		audio->UnlockAudio(audio);
   581 	}
   582 }
   583 
   584 void SDL_CloseAudio (void)
   585 {
   586 	SDL_QuitSubSystem(SDL_INIT_AUDIO);
   587 }
   588 
   589 void SDL_AudioQuit(void)
   590 {
   591 	SDL_AudioDevice *audio = current_audio;
   592 
   593 	if ( audio ) {
   594 		audio->enabled = 0;
   595 		if ( audio->thread != NULL ) {
   596 			SDL_WaitThread(audio->thread, NULL);
   597 		}
   598 		if ( audio->mixer_lock != NULL ) {
   599 			SDL_DestroyMutex(audio->mixer_lock);
   600 		}
   601 		if ( audio->fake_stream != NULL ) {
   602 			SDL_FreeAudioMem(audio->fake_stream);
   603 		}
   604 		if ( audio->convert.needed ) {
   605 			SDL_FreeAudioMem(audio->convert.buf);
   606 
   607 		}
   608 #if !SDL_AUDIO_DRIVER_AHI
   609 		if ( audio->opened ) {
   610 			audio->CloseAudio(audio);
   611 			audio->opened = 0;
   612 		}
   613 #endif
   614 		/* Free the driver data */
   615 		audio->free(audio);
   616 		current_audio = NULL;
   617 	}
   618 }
   619 
   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 },
   630 };
   631 
   632 Uint16 SDL_FirstAudioFormat(Uint16 format)
   633 {
   634 	for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
   635 		if ( format_list[format_idx][0] == format ) {
   636 			break;
   637 		}
   638 	}
   639 	format_idx_sub = 0;
   640 	return(SDL_NextAudioFormat());
   641 }
   642 
   643 Uint16 SDL_NextAudioFormat(void)
   644 {
   645 	if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
   646 		return(0);
   647 	}
   648 	return(format_list[format_idx][format_idx_sub++]);
   649 }
   650 
   651 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
   652 {
   653 	switch (spec->format) {
   654 		case AUDIO_U8:
   655 			spec->silence = 0x80;
   656 			break;
   657 		default:
   658 			spec->silence = 0x00;
   659 			break;
   660 	}
   661 	spec->size = (spec->format&0xFF)/8;
   662 	spec->size *= spec->channels;
   663 	spec->size *= spec->samples;
   664 }