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