src/audio/SDL_audio.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 09 Mar 2006 06:33:21 +0000
changeset 1487 dc6b59e925a2
parent 1442 e3242177fe4a
child 1532 30f189cdd82b
permissions -rw-r--r--
Cleaning up warnings on MacOS X
     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         if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO"))
   185         {
   186 #ifdef DEBUG_BUILD
   187           printf("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n", SDL_ThreadID());
   188 #endif
   189           DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
   190         }
   191         else
   192         {
   193 #ifdef DEBUG_BUILD
   194           printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
   195 #endif
   196           DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
   197         }
   198 #endif
   199 #endif
   200 
   201 	/* Loop, filling the audio buffers */
   202 	while ( audio->enabled ) {
   203 
   204 		/* Wait for new current buffer to finish playing */
   205 		if ( stream == audio->fake_stream ) {
   206 			SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
   207 		} else {
   208 #if SDL_AUDIO_DRIVER_AHI
   209 			if ( started > 1 )
   210 #endif
   211 			audio->WaitAudio(audio);
   212 		}
   213 
   214 		/* Fill the current buffer with sound */
   215 		if ( audio->convert.needed ) {
   216 			if ( audio->convert.buf ) {
   217 				stream = audio->convert.buf;
   218 			} else {
   219 				continue;
   220 			}
   221 		} else {
   222 			stream = audio->GetAudioBuf(audio);
   223 			if ( stream == NULL ) {
   224 				stream = audio->fake_stream;
   225 			}
   226 		}
   227 		SDL_memset(stream, silence, stream_len);
   228 
   229 		if ( ! audio->paused ) {
   230 			SDL_mutexP(audio->mixer_lock);
   231 			(*fill)(udata, stream, stream_len);
   232 			SDL_mutexV(audio->mixer_lock);
   233 		}
   234 
   235 		/* Convert the audio if necessary */
   236 		if ( audio->convert.needed ) {
   237 			SDL_ConvertAudio(&audio->convert);
   238 			stream = audio->GetAudioBuf(audio);
   239 			if ( stream == NULL ) {
   240 				stream = audio->fake_stream;
   241 			}
   242 			SDL_memcpy(stream, audio->convert.buf,
   243 			               audio->convert.len_cvt);
   244 		}
   245 
   246 		/* Ready current buffer for play and change current buffer */
   247 		if ( stream != audio->fake_stream ) {
   248 			audio->PlayAudio(audio);
   249 #if SDL_AUDIO_DRIVER_AHI
   250 /* AmigaOS don't have to wait the first time audio is played! */
   251 			started++;
   252 #endif
   253 		}
   254 	}
   255 	/* Wait for the audio to drain.. */
   256 	if ( audio->WaitDone ) {
   257 		audio->WaitDone(audio);
   258 	}
   259 
   260 #if SDL_AUDIO_DRIVER_AHI
   261 	D(bug("WaitAudio...Done\n"));
   262 
   263 	audio->CloseAudio(audio);
   264 
   265 	D(bug("CloseAudio..Done, subtask exiting...\n"));
   266 	audio_configured = 0;
   267 #endif
   268 #ifdef __OS2__
   269 #ifdef DEBUG_BUILD
   270         printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
   271 #endif
   272 #endif
   273 	return(0);
   274 }
   275 
   276 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
   277 {
   278 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   279 		return;
   280 	}
   281 	SDL_mutexP(audio->mixer_lock);
   282 }
   283 
   284 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
   285 {
   286 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   287 		return;
   288 	}
   289 	SDL_mutexV(audio->mixer_lock);
   290 }
   291 
   292 int SDL_AudioInit(const char *driver_name)
   293 {
   294 	SDL_AudioDevice *audio;
   295 	int i = 0, idx;
   296 
   297 	/* Check to make sure we don't overwrite 'current_audio' */
   298 	if ( current_audio != NULL ) {
   299 		SDL_AudioQuit();
   300 	}
   301 
   302 	/* Select the proper audio driver */
   303 	audio = NULL;
   304 	idx = 0;
   305 #if SDL_AUDIO_DRIVER_ESD
   306 	if ( (driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL) ) {
   307 		/* Ahem, we know that if ESPEAKER is set, user probably wants
   308 		   to use ESD, but don't start it if it's not already running.
   309 		   This probably isn't the place to do this, but... Shh! :)
   310 		 */
   311 		for ( i=0; bootstrap[i]; ++i ) {
   312 			if ( SDL_strcmp(bootstrap[i]->name, "esd") == 0 ) {
   313 #ifdef HAVE_PUTENV
   314 				const char *esd_no_spawn;
   315 
   316 				/* Don't start ESD if it's not running */
   317 				esd_no_spawn = getenv("ESD_NO_SPAWN");
   318 				if ( esd_no_spawn == NULL ) {
   319 					putenv("ESD_NO_SPAWN=1");
   320 				}
   321 #endif
   322 				if ( bootstrap[i]->available() ) {
   323 					audio = bootstrap[i]->create(0);
   324 					break;
   325 				}
   326 #ifdef HAVE_UNSETENV
   327 				if ( esd_no_spawn == NULL ) {
   328 					unsetenv("ESD_NO_SPAWN");
   329 				}
   330 #endif
   331 			}
   332 		}
   333 	}
   334 #endif /* SDL_AUDIO_DRIVER_ESD */
   335 	if ( audio == NULL ) {
   336 		if ( driver_name != NULL ) {
   337 #if 0	/* This will be replaced with a better driver selection API */
   338 			if ( SDL_strrchr(driver_name, ':') != NULL ) {
   339 				idx = atoi(SDL_strrchr(driver_name, ':')+1);
   340 			}
   341 #endif
   342 			for ( i=0; bootstrap[i]; ++i ) {
   343 				if (SDL_strncmp(bootstrap[i]->name, driver_name,
   344 				            SDL_strlen(bootstrap[i]->name)) == 0) {
   345 					if ( bootstrap[i]->available() ) {
   346 						audio=bootstrap[i]->create(idx);
   347 						break;
   348 					}
   349 				}
   350 			}
   351 		} else {
   352 			for ( i=0; bootstrap[i]; ++i ) {
   353 				if ( bootstrap[i]->available() ) {
   354 					audio = bootstrap[i]->create(idx);
   355 					if ( audio != NULL ) {
   356 						break;
   357 					}
   358 				}
   359 			}
   360 		}
   361 		if ( audio == NULL ) {
   362 			SDL_SetError("No available audio device");
   363 #if 0 /* Don't fail SDL_Init() if audio isn't available.
   364          SDL_OpenAudio() will handle it at that point.  *sigh*
   365        */
   366 			return(-1);
   367 #endif
   368 		}
   369 	}
   370 	current_audio = audio;
   371 	if ( current_audio ) {
   372 		current_audio->name = bootstrap[i]->name;
   373 		if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
   374 			current_audio->LockAudio = SDL_LockAudio_Default;
   375 			current_audio->UnlockAudio = SDL_UnlockAudio_Default;
   376 		}
   377 	}
   378 	return(0);
   379 }
   380 
   381 char *SDL_AudioDriverName(char *namebuf, int maxlen)
   382 {
   383 	if ( current_audio != NULL ) {
   384 		SDL_strlcpy(namebuf, current_audio->name, maxlen);
   385 		return(namebuf);
   386 	}
   387 	return(NULL);
   388 }
   389 
   390 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
   391 {
   392 	SDL_AudioDevice *audio;
   393 
   394 	/* Start up the audio driver, if necessary */
   395 	if ( ! current_audio ) {
   396 		if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
   397 		     (current_audio == NULL) ) {
   398 			return(-1);
   399 		}
   400 	}
   401 	audio = current_audio;
   402 
   403 	if (audio->opened) {
   404 		SDL_SetError("Audio device is already opened");
   405 		return(-1);
   406 	}
   407 
   408 	/* Verify some parameters */
   409 	if ( desired->callback == NULL ) {
   410 		SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   411 		return(-1);
   412 	}
   413 	switch ( desired->channels ) {
   414 	    case 1:	/* Mono */
   415 	    case 2:	/* Stereo */
   416 	    case 4:	/* surround */
   417 	    case 6:	/* surround with center and lfe */
   418 		break;
   419 	    default:
   420 		SDL_SetError("1 (mono) and 2 (stereo) channels supported");
   421 		return(-1);
   422 	}
   423 
   424 #if defined(__MACOS__) || (defined(__RISCOS__) && SDL_THREADS_DISABLED)
   425 	/* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
   426 #else
   427 #if defined(__MINT__) && SDL_THREADS_DISABLED
   428 	/* Uses interrupt driven audio, without thread */
   429 #else
   430 	/* Create a semaphore for locking the sound buffers */
   431 	audio->mixer_lock = SDL_CreateMutex();
   432 	if ( audio->mixer_lock == NULL ) {
   433 		SDL_SetError("Couldn't create mixer lock");
   434 		SDL_CloseAudio();
   435 		return(-1);
   436 	}
   437 #endif /* __MINT__ */
   438 #endif /* __MACOS__ */
   439 
   440 	/* Calculate the silence and size of the audio specification */
   441 	SDL_CalculateAudioSpec(desired);
   442 
   443 	/* Open the audio subsystem */
   444 	SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
   445 	audio->convert.needed = 0;
   446 	audio->enabled = 1;
   447 	audio->paused  = 1;
   448 
   449 #if !SDL_AUDIO_DRIVER_AHI
   450 
   451 /* AmigaOS opens audio inside the main loop */
   452 	audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
   453 
   454 	if ( ! audio->opened ) {
   455 		SDL_CloseAudio();
   456 		return(-1);
   457 	}
   458 #else
   459 	D(bug("Locking semaphore..."));
   460 	SDL_mutexP(audio->mixer_lock);
   461 
   462 
   463 	audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   464 	D(bug("Created thread...\n"));
   465 
   466 	if ( audio->thread == NULL ) {
   467 		SDL_mutexV(audio->mixer_lock);
   468 		SDL_CloseAudio();
   469 		SDL_SetError("Couldn't create audio thread");
   470 		return(-1);
   471 	}
   472 
   473 	while(!audio_configured)
   474 		SDL_Delay(100);
   475 #endif
   476 
   477 	/* If the audio driver changes the buffer size, accept it */
   478 	if ( audio->spec.samples != desired->samples ) {
   479 		desired->samples = audio->spec.samples;
   480 		SDL_CalculateAudioSpec(desired);
   481 	}
   482 
   483 	/* Allocate a fake audio memory buffer */
   484 	audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
   485 	if ( audio->fake_stream == NULL ) {
   486 		SDL_CloseAudio();
   487 		SDL_OutOfMemory();
   488 		return(-1);
   489 	}
   490 
   491 	/* See if we need to do any conversion */
   492 	if ( obtained != NULL ) {
   493 		SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
   494 	} else if ( desired->freq != audio->spec.freq ||
   495                     desired->format != audio->spec.format ||
   496 	            desired->channels != audio->spec.channels ) {
   497 		/* Build an audio conversion block */
   498 		if ( SDL_BuildAudioCVT(&audio->convert,
   499 			desired->format, desired->channels,
   500 					desired->freq,
   501 			audio->spec.format, audio->spec.channels,
   502 					audio->spec.freq) < 0 ) {
   503 			SDL_CloseAudio();
   504 			return(-1);
   505 		}
   506 		if ( audio->convert.needed ) {
   507 			audio->convert.len = desired->size;
   508 			audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
   509 			   audio->convert.len*audio->convert.len_mult);
   510 			if ( audio->convert.buf == NULL ) {
   511 				SDL_CloseAudio();
   512 				SDL_OutOfMemory();
   513 				return(-1);
   514 			}
   515 		}
   516 	}
   517 
   518 #if !SDL_AUDIO_DRIVER_AHI
   519 	/* Start the audio thread if necessary */
   520 	switch (audio->opened) {
   521 		case  1:
   522 			/* Start the audio thread */
   523 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
   524 #undef SDL_CreateThread
   525 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
   526 #else
   527 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   528 #endif
   529 			if ( audio->thread == NULL ) {
   530 				SDL_CloseAudio();
   531 				SDL_SetError("Couldn't create audio thread");
   532 				return(-1);
   533 			}
   534 			break;
   535 
   536 		default:
   537 			/* The audio is now playing */
   538 			break;
   539 	}
   540 #else
   541 	SDL_mutexV(audio->mixer_lock);
   542 	D(bug("SDL_OpenAudio USCITA...\n"));
   543 
   544 #endif
   545 
   546 	return(0);
   547 }
   548 
   549 SDL_audiostatus SDL_GetAudioStatus(void)
   550 {
   551 	SDL_AudioDevice *audio = current_audio;
   552 	SDL_audiostatus status;
   553 
   554 	status = SDL_AUDIO_STOPPED;
   555 	if ( audio && audio->enabled ) {
   556 		if ( audio->paused ) {
   557 			status = SDL_AUDIO_PAUSED;
   558 		} else {
   559 			status = SDL_AUDIO_PLAYING;
   560 		}
   561 	}
   562 	return(status);
   563 }
   564 
   565 void SDL_PauseAudio (int pause_on)
   566 {
   567 	SDL_AudioDevice *audio = current_audio;
   568 
   569 	if ( audio ) {
   570 		audio->paused = pause_on;
   571 	}
   572 }
   573 
   574 void SDL_LockAudio (void)
   575 {
   576 	SDL_AudioDevice *audio = current_audio;
   577 
   578 	/* Obtain a lock on the mixing buffers */
   579 	if ( audio && audio->LockAudio ) {
   580 		audio->LockAudio(audio);
   581 	}
   582 }
   583 
   584 void SDL_UnlockAudio (void)
   585 {
   586 	SDL_AudioDevice *audio = current_audio;
   587 
   588 	/* Release lock on the mixing buffers */
   589 	if ( audio && audio->UnlockAudio ) {
   590 		audio->UnlockAudio(audio);
   591 	}
   592 }
   593 
   594 void SDL_CloseAudio (void)
   595 {
   596 	SDL_QuitSubSystem(SDL_INIT_AUDIO);
   597 }
   598 
   599 void SDL_AudioQuit(void)
   600 {
   601 	SDL_AudioDevice *audio = current_audio;
   602 
   603 	if ( audio ) {
   604 		audio->enabled = 0;
   605 		if ( audio->thread != NULL ) {
   606 			SDL_WaitThread(audio->thread, NULL);
   607 		}
   608 		if ( audio->mixer_lock != NULL ) {
   609 			SDL_DestroyMutex(audio->mixer_lock);
   610 		}
   611 		if ( audio->fake_stream != NULL ) {
   612 			SDL_FreeAudioMem(audio->fake_stream);
   613 		}
   614 		if ( audio->convert.needed ) {
   615 			SDL_FreeAudioMem(audio->convert.buf);
   616 
   617 		}
   618 #if !SDL_AUDIO_DRIVER_AHI
   619 		if ( audio->opened ) {
   620 			audio->CloseAudio(audio);
   621 			audio->opened = 0;
   622 		}
   623 #endif
   624 		/* Free the driver data */
   625 		audio->free(audio);
   626 		current_audio = NULL;
   627 	}
   628 }
   629 
   630 #define NUM_FORMATS	6
   631 static int format_idx;
   632 static int format_idx_sub;
   633 static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
   634  { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
   635  { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
   636  { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
   637  { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
   638  { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
   639  { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
   640 };
   641 
   642 Uint16 SDL_FirstAudioFormat(Uint16 format)
   643 {
   644 	for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
   645 		if ( format_list[format_idx][0] == format ) {
   646 			break;
   647 		}
   648 	}
   649 	format_idx_sub = 0;
   650 	return(SDL_NextAudioFormat());
   651 }
   652 
   653 Uint16 SDL_NextAudioFormat(void)
   654 {
   655 	if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
   656 		return(0);
   657 	}
   658 	return(format_list[format_idx][format_idx_sub++]);
   659 }
   660 
   661 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
   662 {
   663 	switch (spec->format) {
   664 		case AUDIO_U8:
   665 			spec->silence = 0x80;
   666 			break;
   667 		default:
   668 			spec->silence = 0x00;
   669 			break;
   670 	}
   671 	spec->size = (spec->format&0xFF)/8;
   672 	spec->size *= spec->channels;
   673 	spec->size *= spec->samples;
   674 }