mixer.c
author Ozkan Sezer
Wed, 23 Sep 2020 05:32:00 +0300
branchSDL-1.2
changeset 1136 33a3817d1066
parent 1081 119300487b73
permissions -rw-r--r--
mixer.c: add missing dynamic_fluidsynth.h include -- fixes bug #5296.
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* $Id$ */
    23 
    24 #include <stdio.h>
    25 #include <stdlib.h>
    26 #include <string.h>
    27 
    28 #include "SDL_mutex.h"
    29 #include "SDL_endian.h"
    30 #include "SDL_timer.h"
    31 
    32 #include "SDL_mixer.h"
    33 #include "load_aiff.h"
    34 #include "load_voc.h"
    35 #include "load_ogg.h"
    36 #include "load_flac.h"
    37 #include "dynamic_fluidsynth.h"
    38 #include "dynamic_flac.h"
    39 #include "dynamic_mod.h"
    40 #include "dynamic_mp3.h"
    41 #include "dynamic_ogg.h"
    42 
    43 #define __MIX_INTERNAL_EFFECT__
    44 #include "effects_internal.h"
    45 
    46 /* Magic numbers for various audio file formats */
    47 #define RIFF		0x46464952		/* "RIFF" */
    48 #define WAVE		0x45564157		/* "WAVE" */
    49 #define FORM		0x4d524f46		/* "FORM" */
    50 #define OGGS		0x5367674f		/* "OggS" */
    51 #define CREA		0x61657243		/* "Crea" */
    52 #define FLAC		0x43614C66		/* "fLaC" */
    53 
    54 static int audio_opened = 0;
    55 static SDL_AudioSpec mixer;
    56 
    57 typedef struct _Mix_effectinfo
    58 {
    59 	Mix_EffectFunc_t callback;
    60 	Mix_EffectDone_t done_callback;
    61 	void *udata;
    62 	struct _Mix_effectinfo *next;
    63 } effect_info;
    64 
    65 static struct _Mix_Channel {
    66 	Mix_Chunk *chunk;
    67 	int playing;
    68 	int paused;
    69 	Uint8 *samples;
    70 	int volume;
    71 	int looping;
    72 	int tag;
    73 	Uint32 expire;
    74 	Uint32 start_time;
    75 	Mix_Fading fading;
    76 	int fade_volume;
    77 	int fade_volume_reset;
    78 	Uint32 fade_length;
    79 	Uint32 ticks_fade;
    80 	effect_info *effects;
    81 } *mix_channel = NULL;
    82 
    83 static effect_info *posteffects = NULL;
    84 
    85 static int num_channels;
    86 static int reserved_channels = 0;
    87 
    88 
    89 /* Support for hooking into the mixer callback system */
    90 static void (SDLCALL *mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
    91 static void *mix_postmix_data = NULL;
    92 
    93 /* rcg07062001 callback to alert when channels are done playing. */
    94 static void (SDLCALL *channel_done_callback)(int channel) = NULL;
    95 
    96 /* Music function declarations */
    97 extern int open_music(SDL_AudioSpec *mixer);
    98 extern void close_music(void);
    99 
   100 /* Support for user defined music functions, plus the default one */
   101 extern int volatile music_active;
   102 extern void SDLCALL music_mixer(void *udata, Uint8 *stream, int len);
   103 static void (SDLCALL *mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
   104 static void *music_data = NULL;
   105 
   106 /* rcg06042009 report available decoders at runtime. */
   107 static const char **chunk_decoders = NULL;
   108 static int num_decoders = 0;
   109 
   110 /* Semicolon-separated SoundFont paths */
   111 extern char* soundfont_paths;
   112 
   113 int Mix_GetNumChunkDecoders(void)
   114 {
   115 	return(num_decoders);
   116 }
   117 
   118 const char *Mix_GetChunkDecoder(int index)
   119 {
   120 	if ((index < 0) || (index >= num_decoders)) {
   121 		return NULL;
   122 	}
   123 	return(chunk_decoders[index]);
   124 }
   125 
   126 static void add_chunk_decoder(const char *decoder)
   127 {
   128 	void *ptr = SDL_realloc(chunk_decoders, (num_decoders + 1) * sizeof (const char *));
   129 	if (ptr == NULL) {
   130 		return;  /* oh well, go on without it. */
   131 	}
   132 	chunk_decoders = (const char **) ptr;
   133 	chunk_decoders[num_decoders++] = decoder;
   134 }
   135 
   136 /* rcg06192001 get linked library's version. */
   137 const SDL_version *Mix_Linked_Version(void)
   138 {
   139 	static SDL_version linked_version;
   140 	SDL_MIXER_VERSION(&linked_version);
   141 	return(&linked_version);
   142 }
   143 
   144 static int initialized = 0;
   145 
   146 int Mix_Init(int flags)
   147 {
   148 	int result = 0;
   149 
   150 #ifdef MIX_INIT_SOUNDFONT_PATHS
   151 	if (!soundfont_paths)
   152 		soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
   153 #endif
   154 
   155 	if (flags & MIX_INIT_FLUIDSYNTH) {
   156 #ifdef USE_FLUIDSYNTH_MIDI
   157 		if ((initialized & MIX_INIT_FLUIDSYNTH) || Mix_InitFluidSynth() == 0) {
   158 			result |= MIX_INIT_FLUIDSYNTH;
   159 		}
   160 #else
   161 		Mix_SetError("Mixer not built with FluidSynth support");
   162 #endif
   163 	}
   164 	if (flags & MIX_INIT_FLAC) {
   165 #ifdef FLAC_MUSIC
   166 		if ((initialized & MIX_INIT_FLAC) || Mix_InitFLAC() == 0) {
   167 			result |= MIX_INIT_FLAC;
   168 		}
   169 #else
   170 		Mix_SetError("Mixer not built with FLAC support");
   171 #endif
   172 	}
   173 	if (flags & MIX_INIT_MOD) {
   174 #ifdef MOD_MUSIC
   175 		if ((initialized & MIX_INIT_MOD) || Mix_InitMOD() == 0) {
   176 			result |= MIX_INIT_MOD;
   177 		}
   178 #else
   179 		Mix_SetError("Mixer not built with MOD support");
   180 #endif
   181 	}
   182 	if (flags & MIX_INIT_MP3) {
   183 #ifdef MP3_MUSIC
   184 		if ((initialized & MIX_INIT_MP3) || Mix_InitMP3() == 0) {
   185 			result |= MIX_INIT_MP3;
   186 		}
   187 #elif defined(MP3_MAD_MUSIC)
   188 		result |= MIX_INIT_MP3;
   189 #else
   190 		Mix_SetError("Mixer not built with MP3 support");
   191 #endif
   192 	}
   193 	if (flags & MIX_INIT_OGG) {
   194 #ifdef OGG_MUSIC
   195 		if ((initialized & MIX_INIT_OGG) || Mix_InitOgg() == 0) {
   196 			result |= MIX_INIT_OGG;
   197 		}
   198 #else
   199 		Mix_SetError("Mixer not built with Ogg Vorbis support");
   200 #endif
   201 	}
   202 	initialized |= result;
   203 
   204 	return (result);
   205 }
   206 
   207 void Mix_Quit(void)
   208 {
   209 #ifdef USE_FLUIDSYNTH_MIDI
   210 	if (initialized & MIX_INIT_FLUIDSYNTH) {
   211 		Mix_QuitFluidSynth();
   212 	}
   213 #endif
   214 #ifdef FLAC_MUSIC
   215 	if (initialized & MIX_INIT_FLAC) {
   216 		Mix_QuitFLAC();
   217 	}
   218 #endif
   219 #ifdef MOD_MUSIC
   220 	if (initialized & MIX_INIT_MOD) {
   221 		Mix_QuitMOD();
   222 	}
   223 #endif
   224 #ifdef MP3_MUSIC
   225 	if (initialized & MIX_INIT_MP3) {
   226 		Mix_QuitMP3();
   227 	}
   228 #endif
   229 #ifdef OGG_MUSIC
   230 	if (initialized & MIX_INIT_OGG) {
   231 		Mix_QuitOgg();
   232 	}
   233 #endif
   234 	if (soundfont_paths) {
   235 		SDL_free(soundfont_paths);
   236 		soundfont_paths=NULL;
   237 	}
   238 	initialized = 0;
   239 }
   240 
   241 static int _Mix_remove_all_effects(int channel, effect_info **e);
   242 
   243 /*
   244  * rcg06122001 Cleanup effect callbacks.
   245  *  MAKE SURE SDL_LockAudio() is called before this (or you're in the
   246  *   audio callback).
   247  */
   248 static void _Mix_channel_done_playing(int channel)
   249 {
   250 	if (channel_done_callback) {
   251 	    channel_done_callback(channel);
   252 	}
   253 
   254 	/*
   255 	 * Call internal function directly, to avoid locking audio from
   256 	 *   inside audio callback.
   257 	 */
   258 	_Mix_remove_all_effects(channel, &mix_channel[channel].effects);
   259 }
   260 
   261 
   262 static void *Mix_DoEffects(int chan, void *snd, int len)
   263 {
   264 	int posteffect = (chan == MIX_CHANNEL_POST);
   265 	effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects);
   266 	void *buf = snd;
   267 
   268 	if (e != NULL) {    /* are there any registered effects? */
   269 		/* if this is the postmix, we can just overwrite the original. */
   270 		if (!posteffect) {
   271 			buf = SDL_malloc(len);
   272 			if (buf == NULL) {
   273 				return(snd);
   274 			}
   275 			memcpy(buf, snd, len);
   276 		}
   277 
   278 		for (; e != NULL; e = e->next) {
   279 			if (e->callback != NULL) {
   280 				e->callback(chan, buf, len, e->udata);
   281 			}
   282 		}
   283 	}
   284 
   285 	/* be sure to SDL_free() the return value if != snd ... */
   286 	return(buf);
   287 }
   288 
   289 
   290 /* Mixing function */
   291 static void SDLCALL mix_channels(void *udata, Uint8 *stream, int len)
   292 {
   293 	Uint8 *mix_input;
   294 	int i, mixable, volume = SDL_MIX_MAXVOLUME;
   295 	Uint32 sdl_ticks;
   296 
   297 #if SDL_VERSION_ATLEAST(1, 3, 0)
   298 	/* Need to initialize the stream in SDL 1.3+ */
   299 	memset(stream, mixer.silence, len);
   300 #endif
   301 
   302 	/* Mix the music (must be done before the channels are added) */
   303 	if ( music_active || (mix_music != music_mixer) ) {
   304 		mix_music(music_data, stream, len);
   305 	}
   306 
   307 	/* Mix any playing channels... */
   308 	sdl_ticks = SDL_GetTicks();
   309 	for ( i=0; i<num_channels; ++i ) {
   310 		if( ! mix_channel[i].paused ) {
   311 			if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) {
   312 				/* Expiration delay for that channel is reached */
   313 				mix_channel[i].playing = 0;
   314 				mix_channel[i].looping = 0;
   315 				mix_channel[i].fading = MIX_NO_FADING;
   316 				mix_channel[i].expire = 0;
   317 				_Mix_channel_done_playing(i);
   318 			} else if ( mix_channel[i].fading != MIX_NO_FADING ) {
   319 				Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
   320 				if ( ticks >= mix_channel[i].fade_length ) {
   321 					Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
   322 					if( mix_channel[i].fading == MIX_FADING_OUT ) {
   323 						mix_channel[i].playing = 0;
   324 						mix_channel[i].looping = 0;
   325 						mix_channel[i].expire = 0;
   326 						_Mix_channel_done_playing(i);
   327 					}
   328 					mix_channel[i].fading = MIX_NO_FADING;
   329 				} else {
   330 					if( mix_channel[i].fading == MIX_FADING_OUT ) {
   331 						Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
   332 								   / mix_channel[i].fade_length );
   333 					} else {
   334 						Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
   335 					}
   336 				}
   337 			}
   338 			if ( mix_channel[i].playing > 0 ) {
   339 				int index = 0;
   340 				int remaining = len;
   341 				while (mix_channel[i].playing > 0 && index < len) {
   342 					remaining = len - index;
   343 					volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
   344 					mixable = mix_channel[i].playing;
   345 					if ( mixable > remaining ) {
   346 						mixable = remaining;
   347 					}
   348 
   349 					mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
   350 					SDL_MixAudio(stream+index,mix_input,mixable,volume);
   351 					if (mix_input != mix_channel[i].samples)
   352 						SDL_free(mix_input);
   353 
   354 					mix_channel[i].samples += mixable;
   355 					mix_channel[i].playing -= mixable;
   356 					index += mixable;
   357 
   358 					/* rcg06072001 Alert app if channel is done playing. */
   359 					if (!mix_channel[i].playing && !mix_channel[i].looping) {
   360 						_Mix_channel_done_playing(i);
   361 					}
   362 				}
   363 
   364 				/* If looping the sample and we are at its end, make sure
   365 				   we will still return a full buffer */
   366 				while ( mix_channel[i].looping && index < len ) {
   367 					int alen = mix_channel[i].chunk->alen;
   368 					remaining = len - index;
   369 					if (remaining > alen) {
   370 						remaining = alen;
   371 					}
   372 
   373 					mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
   374 					SDL_MixAudio(stream+index, mix_input, remaining, volume);
   375 					if (mix_input != mix_channel[i].chunk->abuf)
   376 						SDL_free(mix_input);
   377 
   378 					if (mix_channel[i].looping > 0) {
   379 						--mix_channel[i].looping;
   380 					}
   381 					mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
   382 					mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
   383 					index += remaining;
   384 				}
   385 				if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
   386 					if (mix_channel[i].looping > 0) {
   387 						--mix_channel[i].looping;
   388 					}
   389 					mix_channel[i].samples = mix_channel[i].chunk->abuf;
   390 					mix_channel[i].playing = mix_channel[i].chunk->alen;
   391 				}
   392 			}
   393 		}
   394 	}
   395 
   396 	/* rcg06122001 run posteffects... */
   397 	Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
   398 
   399 	if ( mix_postmix ) {
   400 		mix_postmix(mix_postmix_data, stream, len);
   401 	}
   402 }
   403 
   404 #if 0
   405 static void PrintFormat(char *title, SDL_AudioSpec *fmt)
   406 {
   407 	printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
   408 			(fmt->format&0x8000) ? "signed" : "unsigned",
   409 			(fmt->channels > 2) ? "surround" :
   410 			(fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
   411 }
   412 #endif
   413 
   414 
   415 /* Open the mixer with a certain desired audio format */
   416 int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
   417 {
   418 	int i;
   419 	SDL_AudioSpec desired;
   420 
   421 	/* If the mixer is already opened, increment open count */
   422 	if ( audio_opened ) {
   423 		if ( format == mixer.format && nchannels == mixer.channels ) {
   424 			++audio_opened;
   425 			return(0);
   426 		}
   427 		while ( audio_opened ) {
   428 			Mix_CloseAudio();
   429 		}
   430 	}
   431 
   432 	/* Set the desired format and frequency */
   433 	desired.freq = frequency;
   434 	desired.format = format;
   435 	desired.channels = nchannels;
   436 	desired.samples = chunksize;
   437 	desired.callback = mix_channels;
   438 	desired.userdata = NULL;
   439 
   440 	/* Accept nearly any audio format */
   441 	if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
   442 		return(-1);
   443 	}
   444 #if 0
   445 	PrintFormat("Audio device", &mixer);
   446 #endif
   447 
   448 	/* Initialize the music players */
   449 	if ( open_music(&mixer) < 0 ) {
   450 		SDL_CloseAudio();
   451 		return(-1);
   452 	}
   453 
   454 	num_channels = MIX_CHANNELS;
   455 	mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
   456 
   457 	/* Clear out the audio channels */
   458 	for ( i=0; i<num_channels; ++i ) {
   459 		mix_channel[i].chunk = NULL;
   460 		mix_channel[i].playing = 0;
   461 		mix_channel[i].looping = 0;
   462 		mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   463 		mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   464 		mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   465 		mix_channel[i].fading = MIX_NO_FADING;
   466 		mix_channel[i].tag = -1;
   467 		mix_channel[i].expire = 0;
   468 		mix_channel[i].effects = NULL;
   469 		mix_channel[i].paused = 0;
   470 	}
   471 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   472 
   473 	_Mix_InitEffects();
   474 
   475 	/* This list is (currently) decided at build time. */
   476 	add_chunk_decoder("WAVE");
   477 	add_chunk_decoder("AIFF");
   478 	add_chunk_decoder("VOC");
   479 #ifdef OGG_MUSIC
   480 	add_chunk_decoder("OGG");
   481 #endif
   482 #ifdef FLAC_MUSIC
   483 	add_chunk_decoder("FLAC");
   484 #endif
   485 
   486 	audio_opened = 1;
   487 	SDL_PauseAudio(0);
   488 	return(0);
   489 }
   490 
   491 /* Dynamically change the number of channels managed by the mixer.
   492    If decreasing the number of channels, the upper channels are
   493    stopped.
   494  */
   495 int Mix_AllocateChannels(int numchans)
   496 {
   497 	if ( numchans<0 || numchans==num_channels )
   498 		return(num_channels);
   499 
   500 	if ( numchans < num_channels ) {
   501 		/* Stop the affected channels */
   502 		int i;
   503 		for(i=numchans; i < num_channels; i++) {
   504 			Mix_UnregisterAllEffects(i);
   505 			Mix_HaltChannel(i);
   506 		}
   507 	}
   508 	SDL_LockAudio();
   509 	mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
   510 	if ( numchans > num_channels ) {
   511 		/* Initialize the new channels */
   512 		int i;
   513 		for(i=num_channels; i < numchans; i++) {
   514 			mix_channel[i].chunk = NULL;
   515 			mix_channel[i].playing = 0;
   516 			mix_channel[i].looping = 0;
   517 			mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   518 			mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   519 			mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   520 			mix_channel[i].fading = MIX_NO_FADING;
   521 			mix_channel[i].tag = -1;
   522 			mix_channel[i].expire = 0;
   523 			mix_channel[i].effects = NULL;
   524 			mix_channel[i].paused = 0;
   525 		}
   526 	}
   527 	num_channels = numchans;
   528 	SDL_UnlockAudio();
   529 	return(num_channels);
   530 }
   531 
   532 /* Return the actual mixer parameters */
   533 int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
   534 {
   535 	if ( audio_opened ) {
   536 		if ( frequency ) {
   537 			*frequency = mixer.freq;
   538 		}
   539 		if ( format ) {
   540 			*format = mixer.format;
   541 		}
   542 		if ( channels ) {
   543 			*channels = mixer.channels;
   544 		}
   545 	}
   546 	return(audio_opened);
   547 }
   548 
   549 
   550 /*
   551  * !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the
   552  *             generic setup, then call the correct file format loader.
   553  */
   554 
   555 /* Load a wave file */
   556 Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
   557 {
   558 	Uint32 magic;
   559 	Mix_Chunk *chunk;
   560 	SDL_AudioSpec wavespec, *loaded;
   561 	SDL_AudioCVT wavecvt;
   562 	int samplesize;
   563 
   564 	/* rcg06012001 Make sure src is valid */
   565 	if ( ! src ) {
   566 		SDL_SetError("Mix_LoadWAV_RW with NULL src");
   567 		return(NULL);
   568 	}
   569 
   570 	/* Make sure audio has been opened */
   571 	if ( ! audio_opened ) {
   572 		SDL_SetError("Audio device hasn't been opened");
   573 		if ( freesrc && src ) {
   574 			SDL_RWclose(src);
   575 		}
   576 		return(NULL);
   577 	}
   578 
   579 	/* Allocate the chunk memory */
   580 	chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   581 	if ( chunk == NULL ) {
   582 		SDL_SetError("Out of memory");
   583 		if ( freesrc ) {
   584 			SDL_RWclose(src);
   585 		}
   586 		return(NULL);
   587 	}
   588 
   589 	/* Find out what kind of audio file this is */
   590 	magic = SDL_ReadLE32(src);
   591 	/* Seek backwards for compatibility with older loaders */
   592 	SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
   593 
   594 	switch (magic) {
   595 		case WAVE:
   596 		case RIFF:
   597 			loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
   598 					(Uint8 **)&chunk->abuf, &chunk->alen);
   599 			break;
   600 		case FORM:
   601 			loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
   602 					(Uint8 **)&chunk->abuf, &chunk->alen);
   603 			break;
   604 #ifdef OGG_MUSIC
   605 		case OGGS:
   606 			loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
   607 					(Uint8 **)&chunk->abuf, &chunk->alen);
   608 			break;
   609 #endif
   610 #ifdef FLAC_MUSIC
   611 		case FLAC:
   612 			loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
   613 					(Uint8 **)&chunk->abuf, &chunk->alen);
   614 			break;
   615 #endif
   616 		case CREA:
   617 			loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
   618 					(Uint8 **)&chunk->abuf, &chunk->alen);
   619 			break;
   620 		default:
   621 			SDL_SetError("Unrecognized sound file type");
   622 			if ( freesrc ) {
   623 				SDL_RWclose(src);
   624 			}
   625 			loaded = NULL;
   626 			break;
   627 	}
   628 	if ( !loaded ) {
   629 		/* The individual loaders have closed src if needed */
   630 		SDL_free(chunk);
   631 		return(NULL);
   632 	}
   633 
   634 #if 0
   635 	PrintFormat("Audio device", &mixer);
   636 	PrintFormat("-- Wave file", &wavespec);
   637 #endif
   638 
   639 	/* Build the audio converter and create conversion buffers */
   640 	if ( wavespec.format != mixer.format ||
   641 		 wavespec.channels != mixer.channels ||
   642 		 wavespec.freq != mixer.freq ) {
   643 		if ( SDL_BuildAudioCVT(&wavecvt,
   644 				wavespec.format, wavespec.channels, wavespec.freq,
   645 				mixer.format, mixer.channels, mixer.freq) < 0 ) {
   646 			SDL_free(chunk->abuf);
   647 			SDL_free(chunk);
   648 			return(NULL);
   649 		}
   650 		samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
   651 		wavecvt.len = chunk->alen & ~(samplesize-1);
   652 		wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
   653 		if ( wavecvt.buf == NULL ) {
   654 			SDL_SetError("Out of memory");
   655 			SDL_free(chunk->abuf);
   656 			SDL_free(chunk);
   657 			return(NULL);
   658 		}
   659 		memcpy(wavecvt.buf, chunk->abuf, wavecvt.len);
   660 		SDL_free(chunk->abuf);
   661 
   662 		/* Run the audio converter */
   663 		if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
   664 			SDL_free(wavecvt.buf);
   665 			SDL_free(chunk);
   666 			return(NULL);
   667 		}
   668 
   669 		chunk->abuf = wavecvt.buf;
   670 		chunk->alen = wavecvt.len_cvt;
   671 	}
   672 
   673 	chunk->allocated = 1;
   674 	chunk->volume = MIX_MAX_VOLUME;
   675 
   676 	return(chunk);
   677 }
   678 
   679 /* Load a wave file of the mixer format from a memory buffer */
   680 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
   681 {
   682 	Mix_Chunk *chunk;
   683 	Uint8 magic[4];
   684 
   685 	/* Make sure audio has been opened */
   686 	if ( ! audio_opened ) {
   687 		SDL_SetError("Audio device hasn't been opened");
   688 		return(NULL);
   689 	}
   690 
   691 	/* Allocate the chunk memory */
   692 	chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
   693 	if ( chunk == NULL ) {
   694 		SDL_SetError("Out of memory");
   695 		return(NULL);
   696 	}
   697 
   698 	/* Essentially just skip to the audio data (no error checking - fast) */
   699 	chunk->allocated = 0;
   700 	mem += 12; /* WAV header */
   701 	do {
   702 		memcpy(magic, mem, 4);
   703 		mem += 4;
   704 		chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
   705 		mem += 4;
   706 		chunk->abuf = mem;
   707 		mem += chunk->alen;
   708 	} while ( memcmp(magic, "data", 4) != 0 );
   709 	chunk->volume = MIX_MAX_VOLUME;
   710 
   711 	return(chunk);
   712 }
   713 
   714 /* Load raw audio data of the mixer format from a memory buffer */
   715 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
   716 {
   717 	Mix_Chunk *chunk;
   718 
   719 	/* Make sure audio has been opened */
   720 	if ( ! audio_opened ) {
   721 		SDL_SetError("Audio device hasn't been opened");
   722 		return(NULL);
   723 	}
   724 
   725 	/* Allocate the chunk memory */
   726 	chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   727 	if ( chunk == NULL ) {
   728 		SDL_SetError("Out of memory");
   729 		return(NULL);
   730 	}
   731 
   732 	/* Essentially just point at the audio data (no error checking - fast) */
   733 	chunk->allocated = 0;
   734 	chunk->alen = len;
   735 	chunk->abuf = mem;
   736 	chunk->volume = MIX_MAX_VOLUME;
   737 
   738 	return(chunk);
   739 }
   740 
   741 /* Free an audio chunk previously loaded */
   742 void Mix_FreeChunk(Mix_Chunk *chunk)
   743 {
   744 	int i;
   745 
   746 	/* Caution -- if the chunk is playing, the mixer will crash */
   747 	if ( chunk ) {
   748 		/* Guarantee that this chunk isn't playing */
   749 		SDL_LockAudio();
   750 		if ( mix_channel ) {
   751 			for ( i=0; i<num_channels; ++i ) {
   752 				if ( chunk == mix_channel[i].chunk ) {
   753 					mix_channel[i].playing = 0;
   754 					mix_channel[i].looping = 0;
   755 				}
   756 			}
   757 		}
   758 		SDL_UnlockAudio();
   759 		/* Actually free the chunk */
   760 		if ( chunk->allocated ) {
   761 			SDL_free(chunk->abuf);
   762 		}
   763 		SDL_free(chunk);
   764 	}
   765 }
   766 
   767 /* Set a function that is called after all mixing is performed.
   768    This can be used to provide real-time visual display of the audio stream
   769    or add a custom mixer filter for the stream data.
   770 */
   771 void Mix_SetPostMix(void (SDLCALL *mix_func)
   772                     (void *udata, Uint8 *stream, int len), void *arg)
   773 {
   774 	SDL_LockAudio();
   775 	mix_postmix_data = arg;
   776 	mix_postmix = mix_func;
   777 	SDL_UnlockAudio();
   778 }
   779 
   780 /* Add your own music player or mixer function.
   781    If 'mix_func' is NULL, the default music player is re-enabled.
   782  */
   783 void Mix_HookMusic(void (SDLCALL *mix_func)(void *udata, Uint8 *stream, int len),
   784                                                                 void *arg)
   785 {
   786 	SDL_LockAudio();
   787 	if ( mix_func != NULL ) {
   788 		music_data = arg;
   789 		mix_music = mix_func;
   790 	} else {
   791 		music_data = NULL;
   792 		mix_music = music_mixer;
   793 	}
   794 	SDL_UnlockAudio();
   795 }
   796 
   797 void *Mix_GetMusicHookData(void)
   798 {
   799 	return(music_data);
   800 }
   801 
   802 void Mix_ChannelFinished(void (SDLCALL *channel_finished)(int channel))
   803 {
   804 	SDL_LockAudio();
   805 	channel_done_callback = channel_finished;
   806 	SDL_UnlockAudio();
   807 }
   808 
   809 
   810 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
   811    them dynamically to the next sample if requested with a -1 value below.
   812    Returns the number of reserved channels.
   813  */
   814 int Mix_ReserveChannels(int num)
   815 {
   816 	if (num > num_channels)
   817 		num = num_channels;
   818 	reserved_channels = num;
   819 	return num;
   820 }
   821 
   822 static int checkchunkintegral(Mix_Chunk *chunk)
   823 {
   824 	int frame_width = 1;
   825 
   826 	if ((mixer.format & 0xFF) == 16) frame_width = 2;
   827 	frame_width *= mixer.channels;
   828 	while (chunk->alen % frame_width) chunk->alen--;
   829 	return chunk->alen;
   830 }
   831 
   832 /* Play an audio chunk on a specific channel.
   833    If the specified channel is -1, play on the first free channel.
   834    'ticks' is the number of milliseconds at most to play the sample, or -1
   835    if there is no limit.
   836    Returns which channel was used to play the sound.
   837 */
   838 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   839 {
   840 	int i;
   841 
   842 	/* Don't play null pointers :-) */
   843 	if ( chunk == NULL ) {
   844 		Mix_SetError("Tried to play a NULL chunk");
   845 		return(-1);
   846 	}
   847 	if ( !checkchunkintegral(chunk)) {
   848 		Mix_SetError("Tried to play a chunk with a bad frame");
   849 		return(-1);
   850 	}
   851 
   852 	/* Lock the mixer while modifying the playing channels */
   853 	SDL_LockAudio();
   854 	{
   855 		/* If which is -1, play on the first free channel */
   856 		if ( which == -1 ) {
   857 			for ( i=reserved_channels; i<num_channels; ++i ) {
   858 				if ( mix_channel[i].playing <= 0 )
   859 					break;
   860 			}
   861 			if ( i == num_channels ) {
   862 				Mix_SetError("No free channels available");
   863 				which = -1;
   864 			} else {
   865 				which = i;
   866 			}
   867 		}
   868 
   869 		/* Queue up the audio data for this channel */
   870 		if ( which >= 0 && which < num_channels ) {
   871 			Uint32 sdl_ticks = SDL_GetTicks();
   872 			if (Mix_Playing(which))
   873 				_Mix_channel_done_playing(which);
   874 			mix_channel[which].samples = chunk->abuf;
   875 			mix_channel[which].playing = chunk->alen;
   876 			mix_channel[which].looping = loops;
   877 			mix_channel[which].chunk = chunk;
   878 			mix_channel[which].paused = 0;
   879 			mix_channel[which].fading = MIX_NO_FADING;
   880 			mix_channel[which].start_time = sdl_ticks;
   881 			mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
   882 		}
   883 	}
   884 	SDL_UnlockAudio();
   885 
   886 	/* Return the channel on which the sound is being played */
   887 	return(which);
   888 }
   889 
   890 /* Change the expiration delay for a channel */
   891 int Mix_ExpireChannel(int which, int ticks)
   892 {
   893 	int status = 0;
   894 
   895 	if ( which == -1 ) {
   896 		int i;
   897 		for ( i=0; i < num_channels; ++ i ) {
   898 			status += Mix_ExpireChannel(i, ticks);
   899 		}
   900 	} else if ( which < num_channels ) {
   901 		SDL_LockAudio();
   902 		mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
   903 		SDL_UnlockAudio();
   904 		++ status;
   905 	}
   906 	return(status);
   907 }
   908 
   909 /* Fade in a sound on a channel, over ms milliseconds */
   910 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
   911 {
   912 	int i;
   913 
   914 	/* Don't play null pointers :-) */
   915 	if ( chunk == NULL ) {
   916 		return(-1);
   917 	}
   918 	if ( !checkchunkintegral(chunk)) {
   919 		Mix_SetError("Tried to play a chunk with a bad frame");
   920 		return(-1);
   921 	}
   922 
   923 	/* Lock the mixer while modifying the playing channels */
   924 	SDL_LockAudio();
   925 	{
   926 		/* If which is -1, play on the first free channel */
   927 		if ( which == -1 ) {
   928 			for ( i=reserved_channels; i<num_channels; ++i ) {
   929 				if ( mix_channel[i].playing <= 0 )
   930 					break;
   931 			}
   932 			if ( i == num_channels ) {
   933 				which = -1;
   934 			} else {
   935 				which = i;
   936 			}
   937 		}
   938 
   939 		/* Queue up the audio data for this channel */
   940 		if ( which >= 0 && which < num_channels ) {
   941 			Uint32 sdl_ticks = SDL_GetTicks();
   942 			if (Mix_Playing(which))
   943 				_Mix_channel_done_playing(which);
   944 			mix_channel[which].samples = chunk->abuf;
   945 			mix_channel[which].playing = chunk->alen;
   946 			mix_channel[which].looping = loops;
   947 			mix_channel[which].chunk = chunk;
   948 			mix_channel[which].paused = 0;
   949 			if (mix_channel[which].fading == MIX_NO_FADING) {
   950 			    mix_channel[which].fade_volume_reset = mix_channel[which].volume;
   951 			}
   952 			mix_channel[which].fading = MIX_FADING_IN;
   953 			mix_channel[which].fade_volume = mix_channel[which].volume;
   954 			mix_channel[which].volume = 0;
   955 			mix_channel[which].fade_length = (Uint32)ms;
   956 			mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
   957 			mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
   958 		}
   959 	}
   960 	SDL_UnlockAudio();
   961 
   962 	/* Return the channel on which the sound is being played */
   963 	return(which);
   964 }
   965 
   966 /* Set volume of a particular channel */
   967 int Mix_Volume(int which, int volume)
   968 {
   969 	int i;
   970 	int prev_volume = 0;
   971 
   972 	if ( which == -1 ) {
   973 		for ( i=0; i<num_channels; ++i ) {
   974 			prev_volume += Mix_Volume(i, volume);
   975 		}
   976 		prev_volume /= num_channels;
   977 	} else if ( which < num_channels ) {
   978 		prev_volume = mix_channel[which].volume;
   979 		if ( volume >= 0 ) {
   980 			if ( volume > SDL_MIX_MAXVOLUME ) {
   981 				volume = SDL_MIX_MAXVOLUME;
   982 			}
   983 			mix_channel[which].volume = volume;
   984 		}
   985 	}
   986 	return(prev_volume);
   987 }
   988 /* Set volume of a particular chunk */
   989 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
   990 {
   991 	int prev_volume;
   992 
   993 	prev_volume = chunk->volume;
   994 	if ( volume >= 0 ) {
   995 		if ( volume > MIX_MAX_VOLUME ) {
   996 			volume = MIX_MAX_VOLUME;
   997 		}
   998 		chunk->volume = volume;
   999 	}
  1000 	return(prev_volume);
  1001 }
  1002 
  1003 /* Halt playing of a particular channel */
  1004 int Mix_HaltChannel(int which)
  1005 {
  1006 	int i;
  1007 
  1008 	if ( which == -1 ) {
  1009 		for ( i=0; i<num_channels; ++i ) {
  1010 			Mix_HaltChannel(i);
  1011 		}
  1012 	} else if ( which < num_channels ) {
  1013 		SDL_LockAudio();
  1014 		if (mix_channel[which].playing) {
  1015 			_Mix_channel_done_playing(which);
  1016 			mix_channel[which].playing = 0;
  1017 			mix_channel[which].looping = 0;
  1018 		}
  1019 		mix_channel[which].expire = 0;
  1020 		if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
  1021 			mix_channel[which].volume = mix_channel[which].fade_volume_reset;
  1022 		mix_channel[which].fading = MIX_NO_FADING;
  1023 		SDL_UnlockAudio();
  1024 	}
  1025 	return(0);
  1026 }
  1027 
  1028 /* Halt playing of a particular group of channels */
  1029 int Mix_HaltGroup(int tag)
  1030 {
  1031 	int i;
  1032 
  1033 	for ( i=0; i<num_channels; ++i ) {
  1034 		if( mix_channel[i].tag == tag ) {
  1035 			Mix_HaltChannel(i);
  1036 		}
  1037 	}
  1038 	return(0);
  1039 }
  1040 
  1041 /* Fade out a channel and then stop it automatically */
  1042 int Mix_FadeOutChannel(int which, int ms)
  1043 {
  1044 	int status;
  1045 
  1046 	status = 0;
  1047 	if ( audio_opened ) {
  1048 		if ( which == -1 ) {
  1049 			int i;
  1050 
  1051 			for ( i=0; i<num_channels; ++i ) {
  1052 				status += Mix_FadeOutChannel(i, ms);
  1053 			}
  1054 		} else if ( which < num_channels ) {
  1055 			SDL_LockAudio();
  1056 			if ( mix_channel[which].playing && 
  1057 			    (mix_channel[which].volume > 0) &&
  1058 			    (mix_channel[which].fading != MIX_FADING_OUT) ) {
  1059 				mix_channel[which].fade_volume = mix_channel[which].volume;
  1060 				mix_channel[which].fade_length = (Uint32)ms;
  1061 				mix_channel[which].ticks_fade = SDL_GetTicks();
  1062 
  1063 				/* only change fade_volume_reset if we're not fading. */
  1064 				if (mix_channel[which].fading == MIX_NO_FADING) {
  1065 				    mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1066 				}
  1067 
  1068 				mix_channel[which].fading = MIX_FADING_OUT;
  1069 
  1070 				++status;
  1071 			}
  1072 			SDL_UnlockAudio();
  1073 		}
  1074 	}
  1075 	return(status);
  1076 }
  1077 
  1078 /* Halt playing of a particular group of channels */
  1079 int Mix_FadeOutGroup(int tag, int ms)
  1080 {
  1081 	int i;
  1082 	int status = 0;
  1083 	for ( i=0; i<num_channels; ++i ) {
  1084 		if( mix_channel[i].tag == tag ) {
  1085 			status += Mix_FadeOutChannel(i,ms);
  1086 		}
  1087 	}
  1088 	return(status);
  1089 }
  1090 
  1091 Mix_Fading Mix_FadingChannel(int which)
  1092 {
  1093 	if ( which < 0 || which >= num_channels ) {
  1094 		return MIX_NO_FADING;
  1095 	}
  1096 	return mix_channel[which].fading;
  1097 }
  1098 
  1099 /* Check the status of a specific channel.
  1100    If the specified mix_channel is -1, check all mix channels.
  1101 */
  1102 int Mix_Playing(int which)
  1103 {
  1104 	int status;
  1105 
  1106 	status = 0;
  1107 	if ( which == -1 ) {
  1108 		int i;
  1109 
  1110 		for ( i=0; i<num_channels; ++i ) {
  1111 			if ((mix_channel[i].playing > 0) ||
  1112 			     mix_channel[i].looping)
  1113 			{
  1114 				++status;
  1115 			}
  1116 		}
  1117 	} else if ( which < num_channels ) {
  1118 		if ( (mix_channel[which].playing > 0) ||
  1119 		      mix_channel[which].looping )
  1120 		{
  1121 			++status;
  1122 		}
  1123 	}
  1124 	return(status);
  1125 }
  1126 
  1127 /* rcg06072001 Get the chunk associated with a channel. */
  1128 Mix_Chunk *Mix_GetChunk(int channel)
  1129 {
  1130 	Mix_Chunk *retval = NULL;
  1131 
  1132 	if ((channel >= 0) && (channel < num_channels)) {
  1133 		retval = mix_channel[channel].chunk;
  1134 	}
  1135 
  1136 	return(retval);
  1137 }
  1138 
  1139 /* Close the mixer, halting all playing audio */
  1140 void Mix_CloseAudio(void)
  1141 {
  1142 	int i;
  1143 
  1144 	if ( audio_opened ) {
  1145 		if ( audio_opened == 1 ) {
  1146 			for (i = 0; i < num_channels; i++) {
  1147 				Mix_UnregisterAllEffects(i);
  1148 			}
  1149 			Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
  1150 			close_music();
  1151 			Mix_HaltChannel(-1);
  1152 			_Mix_DeinitEffects();
  1153 			SDL_CloseAudio();
  1154 			SDL_free(mix_channel);
  1155 			mix_channel = NULL;
  1156 
  1157 			/* rcg06042009 report available decoders at runtime. */
  1158 			SDL_free(chunk_decoders);
  1159 			chunk_decoders = NULL;
  1160 			num_decoders = 0;
  1161 		}
  1162 		--audio_opened;
  1163 	}
  1164 }
  1165 
  1166 /* Pause a particular channel (or all) */
  1167 void Mix_Pause(int which)
  1168 {
  1169 	Uint32 sdl_ticks = SDL_GetTicks();
  1170 	if ( which == -1 ) {
  1171 		int i;
  1172 
  1173 		for ( i=0; i<num_channels; ++i ) {
  1174 			if ( mix_channel[i].playing > 0 ) {
  1175 				mix_channel[i].paused = sdl_ticks;
  1176 			}
  1177 		}
  1178 	} else if ( which < num_channels ) {
  1179 		if ( mix_channel[which].playing > 0 ) {
  1180 			mix_channel[which].paused = sdl_ticks;
  1181 		}
  1182 	}
  1183 }
  1184 
  1185 /* Resume a paused channel */
  1186 void Mix_Resume(int which)
  1187 {
  1188 	Uint32 sdl_ticks = SDL_GetTicks();
  1189 
  1190 	SDL_LockAudio();
  1191 	if ( which == -1 ) {
  1192 		int i;
  1193 
  1194 		for ( i=0; i<num_channels; ++i ) {
  1195 			if ( mix_channel[i].playing > 0 ) {
  1196 				if(mix_channel[i].expire > 0)
  1197 					mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
  1198 				mix_channel[i].paused = 0;
  1199 			}
  1200 		}
  1201 	} else if ( which < num_channels ) {
  1202 		if ( mix_channel[which].playing > 0 ) {
  1203 			if(mix_channel[which].expire > 0)
  1204 				mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
  1205 			mix_channel[which].paused = 0;
  1206 		}
  1207 	}
  1208 	SDL_UnlockAudio();
  1209 }
  1210 
  1211 int Mix_Paused(int which)
  1212 {
  1213 	if ( which < 0 ) {
  1214 		int status = 0;
  1215 		int i;
  1216 		for( i=0; i < num_channels; ++i ) {
  1217 			if ( mix_channel[i].paused ) {
  1218 				++ status;
  1219 			}
  1220 		}
  1221 		return(status);
  1222 	} else if ( which < num_channels ) {
  1223 		return(mix_channel[which].paused != 0);
  1224 	} else {
  1225 		return(0);
  1226 	}
  1227 }
  1228 
  1229 /* Change the group of a channel */
  1230 int Mix_GroupChannel(int which, int tag)
  1231 {
  1232 	if ( which < 0 || which > num_channels )
  1233 		return(0);
  1234 
  1235 	SDL_LockAudio();
  1236 	mix_channel[which].tag = tag;
  1237 	SDL_UnlockAudio();
  1238 	return(1);
  1239 }
  1240 
  1241 /* Assign several consecutive channels to a group */
  1242 int Mix_GroupChannels(int from, int to, int tag)
  1243 {
  1244 	int status = 0;
  1245 	for( ; from <= to; ++ from ) {
  1246 		status += Mix_GroupChannel(from, tag);
  1247 	}
  1248 	return(status);
  1249 }
  1250 
  1251 /* Finds the first available channel in a group of channels */
  1252 int Mix_GroupAvailable(int tag)
  1253 {
  1254 	int i;
  1255 	for( i=0; i < num_channels; i ++ ) {
  1256 		if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
  1257 		                    (mix_channel[i].playing <= 0) )
  1258 			return i;
  1259 	}
  1260 	return(-1);
  1261 }
  1262 
  1263 int Mix_GroupCount(int tag)
  1264 {
  1265 	int count = 0;
  1266 	int i;
  1267 	for( i=0; i < num_channels; i ++ ) {
  1268 		if ( mix_channel[i].tag==tag || tag==-1 )
  1269 			++ count;
  1270 	}
  1271 	return(count);
  1272 }
  1273 
  1274 /* Finds the "oldest" sample playing in a group of channels */
  1275 int Mix_GroupOldest(int tag)
  1276 {
  1277 	int chan = -1;
  1278 	Uint32 mintime = SDL_GetTicks();
  1279 	int i;
  1280 	for( i=0; i < num_channels; i ++ ) {
  1281 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1282 			 && mix_channel[i].start_time <= mintime ) {
  1283 			mintime = mix_channel[i].start_time;
  1284 			chan = i;
  1285 		}
  1286 	}
  1287 	return(chan);
  1288 }
  1289 
  1290 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
  1291 int Mix_GroupNewer(int tag)
  1292 {
  1293 	int chan = -1;
  1294 	Uint32 maxtime = 0;
  1295 	int i;
  1296 	for( i=0; i < num_channels; i ++ ) {
  1297 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1298 			 && mix_channel[i].start_time >= maxtime ) {
  1299 			maxtime = mix_channel[i].start_time;
  1300 			chan = i;
  1301 		}
  1302 	}
  1303 	return(chan);
  1304 }
  1305 
  1306 
  1307 
  1308 /*
  1309  * rcg06122001 The special effects exportable API.
  1310  *  Please see effect_*.c for internally-implemented effects, such
  1311  *  as Mix_SetPanning().
  1312  */
  1313 
  1314 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1315 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
  1316 				Mix_EffectDone_t d, void *arg)
  1317 {
  1318 	effect_info *new_e;
  1319 
  1320 	if (!e) {
  1321 		Mix_SetError("Internal error");
  1322 		return(0);
  1323 	}
  1324 
  1325 	if (f == NULL) {
  1326 		Mix_SetError("NULL effect callback");
  1327 		return(0);
  1328 	}
  1329 
  1330 	new_e = SDL_malloc(sizeof (effect_info));
  1331 	if (new_e == NULL) {
  1332 		Mix_SetError("Out of memory");
  1333 		return(0);
  1334 	}
  1335 
  1336 	new_e->callback = f;
  1337 	new_e->done_callback = d;
  1338 	new_e->udata = arg;
  1339 	new_e->next = NULL;
  1340 
  1341 	/* add new effect to end of linked list... */
  1342 	if (*e == NULL) {
  1343 		*e = new_e;
  1344 	} else {
  1345 		effect_info *cur = *e;
  1346 		while (1) {
  1347 			if (cur->next == NULL) {
  1348 				cur->next = new_e;
  1349 				break;
  1350 			}
  1351 			cur = cur->next;
  1352 		}
  1353 	}
  1354 
  1355 	return(1);
  1356 }
  1357 
  1358 
  1359 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1360 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
  1361 {
  1362 	effect_info *cur;
  1363 	effect_info *prev = NULL;
  1364 	effect_info *next = NULL;
  1365 
  1366 	if (!e) {
  1367 		Mix_SetError("Internal error");
  1368 		return(0);
  1369 	}
  1370 
  1371 	for (cur = *e; cur != NULL; cur = cur->next) {
  1372 		if (cur->callback == f) {
  1373 			next = cur->next;
  1374 			if (cur->done_callback != NULL) {
  1375 				cur->done_callback(channel, cur->udata);
  1376 			}
  1377 			SDL_free(cur);
  1378 
  1379 			if (prev == NULL) {   /* removing first item of list? */
  1380 				*e = next;
  1381 			} else {
  1382 				prev->next = next;
  1383 			}
  1384 			return(1);
  1385 		}
  1386 		prev = cur;
  1387 	}
  1388 
  1389 	Mix_SetError("No such effect registered");
  1390 	return(0);
  1391 }
  1392 
  1393 
  1394 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1395 static int _Mix_remove_all_effects(int channel, effect_info **e)
  1396 {
  1397 	effect_info *cur;
  1398 	effect_info *next;
  1399 
  1400 	if (!e) {
  1401 		Mix_SetError("Internal error");
  1402 		return(0);
  1403 	}
  1404 
  1405 	for (cur = *e; cur != NULL; cur = next) {
  1406 		next = cur->next;
  1407 		if (cur->done_callback != NULL) {
  1408 			cur->done_callback(channel, cur->udata);
  1409 		}
  1410 		SDL_free(cur);
  1411 	}
  1412 	*e = NULL;
  1413 
  1414 	return(1);
  1415 }
  1416 
  1417 
  1418 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1419 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
  1420 			Mix_EffectDone_t d, void *arg)
  1421 {
  1422 	effect_info **e = NULL;
  1423 
  1424 	if (channel == MIX_CHANNEL_POST) {
  1425 		e = &posteffects;
  1426 	} else {
  1427 		if ((channel < 0) || (channel >= num_channels)) {
  1428 			Mix_SetError("Invalid channel number");
  1429 			return(0);
  1430 		}
  1431 		e = &mix_channel[channel].effects;
  1432 	}
  1433 
  1434 	return _Mix_register_effect(e, f, d, arg);
  1435 }
  1436 
  1437 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
  1438 			Mix_EffectDone_t d, void *arg)
  1439 {
  1440     int retval;
  1441 	SDL_LockAudio();
  1442 	retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
  1443 	SDL_UnlockAudio();
  1444     return retval;
  1445 }
  1446 
  1447 
  1448 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1449 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
  1450 {
  1451 	effect_info **e = NULL;
  1452 
  1453 	if (channel == MIX_CHANNEL_POST) {
  1454 		e = &posteffects;
  1455 	} else {
  1456 		if ((channel < 0) || (channel >= num_channels)) {
  1457 			Mix_SetError("Invalid channel number");
  1458 			return(0);
  1459 		}
  1460 		e = &mix_channel[channel].effects;
  1461 	}
  1462 
  1463 	return _Mix_remove_effect(channel, e, f);
  1464 }
  1465 
  1466 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
  1467 {
  1468 	int retval;
  1469 	SDL_LockAudio();
  1470 	retval = _Mix_UnregisterEffect_locked(channel, f);
  1471 	SDL_UnlockAudio();
  1472 	return(retval);
  1473 }
  1474 
  1475 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1476 int _Mix_UnregisterAllEffects_locked(int channel)
  1477 {
  1478 	effect_info **e = NULL;
  1479 
  1480 	if (channel == MIX_CHANNEL_POST) {
  1481 		e = &posteffects;
  1482 	} else {
  1483 		if ((channel < 0) || (channel >= num_channels)) {
  1484 			Mix_SetError("Invalid channel number");
  1485 			return(0);
  1486 		}
  1487 		e = &mix_channel[channel].effects;
  1488 	}
  1489 
  1490 	return _Mix_remove_all_effects(channel, e);
  1491 }
  1492 
  1493 int Mix_UnregisterAllEffects(int channel)
  1494 {
  1495 	int retval;
  1496 	SDL_LockAudio();
  1497 	retval = _Mix_UnregisterAllEffects_locked(channel);
  1498 	SDL_UnlockAudio();
  1499 	return(retval);
  1500 }
  1501 
  1502 /* end of mixer.c ... */