mixer.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 23:28:23 -0500
changeset 528 bc0dfe8ae026
parent 518 8bc9b5fd2aae
child 539 e7c80564dda5
permissions -rw-r--r--
Backed out changeset 1eddea51f162
     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 = 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 		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 = 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 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].fading = MIX_NO_FADING;
   310 				mix_channel[i].expire = 0;
   311 				_Mix_channel_done_playing(i);
   312 			} else if ( mix_channel[i].fading != MIX_NO_FADING ) {
   313 				Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
   314 				if( ticks > mix_channel[i].fade_length ) {
   315 				    Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
   316 					if( mix_channel[i].fading == MIX_FADING_OUT ) {
   317 						mix_channel[i].playing = 0;
   318 						mix_channel[i].expire = 0;
   319 						_Mix_channel_done_playing(i);
   320 					}
   321 					mix_channel[i].fading = MIX_NO_FADING;
   322 				} else {
   323 					if( mix_channel[i].fading == MIX_FADING_OUT ) {
   324 						Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
   325 								   / mix_channel[i].fade_length );
   326 					} else {
   327 						Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
   328 					}
   329 				}
   330 			}
   331 			if ( mix_channel[i].playing > 0 ) {
   332 				int index = 0;
   333 				int remaining = len;
   334 				while (mix_channel[i].playing > 0 && index < len) {
   335 					remaining = len - index;
   336 					volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
   337 					mixable = mix_channel[i].playing;
   338 					if ( mixable > remaining ) {
   339 						mixable = remaining;
   340 					}
   341 
   342 					mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
   343 					SDL_MixAudio(stream+index,mix_input,mixable,volume);
   344 					if (mix_input != mix_channel[i].samples)
   345 						free(mix_input);
   346 
   347 					mix_channel[i].samples += mixable;
   348 					mix_channel[i].playing -= mixable;
   349 					index += mixable;
   350 
   351 					/* rcg06072001 Alert app if channel is done playing. */
   352 					if (!mix_channel[i].playing && !mix_channel[i].looping) {
   353 						_Mix_channel_done_playing(i);
   354 					}
   355 				}
   356 
   357 				/* If looping the sample and we are at its end, make sure
   358 				   we will still return a full buffer */
   359 				while ( mix_channel[i].looping && index < len ) {
   360 					int alen = mix_channel[i].chunk->alen;
   361 					remaining = len - index;
   362 					if (remaining > alen) {
   363 						remaining = alen;
   364 					}
   365 
   366 					mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
   367 					SDL_MixAudio(stream+index, mix_input, remaining, volume);
   368 					if (mix_input != mix_channel[i].chunk->abuf)
   369 						free(mix_input);
   370 
   371 					--mix_channel[i].looping;
   372 					mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
   373 					mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
   374 					index += remaining;
   375 				}
   376 				if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
   377 					--mix_channel[i].looping;
   378 					mix_channel[i].samples = mix_channel[i].chunk->abuf;
   379 					mix_channel[i].playing = mix_channel[i].chunk->alen;
   380 				}
   381 			}
   382 		}
   383 	}
   384 
   385 	/* rcg06122001 run posteffects... */
   386 	Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
   387 
   388 	if ( mix_postmix ) {
   389 		mix_postmix(mix_postmix_data, stream, len);
   390 	}
   391 }
   392 
   393 #if 0
   394 static void PrintFormat(char *title, SDL_AudioSpec *fmt)
   395 {
   396 	printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
   397 			(fmt->format&0x8000) ? "signed" : "unsigned",
   398 			(fmt->channels > 2) ? "surround" :
   399 			(fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
   400 }
   401 #endif
   402 
   403 
   404 /* Open the mixer with a certain desired audio format */
   405 int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
   406 {
   407 	int i;
   408 	SDL_AudioSpec desired;
   409 
   410 	/* If the mixer is already opened, increment open count */
   411 	if ( audio_opened ) {
   412 		if ( format == mixer.format && nchannels == mixer.channels ) {
   413 			++audio_opened;
   414 			return(0);
   415 		}
   416 		while ( audio_opened ) {
   417 			Mix_CloseAudio();
   418 		}
   419 	}
   420 
   421 	/* Set the desired format and frequency */
   422 	desired.freq = frequency;
   423 	desired.format = format;
   424 	desired.channels = nchannels;
   425 	desired.samples = chunksize;
   426 	desired.callback = mix_channels;
   427 	desired.userdata = NULL;
   428 
   429 	/* Accept nearly any audio format */
   430 	if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
   431 		return(-1);
   432 	}
   433 #if 0
   434 	PrintFormat("Audio device", &mixer);
   435 #endif
   436 
   437 	/* Initialize the music players */
   438 	if ( open_music(&mixer) < 0 ) {
   439 		SDL_CloseAudio();
   440 		return(-1);
   441 	}
   442 
   443 	num_channels = MIX_CHANNELS;
   444 	mix_channel = (struct _Mix_Channel *) malloc(num_channels * sizeof(struct _Mix_Channel));
   445 
   446 	/* Clear out the audio channels */
   447 	for ( i=0; i<num_channels; ++i ) {
   448 		mix_channel[i].chunk = NULL;
   449 		mix_channel[i].playing = 0;
   450 		mix_channel[i].looping = 0;
   451 		mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   452 		mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   453 		mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   454 		mix_channel[i].fading = MIX_NO_FADING;
   455 		mix_channel[i].tag = -1;
   456 		mix_channel[i].expire = 0;
   457 		mix_channel[i].effects = NULL;
   458 		mix_channel[i].paused = 0;
   459 	}
   460 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   461 
   462 	_Mix_InitEffects();
   463 
   464 	/* This list is (currently) decided at build time. */
   465 	add_chunk_decoder("WAVE");
   466 	add_chunk_decoder("AIFF");
   467 	add_chunk_decoder("VOC");
   468 #ifdef OGG_MUSIC
   469 	add_chunk_decoder("OGG");
   470 #endif
   471 #ifdef FLAC_MUSIC
   472 	add_chunk_decoder("FLAC");
   473 #endif
   474 
   475 	audio_opened = 1;
   476 	SDL_PauseAudio(0);
   477 	return(0);
   478 }
   479 
   480 /* Dynamically change the number of channels managed by the mixer.
   481    If decreasing the number of channels, the upper channels are
   482    stopped.
   483  */
   484 int Mix_AllocateChannels(int numchans)
   485 {
   486 	if ( numchans<0 || numchans==num_channels )
   487 		return(num_channels);
   488 
   489 	if ( numchans < num_channels ) {
   490 		/* Stop the affected channels */
   491 		int i;
   492 		for(i=numchans; i < num_channels; i++) {
   493 			Mix_UnregisterAllEffects(i);
   494 			Mix_HaltChannel(i);
   495 		}
   496 	}
   497 	SDL_LockAudio();
   498 	mix_channel = (struct _Mix_Channel *) realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
   499 	if ( numchans > num_channels ) {
   500 		/* Initialize the new channels */
   501 		int i;
   502 		for(i=num_channels; i < numchans; i++) {
   503 			mix_channel[i].chunk = NULL;
   504 			mix_channel[i].playing = 0;
   505 			mix_channel[i].looping = 0;
   506 			mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   507 			mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   508 			mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   509 			mix_channel[i].fading = MIX_NO_FADING;
   510 			mix_channel[i].tag = -1;
   511 			mix_channel[i].expire = 0;
   512 			mix_channel[i].effects = NULL;
   513 			mix_channel[i].paused = 0;
   514 		}
   515 	}
   516 	num_channels = numchans;
   517 	SDL_UnlockAudio();
   518 	return(num_channels);
   519 }
   520 
   521 /* Return the actual mixer parameters */
   522 int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
   523 {
   524 	if ( audio_opened ) {
   525 		if ( frequency ) {
   526 			*frequency = mixer.freq;
   527 		}
   528 		if ( format ) {
   529 			*format = mixer.format;
   530 		}
   531 		if ( channels ) {
   532 			*channels = mixer.channels;
   533 		}
   534 	}
   535 	return(audio_opened);
   536 }
   537 
   538 
   539 /*
   540  * !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the
   541  *             generic setup, then call the correct file format loader.
   542  */
   543 
   544 /* Load a wave file */
   545 Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
   546 {
   547 	Uint32 magic;
   548 	Mix_Chunk *chunk;
   549 	SDL_AudioSpec wavespec, *loaded;
   550 	SDL_AudioCVT wavecvt;
   551 	int samplesize;
   552 
   553 	/* rcg06012001 Make sure src is valid */
   554 	if ( ! src ) {
   555 		SDL_SetError("Mix_LoadWAV_RW with NULL src");
   556 		return(NULL);
   557 	}
   558 
   559 	/* Make sure audio has been opened */
   560 	if ( ! audio_opened ) {
   561 		SDL_SetError("Audio device hasn't been opened");
   562 		if ( freesrc && src ) {
   563 			SDL_RWclose(src);
   564 		}
   565 		return(NULL);
   566 	}
   567 
   568 	/* Allocate the chunk memory */
   569 	chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
   570 	if ( chunk == NULL ) {
   571 		SDL_SetError("Out of memory");
   572 		if ( freesrc ) {
   573 			SDL_RWclose(src);
   574 		}
   575 		return(NULL);
   576 	}
   577 
   578 	/* Find out what kind of audio file this is */
   579 	magic = SDL_ReadLE32(src);
   580 	/* Seek backwards for compatibility with older loaders */
   581 	SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
   582 
   583 	switch (magic) {
   584 		case WAVE:
   585 		case RIFF:
   586 			loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
   587 					(Uint8 **)&chunk->abuf, &chunk->alen);
   588 			break;
   589 		case FORM:
   590 			loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
   591 					(Uint8 **)&chunk->abuf, &chunk->alen);
   592 			break;
   593 #ifdef OGG_MUSIC
   594 		case OGGS:
   595 			loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
   596 					(Uint8 **)&chunk->abuf, &chunk->alen);
   597 			break;
   598 #endif
   599 #ifdef FLAC_MUSIC
   600 		case FLAC:
   601 			loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
   602 					(Uint8 **)&chunk->abuf, &chunk->alen);
   603 			break;
   604 #endif
   605 		case CREA:
   606 			loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
   607 					(Uint8 **)&chunk->abuf, &chunk->alen);
   608 			break;
   609 		default:
   610 			SDL_SetError("Unrecognized sound file type");
   611 			return(0);			
   612 	}
   613 	if ( !loaded ) {
   614 		free(chunk);
   615 		return(NULL);
   616 	}
   617 
   618 #if 0
   619 	PrintFormat("Audio device", &mixer);
   620 	PrintFormat("-- Wave file", &wavespec);
   621 #endif
   622 
   623 	/* Build the audio converter and create conversion buffers */
   624 	if ( SDL_BuildAudioCVT(&wavecvt,
   625 			wavespec.format, wavespec.channels, wavespec.freq,
   626 			mixer.format, mixer.channels, mixer.freq) < 0 ) {
   627 		SDL_FreeWAV(chunk->abuf);
   628 		free(chunk);
   629 		return(NULL);
   630 	}
   631 	samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
   632 	wavecvt.len = chunk->alen & ~(samplesize-1);
   633 	wavecvt.buf = (Uint8 *)calloc(1, wavecvt.len*wavecvt.len_mult);
   634 	if ( wavecvt.buf == NULL ) {
   635 		SDL_SetError("Out of memory");
   636 		SDL_FreeWAV(chunk->abuf);
   637 		free(chunk);
   638 		return(NULL);
   639 	}
   640 	memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
   641 	SDL_FreeWAV(chunk->abuf);
   642 
   643 	/* Run the audio converter */
   644 	if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
   645 		free(wavecvt.buf);
   646 		free(chunk);
   647 		return(NULL);
   648 	}
   649 	chunk->allocated = 1;
   650 	chunk->abuf = wavecvt.buf;
   651 	chunk->alen = wavecvt.len_cvt;
   652 	chunk->volume = MIX_MAX_VOLUME;
   653 
   654 	return(chunk);
   655 }
   656 
   657 /* Load a wave file of the mixer format from a memory buffer */
   658 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
   659 {
   660 	Mix_Chunk *chunk;
   661 	Uint8 magic[4];
   662 
   663 	/* Make sure audio has been opened */
   664 	if ( ! audio_opened ) {
   665 		SDL_SetError("Audio device hasn't been opened");
   666 		return(NULL);
   667 	}
   668 
   669 	/* Allocate the chunk memory */
   670 	chunk = (Mix_Chunk *)calloc(1,sizeof(Mix_Chunk));
   671 	if ( chunk == NULL ) {
   672 		SDL_SetError("Out of memory");
   673 		return(NULL);
   674 	}
   675 
   676 	/* Essentially just skip to the audio data (no error checking - fast) */
   677 	chunk->allocated = 0;
   678 	mem += 12; /* WAV header */
   679 	do {
   680 		memcpy(magic, mem, 4);
   681 		mem += 4;
   682 		chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
   683 		mem += 4;
   684 		chunk->abuf = mem;
   685 		mem += chunk->alen;
   686 	} while ( memcmp(magic, "data", 4) != 0 );
   687 	chunk->volume = MIX_MAX_VOLUME;
   688 
   689 	return(chunk);
   690 }
   691 
   692 /* Load raw audio data of the mixer format from a memory buffer */
   693 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
   694 {
   695 	Mix_Chunk *chunk;
   696 
   697 	/* Make sure audio has been opened */
   698 	if ( ! audio_opened ) {
   699 		SDL_SetError("Audio device hasn't been opened");
   700 		return(NULL);
   701 	}
   702 
   703 	/* Allocate the chunk memory */
   704 	chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
   705 	if ( chunk == NULL ) {
   706 		SDL_SetError("Out of memory");
   707 		return(NULL);
   708 	}
   709 
   710 	/* Essentially just point at the audio data (no error checking - fast) */
   711 	chunk->allocated = 0;
   712 	chunk->alen = len;
   713 	chunk->abuf = mem;
   714 	chunk->volume = MIX_MAX_VOLUME;
   715 
   716 	return(chunk);
   717 }
   718 
   719 /* Free an audio chunk previously loaded */
   720 void Mix_FreeChunk(Mix_Chunk *chunk)
   721 {
   722 	int i;
   723 
   724 	/* Caution -- if the chunk is playing, the mixer will crash */
   725 	if ( chunk ) {
   726 		/* Guarantee that this chunk isn't playing */
   727 		SDL_LockAudio();
   728 		if ( mix_channel ) {
   729 			for ( i=0; i<num_channels; ++i ) {
   730 				if ( chunk == mix_channel[i].chunk ) {
   731 					mix_channel[i].playing = 0;
   732 				}
   733 			}
   734 		}
   735 		SDL_UnlockAudio();
   736 		/* Actually free the chunk */
   737 		if ( chunk->allocated ) {
   738 			free(chunk->abuf);
   739 		}
   740 		free(chunk);
   741 	}
   742 }
   743 
   744 /* Set a function that is called after all mixing is performed.
   745    This can be used to provide real-time visual display of the audio stream
   746    or add a custom mixer filter for the stream data.
   747 */
   748 void Mix_SetPostMix(void (*mix_func)
   749                     (void *udata, Uint8 *stream, int len), void *arg)
   750 {
   751 	SDL_LockAudio();
   752 	mix_postmix_data = arg;
   753 	mix_postmix = mix_func;
   754 	SDL_UnlockAudio();
   755 }
   756 
   757 /* Add your own music player or mixer function.
   758    If 'mix_func' is NULL, the default music player is re-enabled.
   759  */
   760 void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
   761                                                                 void *arg)
   762 {
   763 	SDL_LockAudio();
   764 	if ( mix_func != NULL ) {
   765 		music_data = arg;
   766 		mix_music = mix_func;
   767 	} else {
   768 		music_data = NULL;
   769 		mix_music = music_mixer;
   770 	}
   771 	SDL_UnlockAudio();
   772 }
   773 
   774 void *Mix_GetMusicHookData(void)
   775 {
   776 	return(music_data);
   777 }
   778 
   779 void Mix_ChannelFinished(void (*channel_finished)(int channel))
   780 {
   781 	SDL_LockAudio();
   782 	channel_done_callback = channel_finished;
   783 	SDL_UnlockAudio();
   784 }
   785 
   786 
   787 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
   788    them dynamically to the next sample if requested with a -1 value below.
   789    Returns the number of reserved channels.
   790  */
   791 int Mix_ReserveChannels(int num)
   792 {
   793 	if (num > num_channels)
   794 		num = num_channels;
   795 	reserved_channels = num;
   796 	return num;
   797 }
   798 
   799 static int checkchunkintegral(Mix_Chunk *chunk)
   800 {
   801 	int frame_width = 1;
   802 
   803 	if ((mixer.format & 0xFF) == 16) frame_width = 2;
   804 	frame_width *= mixer.channels;
   805 	while (chunk->alen % frame_width) chunk->alen--;
   806 	return chunk->alen;
   807 }
   808 
   809 /* Play an audio chunk on a specific channel.
   810    If the specified channel is -1, play on the first free channel.
   811    'ticks' is the number of milliseconds at most to play the sample, or -1
   812    if there is no limit.
   813    Returns which channel was used to play the sound.
   814 */
   815 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   816 {
   817 	int i;
   818 
   819 	/* Don't play null pointers :-) */
   820 	if ( chunk == NULL ) {
   821 		Mix_SetError("Tried to play a NULL chunk");
   822 		return(-1);
   823 	}
   824 	if ( !checkchunkintegral(chunk)) {
   825 		Mix_SetError("Tried to play a chunk with a bad frame");
   826 		return(-1);
   827 	}
   828 
   829 	/* Lock the mixer while modifying the playing channels */
   830 	SDL_LockAudio();
   831 	{
   832 		/* If which is -1, play on the first free channel */
   833 		if ( which == -1 ) {
   834 			for ( i=reserved_channels; i<num_channels; ++i ) {
   835 				if ( mix_channel[i].playing <= 0 )
   836 					break;
   837 			}
   838 			if ( i == num_channels ) {
   839 				Mix_SetError("No free channels available");
   840 				which = -1;
   841 			} else {
   842 				which = i;
   843 			}
   844 		}
   845 
   846 		/* Queue up the audio data for this channel */
   847 		if ( which >= 0 && which < num_channels ) {
   848 			Uint32 sdl_ticks = SDL_GetTicks();
   849 			if (Mix_Playing(which))
   850 				_Mix_channel_done_playing(which);
   851 			mix_channel[which].samples = chunk->abuf;
   852 			mix_channel[which].playing = chunk->alen;
   853 			mix_channel[which].looping = loops;
   854 			mix_channel[which].chunk = chunk;
   855 			mix_channel[which].paused = 0;
   856 			mix_channel[which].fading = MIX_NO_FADING;
   857 			mix_channel[which].start_time = sdl_ticks;
   858 			mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
   859 		}
   860 	}
   861 	SDL_UnlockAudio();
   862 
   863 	/* Return the channel on which the sound is being played */
   864 	return(which);
   865 }
   866 
   867 /* Change the expiration delay for a channel */
   868 int Mix_ExpireChannel(int which, int ticks)
   869 {
   870 	int status = 0;
   871 
   872 	if ( which == -1 ) {
   873 		int i;
   874 		for ( i=0; i < num_channels; ++ i ) {
   875 			status += Mix_ExpireChannel(i, ticks);
   876 		}
   877 	} else if ( which < num_channels ) {
   878 		SDL_LockAudio();
   879 		mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
   880 		SDL_UnlockAudio();
   881 		++ status;
   882 	}
   883 	return(status);
   884 }
   885 
   886 /* Fade in a sound on a channel, over ms milliseconds */
   887 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
   888 {
   889 	int i;
   890 
   891 	/* Don't play null pointers :-) */
   892 	if ( chunk == NULL ) {
   893 		return(-1);
   894 	}
   895 	if ( !checkchunkintegral(chunk)) {
   896 		Mix_SetError("Tried to play a chunk with a bad frame");
   897 		return(-1);
   898 	}
   899 
   900 	/* Lock the mixer while modifying the playing channels */
   901 	SDL_LockAudio();
   902 	{
   903 		/* If which is -1, play on the first free channel */
   904 		if ( which == -1 ) {
   905 			for ( i=reserved_channels; i<num_channels; ++i ) {
   906 				if ( mix_channel[i].playing <= 0 )
   907 					break;
   908 			}
   909 			if ( i == num_channels ) {
   910 				which = -1;
   911 			} else {
   912 				which = i;
   913 			}
   914 		}
   915 
   916 		/* Queue up the audio data for this channel */
   917 		if ( which >= 0 && which < num_channels ) {
   918 			Uint32 sdl_ticks = SDL_GetTicks();
   919 			if (Mix_Playing(which))
   920 				_Mix_channel_done_playing(which);
   921 			mix_channel[which].samples = chunk->abuf;
   922 			mix_channel[which].playing = chunk->alen;
   923 			mix_channel[which].looping = loops;
   924 			mix_channel[which].chunk = chunk;
   925 			mix_channel[which].paused = 0;
   926 			mix_channel[which].fading = MIX_FADING_IN;
   927 			mix_channel[which].fade_volume = mix_channel[which].volume;
   928 			mix_channel[which].fade_volume_reset = mix_channel[which].volume;
   929 			mix_channel[which].volume = 0;
   930 			mix_channel[which].fade_length = (Uint32)ms;
   931 			mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
   932 			mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
   933 		}
   934 	}
   935 	SDL_UnlockAudio();
   936 
   937 	/* Return the channel on which the sound is being played */
   938 	return(which);
   939 }
   940 
   941 /* Set volume of a particular channel */
   942 int Mix_Volume(int which, int volume)
   943 {
   944 	int i;
   945 	int prev_volume = 0;
   946 
   947 	if ( which == -1 ) {
   948 		for ( i=0; i<num_channels; ++i ) {
   949 			prev_volume += Mix_Volume(i, volume);
   950 		}
   951 		prev_volume /= num_channels;
   952 	} else if ( which < num_channels ) {
   953 		prev_volume = mix_channel[which].volume;
   954 		if ( volume >= 0 ) {
   955 			if ( volume > SDL_MIX_MAXVOLUME ) {
   956 				volume = SDL_MIX_MAXVOLUME;
   957 			}
   958 			mix_channel[which].volume = volume;
   959 		}
   960 	}
   961 	return(prev_volume);
   962 }
   963 /* Set volume of a particular chunk */
   964 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
   965 {
   966 	int prev_volume;
   967 
   968 	prev_volume = chunk->volume;
   969 	if ( volume >= 0 ) {
   970 		if ( volume > MIX_MAX_VOLUME ) {
   971 			volume = MIX_MAX_VOLUME;
   972 		}
   973 		chunk->volume = volume;
   974 	}
   975 	return(prev_volume);
   976 }
   977 
   978 /* Halt playing of a particular channel */
   979 int Mix_HaltChannel(int which)
   980 {
   981 	int i;
   982 
   983 	if ( which == -1 ) {
   984 		for ( i=0; i<num_channels; ++i ) {
   985 			Mix_HaltChannel(i);
   986 		}
   987 	} else if ( which < num_channels ) {
   988 		SDL_LockAudio();
   989 		if (mix_channel[which].playing) {
   990 			_Mix_channel_done_playing(which);
   991 		mix_channel[which].playing = 0;
   992 		}
   993 		mix_channel[which].expire = 0;
   994 		if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
   995 			mix_channel[which].volume = mix_channel[which].fade_volume_reset;
   996 		mix_channel[which].fading = MIX_NO_FADING;
   997 		SDL_UnlockAudio();
   998 	}
   999 	return(0);
  1000 }
  1001 
  1002 /* Halt playing of a particular group of channels */
  1003 int Mix_HaltGroup(int tag)
  1004 {
  1005 	int i;
  1006 
  1007 	for ( i=0; i<num_channels; ++i ) {
  1008 		if( mix_channel[i].tag == tag ) {
  1009 			Mix_HaltChannel(i);
  1010 		}
  1011 	}
  1012 	return(0);
  1013 }
  1014 
  1015 /* Fade out a channel and then stop it automatically */
  1016 int Mix_FadeOutChannel(int which, int ms)
  1017 {
  1018 	int status;
  1019 
  1020 	status = 0;
  1021 	if ( audio_opened ) {
  1022 		if ( which == -1 ) {
  1023 			int i;
  1024 
  1025 			for ( i=0; i<num_channels; ++i ) {
  1026 				status += Mix_FadeOutChannel(i, ms);
  1027 			}
  1028 		} else if ( which < num_channels ) {
  1029 			SDL_LockAudio();
  1030 			if ( mix_channel[which].playing && 
  1031 			    (mix_channel[which].volume > 0) &&
  1032 			    (mix_channel[which].fading != MIX_FADING_OUT) ) {
  1033 				mix_channel[which].fade_volume = mix_channel[which].volume;
  1034 				mix_channel[which].fading = MIX_FADING_OUT;
  1035 				mix_channel[which].fade_length = ms;
  1036 				mix_channel[which].ticks_fade = SDL_GetTicks();
  1037 
  1038 				/* only change fade_volume_reset if we're not fading. */
  1039 				if (mix_channel[which].fading == MIX_NO_FADING) {
  1040 				    mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1041 				}
  1042 				++status;
  1043 			}
  1044 			SDL_UnlockAudio();
  1045 		}
  1046 	}
  1047 	return(status);
  1048 }
  1049 
  1050 /* Halt playing of a particular group of channels */
  1051 int Mix_FadeOutGroup(int tag, int ms)
  1052 {
  1053 	int i;
  1054 	int status = 0;
  1055 	for ( i=0; i<num_channels; ++i ) {
  1056 		if( mix_channel[i].tag == tag ) {
  1057 			status += Mix_FadeOutChannel(i,ms);
  1058 		}
  1059 	}
  1060 	return(status);
  1061 }
  1062 
  1063 Mix_Fading Mix_FadingChannel(int which)
  1064 {
  1065 	if ( which < 0 || which >= num_channels ) {
  1066 		return MIX_NO_FADING;
  1067 	}
  1068 	return mix_channel[which].fading;
  1069 }
  1070 
  1071 /* Check the status of a specific channel.
  1072    If the specified mix_channel is -1, check all mix channels.
  1073 */
  1074 int Mix_Playing(int which)
  1075 {
  1076 	int status;
  1077 
  1078 	status = 0;
  1079 	if ( which == -1 ) {
  1080 		int i;
  1081 
  1082 		for ( i=0; i<num_channels; ++i ) {
  1083 			if ((mix_channel[i].playing > 0) ||
  1084 				(mix_channel[i].looping > 0))
  1085 			{
  1086 				++status;
  1087 			}
  1088 		}
  1089 	} else if ( which < num_channels ) {
  1090 		if ( (mix_channel[which].playing > 0) ||
  1091 		     (mix_channel[which].looping > 0) )
  1092 		{
  1093 			++status;
  1094 		}
  1095 	}
  1096 	return(status);
  1097 }
  1098 
  1099 /* rcg06072001 Get the chunk associated with a channel. */
  1100 Mix_Chunk *Mix_GetChunk(int channel)
  1101 {
  1102 	Mix_Chunk *retval = NULL;
  1103 
  1104 	if ((channel >= 0) && (channel < num_channels)) {
  1105 		retval = mix_channel[channel].chunk;
  1106 	}
  1107 
  1108 	return(retval);
  1109 }
  1110 
  1111 /* Close the mixer, halting all playing audio */
  1112 void Mix_CloseAudio(void)
  1113 {
  1114 	int i;
  1115 
  1116 	if ( audio_opened ) {
  1117 		if ( audio_opened == 1 ) {
  1118 			for (i = 0; i < num_channels; i++) {
  1119 				Mix_UnregisterAllEffects(i);
  1120 			}
  1121 			Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
  1122 			close_music();
  1123 			Mix_HaltChannel(-1);
  1124 			_Mix_DeinitEffects();
  1125 			SDL_CloseAudio();
  1126 			free(mix_channel);
  1127 			mix_channel = NULL;
  1128 
  1129 			/* rcg06042009 report available decoders at runtime. */
  1130 			free(chunk_decoders);
  1131 			chunk_decoders = NULL;
  1132 			num_decoders = 0;
  1133 		}
  1134 		--audio_opened;
  1135 	}
  1136 }
  1137 
  1138 /* Pause a particular channel (or all) */
  1139 void Mix_Pause(int which)
  1140 {
  1141 	Uint32 sdl_ticks = SDL_GetTicks();
  1142 	if ( which == -1 ) {
  1143 		int i;
  1144 
  1145 		for ( i=0; i<num_channels; ++i ) {
  1146 			if ( mix_channel[i].playing > 0 ) {
  1147 				mix_channel[i].paused = sdl_ticks;
  1148 			}
  1149 		}
  1150 	} else if ( which < num_channels ) {
  1151 		if ( mix_channel[which].playing > 0 ) {
  1152 			mix_channel[which].paused = sdl_ticks;
  1153 		}
  1154 	}
  1155 }
  1156 
  1157 /* Resume a paused channel */
  1158 void Mix_Resume(int which)
  1159 {
  1160 	Uint32 sdl_ticks = SDL_GetTicks();
  1161 
  1162 	SDL_LockAudio();
  1163 	if ( which == -1 ) {
  1164 		int i;
  1165 
  1166 		for ( i=0; i<num_channels; ++i ) {
  1167 			if ( mix_channel[i].playing > 0 ) {
  1168 				if(mix_channel[i].expire > 0)
  1169 					mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
  1170 				mix_channel[i].paused = 0;
  1171 			}
  1172 		}
  1173 	} else if ( which < num_channels ) {
  1174 		if ( mix_channel[which].playing > 0 ) {
  1175 			if(mix_channel[which].expire > 0)
  1176 				mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
  1177 			mix_channel[which].paused = 0;
  1178 		}
  1179 	}
  1180 	SDL_UnlockAudio();
  1181 }
  1182 
  1183 int Mix_Paused(int which)
  1184 {
  1185 	if ( which < 0 ) {
  1186 		int status = 0;
  1187 		int i;
  1188 		for( i=0; i < num_channels; ++i ) {
  1189 			if ( mix_channel[i].paused ) {
  1190 				++ status;
  1191 			}
  1192 		}
  1193 		return(status);
  1194 	} else if ( which < num_channels ) {
  1195 		return(mix_channel[which].paused != 0);
  1196 	} else {
  1197 		return(0);
  1198 	}
  1199 }
  1200 
  1201 /* Change the group of a channel */
  1202 int Mix_GroupChannel(int which, int tag)
  1203 {
  1204 	if ( which < 0 || which > num_channels )
  1205 		return(0);
  1206 
  1207 	SDL_LockAudio();
  1208 	mix_channel[which].tag = tag;
  1209 	SDL_UnlockAudio();
  1210 	return(1);
  1211 }
  1212 
  1213 /* Assign several consecutive channels to a group */
  1214 int Mix_GroupChannels(int from, int to, int tag)
  1215 {
  1216 	int status = 0;
  1217 	for( ; from <= to; ++ from ) {
  1218 		status += Mix_GroupChannel(from, tag);
  1219 	}
  1220 	return(status);
  1221 }
  1222 
  1223 /* Finds the first available channel in a group of channels */
  1224 int Mix_GroupAvailable(int tag)
  1225 {
  1226 	int i;
  1227 	for( i=0; i < num_channels; i ++ ) {
  1228 		if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
  1229 		                    (mix_channel[i].playing <= 0) )
  1230 			return i;
  1231 	}
  1232 	return(-1);
  1233 }
  1234 
  1235 int Mix_GroupCount(int tag)
  1236 {
  1237 	int count = 0;
  1238 	int i;
  1239 	for( i=0; i < num_channels; i ++ ) {
  1240 		if ( mix_channel[i].tag==tag || tag==-1 )
  1241 			++ count;
  1242 	}
  1243 	return(count);
  1244 }
  1245 
  1246 /* Finds the "oldest" sample playing in a group of channels */
  1247 int Mix_GroupOldest(int tag)
  1248 {
  1249 	int chan = -1;
  1250 	Uint32 mintime = SDL_GetTicks();
  1251 	int i;
  1252 	for( i=0; i < num_channels; i ++ ) {
  1253 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1254 			 && mix_channel[i].start_time <= mintime ) {
  1255 			mintime = mix_channel[i].start_time;
  1256 			chan = i;
  1257 		}
  1258 	}
  1259 	return(chan);
  1260 }
  1261 
  1262 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
  1263 int Mix_GroupNewer(int tag)
  1264 {
  1265 	int chan = -1;
  1266 	Uint32 maxtime = 0;
  1267 	int i;
  1268 	for( i=0; i < num_channels; i ++ ) {
  1269 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1270 			 && mix_channel[i].start_time >= maxtime ) {
  1271 			maxtime = mix_channel[i].start_time;
  1272 			chan = i;
  1273 		}
  1274 	}
  1275 	return(chan);
  1276 }
  1277 
  1278 
  1279 
  1280 /*
  1281  * rcg06122001 The special effects exportable API.
  1282  *  Please see effect_*.c for internally-implemented effects, such
  1283  *  as Mix_SetPanning().
  1284  */
  1285 
  1286 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1287 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
  1288 				Mix_EffectDone_t d, void *arg)
  1289 {
  1290 	effect_info *new_e;
  1291 
  1292 	if (!e) {
  1293 		Mix_SetError("Internal error");
  1294 		return(0);
  1295 	}
  1296 
  1297 	if (f == NULL) {
  1298 		Mix_SetError("NULL effect callback");
  1299 		return(0);
  1300 	}
  1301 
  1302 	new_e = malloc(sizeof (effect_info));
  1303 	if (new_e == NULL) {
  1304 		Mix_SetError("Out of memory");
  1305 		return(0);
  1306 	}
  1307 
  1308 	new_e->callback = f;
  1309 	new_e->done_callback = d;
  1310 	new_e->udata = arg;
  1311 	new_e->next = NULL;
  1312 
  1313 	/* add new effect to end of linked list... */
  1314 	if (*e == NULL) {
  1315 		*e = new_e;
  1316 	} else {
  1317 		effect_info *cur = *e;
  1318 		while (1) {
  1319 			if (cur->next == NULL) {
  1320 				cur->next = new_e;
  1321 				break;
  1322 			}
  1323 			cur = cur->next;
  1324 		}
  1325 	}
  1326 
  1327 	return(1);
  1328 }
  1329 
  1330 
  1331 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1332 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
  1333 {
  1334 	effect_info *cur;
  1335 	effect_info *prev = NULL;
  1336 	effect_info *next = NULL;
  1337 
  1338 	if (!e) {
  1339 		Mix_SetError("Internal error");
  1340 		return(0);
  1341 	}
  1342 
  1343 	for (cur = *e; cur != NULL; cur = cur->next) {
  1344 		if (cur->callback == f) {
  1345 			next = cur->next;
  1346 			if (cur->done_callback != NULL) {
  1347 				cur->done_callback(channel, cur->udata);
  1348 			}
  1349 			free(cur);
  1350 
  1351 			if (prev == NULL) {   /* removing first item of list? */
  1352 				*e = next;
  1353 			} else {
  1354 				prev->next = next;
  1355 			}
  1356 			return(1);
  1357 		}
  1358 		prev = cur;
  1359 	}
  1360 
  1361 	Mix_SetError("No such effect registered");
  1362 	return(0);
  1363 }
  1364 
  1365 
  1366 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1367 static int _Mix_remove_all_effects(int channel, effect_info **e)
  1368 {
  1369 	effect_info *cur;
  1370 	effect_info *next;
  1371 
  1372 	if (!e) {
  1373 		Mix_SetError("Internal error");
  1374 		return(0);
  1375 	}
  1376 
  1377 	for (cur = *e; cur != NULL; cur = next) {
  1378 		next = cur->next;
  1379 		if (cur->done_callback != NULL) {
  1380 			cur->done_callback(channel, cur->udata);
  1381 		}
  1382 		free(cur);
  1383 	}
  1384 	*e = NULL;
  1385 
  1386 	return(1);
  1387 }
  1388 
  1389 
  1390 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1391 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
  1392 			Mix_EffectDone_t d, void *arg)
  1393 {
  1394 	effect_info **e = NULL;
  1395 
  1396 	if (channel == MIX_CHANNEL_POST) {
  1397 		e = &posteffects;
  1398 	} else {
  1399 		if ((channel < 0) || (channel >= num_channels)) {
  1400 			Mix_SetError("Invalid channel number");
  1401 			return(0);
  1402 		}
  1403 		e = &mix_channel[channel].effects;
  1404 	}
  1405 
  1406 	return _Mix_register_effect(e, f, d, arg);
  1407 }
  1408 
  1409 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
  1410 			Mix_EffectDone_t d, void *arg)
  1411 {
  1412     int retval;
  1413 	SDL_LockAudio();
  1414 	retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
  1415 	SDL_UnlockAudio();
  1416     return retval;
  1417 }
  1418 
  1419 
  1420 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1421 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
  1422 {
  1423 	effect_info **e = NULL;
  1424 
  1425 	if (channel == MIX_CHANNEL_POST) {
  1426 		e = &posteffects;
  1427 	} else {
  1428 		if ((channel < 0) || (channel >= num_channels)) {
  1429 			Mix_SetError("Invalid channel number");
  1430 			return(0);
  1431 		}
  1432 		e = &mix_channel[channel].effects;
  1433 	}
  1434 
  1435 	return _Mix_remove_effect(channel, e, f);
  1436 }
  1437 
  1438 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
  1439 {
  1440 	int retval;
  1441 	SDL_LockAudio();
  1442 	retval = _Mix_UnregisterEffect_locked(channel, f);
  1443 	SDL_UnlockAudio();
  1444 	return(retval);
  1445 }
  1446 
  1447 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1448 int _Mix_UnregisterAllEffects_locked(int channel)
  1449 {
  1450 	effect_info **e = NULL;
  1451 
  1452 	if (channel == MIX_CHANNEL_POST) {
  1453 		e = &posteffects;
  1454 	} else {
  1455 		if ((channel < 0) || (channel >= num_channels)) {
  1456 			Mix_SetError("Invalid channel number");
  1457 			return(0);
  1458 		}
  1459 		e = &mix_channel[channel].effects;
  1460 	}
  1461 
  1462 	return _Mix_remove_all_effects(channel, e);
  1463 }
  1464 
  1465 int Mix_UnregisterAllEffects(int channel)
  1466 {
  1467 	int retval;
  1468 	SDL_LockAudio();
  1469 	retval = _Mix_UnregisterAllEffects_locked(channel);
  1470 	SDL_UnlockAudio();
  1471 	return(retval);
  1472 }
  1473 
  1474 /* end of mixer.c ... */
  1475