src/audio/SDL_audio.c
author Ryan C. Gordon
Wed, 23 Nov 2005 07:29:56 +0000
changeset 1190 173c063d4f55
parent 955 d74fbf56f2f6
child 1204 f9794ee91dfc
permissions -rw-r--r--
OS/2 port!

This was mostly, if not entirely, written by "Doodle" and "Caetano":
doodle@scenergy.dfmk.hu
daniel@caetano.eng.br

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