src/audio/SDL_audio.c
author Sam Lantinga
Wed, 01 Feb 2006 06:32:25 +0000
changeset 1312 c9b51268668f
parent 1204 f9794ee91dfc
child 1330 450721ad5436
permissions -rw-r--r--
Updated copyright information and removed rcs id lines (problematic in branch merges)
I batch edited these files, so please let me know if I've accidentally removed anybody's
credit here.
     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 
    23 /* Allow access to a raw mixing buffer */
    24 #include <stdlib.h>
    25 #include <stdio.h>
    26 #include <string.h>
    27 
    28 #include "SDL.h"
    29 #include "SDL_audio.h"
    30 #include "SDL_timer.h"
    31 #include "SDL_error.h"
    32 #include "SDL_audio_c.h"
    33 #include "SDL_audiomem.h"
    34 #include "SDL_sysaudio.h"
    35 
    36 #ifdef __OS2__
    37 // We'll need the DosSetPriority() API!
    38 #define INCL_DOSPROCESS
    39 #include <os2.h>
    40 #endif
    41 
    42 /* Available audio drivers */
    43 static AudioBootStrap *bootstrap[] = {
    44 #ifdef OPENBSD_AUDIO_SUPPORT
    45 	&OPENBSD_AUDIO_bootstrap,
    46 #endif
    47 #ifdef OSS_SUPPORT
    48 	&DSP_bootstrap,
    49 	&DMA_bootstrap,
    50 #endif
    51 #ifdef ALSA_SUPPORT
    52 	&ALSA_bootstrap,
    53 #endif
    54 #ifdef QNXNTOAUDIO_SUPPORT
    55 	&QNXNTOAUDIO_bootstrap,
    56 #endif
    57 #ifdef SUNAUDIO_SUPPORT
    58 	&SUNAUDIO_bootstrap,
    59 #endif
    60 #ifdef DMEDIA_SUPPORT
    61 	&DMEDIA_bootstrap,
    62 #endif
    63 #ifdef ARTSC_SUPPORT
    64 	&ARTSC_bootstrap,
    65 #endif
    66 #ifdef ESD_SUPPORT
    67 	&ESD_bootstrap,
    68 #endif
    69 #ifdef NAS_SUPPORT
    70 	&NAS_bootstrap,
    71 #endif
    72 #ifdef ENABLE_DIRECTX
    73 	&DSOUND_bootstrap,
    74 #endif
    75 #ifdef ENABLE_WINDIB
    76 	&WAVEOUT_bootstrap,
    77 #endif
    78 #ifdef __BEOS__
    79 	&BAUDIO_bootstrap,
    80 #endif
    81 #ifdef MACOSX
    82 	&COREAUDIO_bootstrap,
    83 #endif
    84 #if defined(macintosh) || TARGET_API_MAC_CARBON
    85 	&SNDMGR_bootstrap,
    86 #endif
    87 #ifdef _AIX
    88 	&Paud_bootstrap,
    89 #endif
    90 #ifdef ENABLE_AHI
    91 	&AHI_bootstrap,
    92 #endif
    93 #ifdef MMEAUDIO_SUPPORT
    94 	&MMEAUDIO_bootstrap,
    95 #endif
    96 #ifdef MINTAUDIO_SUPPORT
    97 	&MINTAUDIO_GSXB_bootstrap,
    98 	&MINTAUDIO_MCSN_bootstrap,
    99 	&MINTAUDIO_STFA_bootstrap,
   100 	&MINTAUDIO_XBIOS_bootstrap,
   101 	&MINTAUDIO_DMA8_bootstrap,
   102 #endif
   103 #ifdef DISKAUD_SUPPORT
   104 	&DISKAUD_bootstrap,
   105 #endif
   106 #ifdef ENABLE_DC
   107 	&DCAUD_bootstrap,
   108 #endif
   109 #ifdef DRENDERER_SUPPORT
   110 	&DRENDERER_bootstrap,
   111 #endif
   112 #ifdef __OS2__
   113         &DART_bootstrap,
   114 #endif
   115 	NULL
   116 };
   117 SDL_AudioDevice *current_audio = NULL;
   118 
   119 /* Various local functions */
   120 int SDL_AudioInit(const char *driver_name);
   121 void SDL_AudioQuit(void);
   122 
   123 #ifdef ENABLE_AHI
   124 static int audio_configured = 0;
   125 #endif
   126 
   127 /* The general mixing thread function */
   128 int SDL_RunAudio(void *audiop)
   129 {
   130 	SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
   131 	Uint8 *stream;
   132 	int    stream_len;
   133 	void  *udata;
   134 	void (*fill)(void *userdata,Uint8 *stream, int len);
   135 	int    silence;
   136 #ifdef ENABLE_AHI
   137 	int started = 0;
   138 
   139 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
   140 
   141 	D(bug("Task audio started audio struct:<%lx>...\n",audiop));
   142 
   143 	D(bug("Before Openaudio..."));
   144 	if(audio->OpenAudio(audio, &audio->spec)==-1)
   145 	{
   146 		D(bug("Open audio failed...\n"));
   147 		return(-1);
   148 	}
   149 	D(bug("OpenAudio...OK\n"));
   150 #endif
   151 
   152 	/* Perform any thread setup */
   153 	if ( audio->ThreadInit ) {
   154 		audio->ThreadInit(audio);
   155 	}
   156 	audio->threadid = SDL_ThreadID();
   157 
   158 	/* Set up the mixing function */
   159 	fill  = audio->spec.callback;
   160 	udata = audio->spec.userdata;
   161 
   162 #ifdef ENABLE_AHI
   163 	audio_configured = 1;
   164 
   165 	D(bug("Audio configured... Checking for conversion\n"));
   166 	SDL_mutexP(audio->mixer_lock);
   167 	D(bug("Semaphore obtained...\n"));
   168 #endif
   169 
   170 	if ( audio->convert.needed ) {
   171 		if ( audio->convert.src_format == AUDIO_U8 ) {
   172 			silence = 0x80;
   173 		} else {
   174 			silence = 0;
   175 		}
   176 		stream_len = audio->convert.len;
   177 	} else {
   178 		silence = audio->spec.silence;
   179 		stream_len = audio->spec.size;
   180 	}
   181 	stream = audio->fake_stream;
   182 
   183 #ifdef ENABLE_AHI
   184 	SDL_mutexV(audio->mixer_lock);
   185 	D(bug("Entering audio loop...\n"));
   186 #endif
   187 
   188 #ifdef __OS2__
   189         // Increase the priority of this thread to make sure that
   190         // the audio will be continuous all the time!
   191 #ifdef USE_DOSSETPRIORITY
   192 #ifdef DEBUG_BUILD
   193         printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
   194 #endif
   195         DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
   196 #endif
   197 #endif
   198 
   199 	/* Loop, filling the audio buffers */
   200 	while ( audio->enabled ) {
   201 
   202 		/* Wait for new current buffer to finish playing */
   203 		if ( stream == audio->fake_stream ) {
   204 			SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
   205 		} else {
   206 #ifdef ENABLE_AHI
   207 			if ( started > 1 )
   208 #endif
   209 			audio->WaitAudio(audio);
   210 		}
   211 
   212 		/* Fill the current buffer with sound */
   213 		if ( audio->convert.needed ) {
   214 			if ( audio->convert.buf ) {
   215 				stream = audio->convert.buf;
   216 			} else {
   217 				continue;
   218 			}
   219 		} else {
   220 			stream = audio->GetAudioBuf(audio);
   221 			if ( stream == NULL ) {
   222 				stream = audio->fake_stream;
   223 			}
   224 		}
   225 		memset(stream, silence, stream_len);
   226 
   227 		if ( ! audio->paused ) {
   228 			SDL_mutexP(audio->mixer_lock);
   229 			(*fill)(udata, stream, stream_len);
   230 			SDL_mutexV(audio->mixer_lock);
   231 		}
   232 
   233 		/* Convert the audio if necessary */
   234 		if ( audio->convert.needed ) {
   235 			SDL_ConvertAudio(&audio->convert);
   236 			stream = audio->GetAudioBuf(audio);
   237 			if ( stream == NULL ) {
   238 				stream = audio->fake_stream;
   239 			}
   240 			memcpy(stream, audio->convert.buf,
   241 			               audio->convert.len_cvt);
   242 		}
   243 
   244 		/* Ready current buffer for play and change current buffer */
   245 		if ( stream != audio->fake_stream ) {
   246 			audio->PlayAudio(audio);
   247 #ifdef ENABLE_AHI
   248 /* AmigaOS don't have to wait the first time audio is played! */
   249 			started++;
   250 #endif
   251 		}
   252 	}
   253 	/* Wait for the audio to drain.. */
   254 	if ( audio->WaitDone ) {
   255 		audio->WaitDone(audio);
   256 	}
   257 
   258 #ifdef ENABLE_AHI
   259 	D(bug("WaitAudio...Done\n"));
   260 
   261 	audio->CloseAudio(audio);
   262 
   263 	D(bug("CloseAudio..Done, subtask exiting...\n"));
   264 	audio_configured = 0;
   265 #endif
   266 #ifdef __OS2__
   267 #ifdef DEBUG_BUILD
   268         printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
   269 #endif
   270 #endif
   271 	return(0);
   272 }
   273 
   274 static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
   275 {
   276 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   277 		return;
   278 	}
   279 	SDL_mutexP(audio->mixer_lock);
   280 }
   281 
   282 static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
   283 {
   284 	if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
   285 		return;
   286 	}
   287 	SDL_mutexV(audio->mixer_lock);
   288 }
   289 
   290 int SDL_AudioInit(const char *driver_name)
   291 {
   292 	SDL_AudioDevice *audio;
   293 	int i = 0, idx;
   294 
   295 	/* Check to make sure we don't overwrite 'current_audio' */
   296 	if ( current_audio != NULL ) {
   297 		SDL_AudioQuit();
   298 	}
   299 
   300 	/* Select the proper audio driver */
   301 	audio = NULL;
   302 	idx = 0;
   303 #ifdef unix
   304 	if ( (driver_name == NULL) && (getenv("ESPEAKER") != NULL) ) {
   305 		/* Ahem, we know that if ESPEAKER is set, user probably wants
   306 		   to use ESD, but don't start it if it's not already running.
   307 		   This probably isn't the place to do this, but... Shh! :)
   308 		 */
   309 		for ( i=0; bootstrap[i]; ++i ) {
   310 			if ( strcmp(bootstrap[i]->name, "esd") == 0 ) {
   311 				const char *esd_no_spawn;
   312 
   313 				/* Don't start ESD if it's not running */
   314 				esd_no_spawn = getenv("ESD_NO_SPAWN");
   315 				if ( esd_no_spawn == NULL ) {
   316 					putenv("ESD_NO_SPAWN=1");
   317 				}
   318 				if ( bootstrap[i]->available() ) {
   319 					audio = bootstrap[i]->create(0);
   320 					break;
   321 				}
   322 #ifdef linux	/* No unsetenv() on most platforms */
   323 				if ( esd_no_spawn == NULL ) {
   324 					unsetenv("ESD_NO_SPAWN");
   325 				}
   326 #endif
   327 			}
   328 		}
   329 	}
   330 #endif /* unix */
   331 	if ( audio == NULL ) {
   332 		if ( driver_name != NULL ) {
   333 #if 0	/* This will be replaced with a better driver selection API */
   334 			if ( strrchr(driver_name, ':') != NULL ) {
   335 				idx = atoi(strrchr(driver_name, ':')+1);
   336 			}
   337 #endif
   338 			for ( i=0; bootstrap[i]; ++i ) {
   339 				if (strncmp(bootstrap[i]->name, driver_name,
   340 				            strlen(bootstrap[i]->name)) == 0) {
   341 					if ( bootstrap[i]->available() ) {
   342 						audio=bootstrap[i]->create(idx);
   343 						break;
   344 					}
   345 				}
   346 			}
   347 		} else {
   348 			for ( i=0; bootstrap[i]; ++i ) {
   349 				if ( bootstrap[i]->available() ) {
   350 					audio = bootstrap[i]->create(idx);
   351 					if ( audio != NULL ) {
   352 						break;
   353 					}
   354 				}
   355 			}
   356 		}
   357 		if ( audio == NULL ) {
   358 			SDL_SetError("No available audio device");
   359 #if 0 /* Don't fail SDL_Init() if audio isn't available.
   360          SDL_OpenAudio() will handle it at that point.  *sigh*
   361        */
   362 			return(-1);
   363 #endif
   364 		}
   365 	}
   366 	current_audio = audio;
   367 	if ( current_audio ) {
   368 		current_audio->name = bootstrap[i]->name;
   369 		if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
   370 			current_audio->LockAudio = SDL_LockAudio_Default;
   371 			current_audio->UnlockAudio = SDL_UnlockAudio_Default;
   372 		}
   373 	}
   374 	return(0);
   375 }
   376 
   377 char *SDL_AudioDriverName(char *namebuf, int maxlen)
   378 {
   379 	if ( current_audio != NULL ) {
   380 		strncpy(namebuf, current_audio->name, maxlen-1);
   381 		namebuf[maxlen-1] = '\0';
   382 		return(namebuf);
   383 	}
   384 	return(NULL);
   385 }
   386 
   387 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
   388 {
   389 	SDL_AudioDevice *audio;
   390 
   391 	/* Start up the audio driver, if necessary */
   392 	if ( ! current_audio ) {
   393 		if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
   394 		     (current_audio == NULL) ) {
   395 			return(-1);
   396 		}
   397 	}
   398 	audio = current_audio;
   399 
   400 	if (audio->opened) {
   401 		SDL_SetError("Audio device is already opened");
   402 		return(-1);
   403 	}
   404 
   405 	/* Verify some parameters */
   406 	if ( desired->callback == NULL ) {
   407 		SDL_SetError("SDL_OpenAudio() passed a NULL callback");
   408 		return(-1);
   409 	}
   410 	switch ( desired->channels ) {
   411 	    case 1:	/* Mono */
   412 	    case 2:	/* Stereo */
   413 	    case 4:	/* surround */
   414 	    case 6:	/* surround with center and lfe */
   415 		break;
   416 	    default:
   417 		SDL_SetError("1 (mono) and 2 (stereo) channels supported");
   418 		return(-1);
   419 	}
   420 
   421 #if defined(macintosh) || (defined(__riscos__) && defined(DISABLE_THREADS))
   422 	/* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
   423 #else
   424 #if defined(__MINT__) && !defined(ENABLE_THREADS)
   425 	/* Uses interrupt driven audio, without thread */
   426 #else
   427 	/* Create a semaphore for locking the sound buffers */
   428 	audio->mixer_lock = SDL_CreateMutex();
   429 	if ( audio->mixer_lock == NULL ) {
   430 		SDL_SetError("Couldn't create mixer lock");
   431 		SDL_CloseAudio();
   432 		return(-1);
   433 	}
   434 #endif /* __MINT__ */
   435 #endif /* macintosh */
   436 
   437 	/* Calculate the silence and size of the audio specification */
   438 	SDL_CalculateAudioSpec(desired);
   439 
   440 	/* Open the audio subsystem */
   441 	memcpy(&audio->spec, desired, sizeof(audio->spec));
   442 	audio->convert.needed = 0;
   443 	audio->enabled = 1;
   444 	audio->paused  = 1;
   445 
   446 #ifndef ENABLE_AHI
   447 
   448 /* AmigaOS opens audio inside the main loop */
   449 	audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
   450 
   451 	if ( ! audio->opened ) {
   452 		SDL_CloseAudio();
   453 		return(-1);
   454 	}
   455 #else
   456 	D(bug("Locking semaphore..."));
   457 	SDL_mutexP(audio->mixer_lock);
   458 
   459 	audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   460 	D(bug("Created thread...\n"));
   461 
   462 	if ( audio->thread == NULL ) {
   463 		SDL_mutexV(audio->mixer_lock);
   464 		SDL_CloseAudio();
   465 		SDL_SetError("Couldn't create audio thread");
   466 		return(-1);
   467 	}
   468 
   469 	while(!audio_configured)
   470 		SDL_Delay(100);
   471 #endif
   472 
   473 	/* If the audio driver changes the buffer size, accept it */
   474 	if ( audio->spec.samples != desired->samples ) {
   475 		desired->samples = audio->spec.samples;
   476 		SDL_CalculateAudioSpec(desired);
   477 	}
   478 
   479 	/* Allocate a fake audio memory buffer */
   480 	audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
   481 	if ( audio->fake_stream == NULL ) {
   482 		SDL_CloseAudio();
   483 		SDL_OutOfMemory();
   484 		return(-1);
   485 	}
   486 
   487 	/* See if we need to do any conversion */
   488 	if ( obtained != NULL ) {
   489 		memcpy(obtained, &audio->spec, sizeof(audio->spec));
   490 	} else if ( desired->freq != audio->spec.freq ||
   491                     desired->format != audio->spec.format ||
   492 	            desired->channels != audio->spec.channels ) {
   493 		/* Build an audio conversion block */
   494 		if ( SDL_BuildAudioCVT(&audio->convert,
   495 			desired->format, desired->channels,
   496 					desired->freq,
   497 			audio->spec.format, audio->spec.channels,
   498 					audio->spec.freq) < 0 ) {
   499 			SDL_CloseAudio();
   500 			return(-1);
   501 		}
   502 		if ( audio->convert.needed ) {
   503 			audio->convert.len = desired->size;
   504 			audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
   505 			   audio->convert.len*audio->convert.len_mult);
   506 			if ( audio->convert.buf == NULL ) {
   507 				SDL_CloseAudio();
   508 				SDL_OutOfMemory();
   509 				return(-1);
   510 			}
   511 		}
   512 	}
   513 
   514 #ifndef ENABLE_AHI
   515 	/* Start the audio thread if necessary */
   516 	switch (audio->opened) {
   517 		case  1:
   518 			/* Start the audio thread */
   519 			audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
   520 			if ( audio->thread == NULL ) {
   521 				SDL_CloseAudio();
   522 				SDL_SetError("Couldn't create audio thread");
   523 				return(-1);
   524 			}
   525 			break;
   526 
   527 		default:
   528 			/* The audio is now playing */
   529 			break;
   530 	}
   531 #else
   532 	SDL_mutexV(audio->mixer_lock);
   533 	D(bug("SDL_OpenAudio USCITA...\n"));
   534 
   535 #endif
   536 
   537 	return(0);
   538 }
   539 
   540 SDL_audiostatus SDL_GetAudioStatus(void)
   541 {
   542 	SDL_AudioDevice *audio = current_audio;
   543 	SDL_audiostatus status;
   544 
   545 	status = SDL_AUDIO_STOPPED;
   546 	if ( audio && audio->enabled ) {
   547 		if ( audio->paused ) {
   548 			status = SDL_AUDIO_PAUSED;
   549 		} else {
   550 			status = SDL_AUDIO_PLAYING;
   551 		}
   552 	}
   553 	return(status);
   554 }
   555 
   556 void SDL_PauseAudio (int pause_on)
   557 {
   558 	SDL_AudioDevice *audio = current_audio;
   559 
   560 	if ( audio ) {
   561 		audio->paused = pause_on;
   562 	}
   563 }
   564 
   565 void SDL_LockAudio (void)
   566 {
   567 	SDL_AudioDevice *audio = current_audio;
   568 
   569 	/* Obtain a lock on the mixing buffers */
   570 	if ( audio && audio->LockAudio ) {
   571 		audio->LockAudio(audio);
   572 	}
   573 }
   574 
   575 void SDL_UnlockAudio (void)
   576 {
   577 	SDL_AudioDevice *audio = current_audio;
   578 
   579 	/* Release lock on the mixing buffers */
   580 	if ( audio && audio->UnlockAudio ) {
   581 		audio->UnlockAudio(audio);
   582 	}
   583 }
   584 
   585 void SDL_CloseAudio (void)
   586 {
   587 	SDL_QuitSubSystem(SDL_INIT_AUDIO);
   588 }
   589 
   590 void SDL_AudioQuit(void)
   591 {
   592 	SDL_AudioDevice *audio = current_audio;
   593 
   594 	if ( audio ) {
   595 		audio->enabled = 0;
   596 		if ( audio->thread != NULL ) {
   597 			SDL_WaitThread(audio->thread, NULL);
   598 		}
   599 		if ( audio->mixer_lock != NULL ) {
   600 			SDL_DestroyMutex(audio->mixer_lock);
   601 		}
   602 		if ( audio->fake_stream != NULL ) {
   603 			SDL_FreeAudioMem(audio->fake_stream);
   604 		}
   605 		if ( audio->convert.needed ) {
   606 			SDL_FreeAudioMem(audio->convert.buf);
   607 
   608 		}
   609 #ifndef ENABLE_AHI
   610 		if ( audio->opened ) {
   611 			audio->CloseAudio(audio);
   612 			audio->opened = 0;
   613 		}
   614 #endif
   615 		/* Free the driver data */
   616 		audio->free(audio);
   617 		current_audio = NULL;
   618 	}
   619 }
   620 
   621 #define NUM_FORMATS	6
   622 static int format_idx;
   623 static int format_idx_sub;
   624 static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
   625  { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
   626  { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
   627  { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
   628  { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
   629  { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
   630  { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
   631 };
   632 
   633 Uint16 SDL_FirstAudioFormat(Uint16 format)
   634 {
   635 	for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
   636 		if ( format_list[format_idx][0] == format ) {
   637 			break;
   638 		}
   639 	}
   640 	format_idx_sub = 0;
   641 	return(SDL_NextAudioFormat());
   642 }
   643 
   644 Uint16 SDL_NextAudioFormat(void)
   645 {
   646 	if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
   647 		return(0);
   648 	}
   649 	return(format_list[format_idx][format_idx_sub++]);
   650 }
   651 
   652 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
   653 {
   654 	switch (spec->format) {
   655 		case AUDIO_U8:
   656 			spec->silence = 0x80;
   657 			break;
   658 		default:
   659 			spec->silence = 0x00;
   660 			break;
   661 	}
   662 	spec->size = (spec->format&0xFF)/8;
   663 	spec->size *= spec->channels;
   664 	spec->size *= spec->samples;
   665 }