mixer.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 09 Jan 2012 07:34:10 -0500
changeset 558 7915d5cc775a
parent 539 e7c80564dda5
child 560 0fc8dffb86c5
permissions -rw-r--r--
Fixed version of smpeg.dll that doesn't dynamically link to libstdc++-6.dll
     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].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 						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 						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 *) 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 *) 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 *)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 			return(0);			
   614 	}
   615 	if ( !loaded ) {
   616 		free(chunk);
   617 		return(NULL);
   618 	}
   619 
   620 #if 0
   621 	PrintFormat("Audio device", &mixer);
   622 	PrintFormat("-- Wave file", &wavespec);
   623 #endif
   624 
   625 	/* Build the audio converter and create conversion buffers */
   626 	if ( SDL_BuildAudioCVT(&wavecvt,
   627 			wavespec.format, wavespec.channels, wavespec.freq,
   628 			mixer.format, mixer.channels, mixer.freq) < 0 ) {
   629 		SDL_FreeWAV(chunk->abuf);
   630 		free(chunk);
   631 		return(NULL);
   632 	}
   633 	samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
   634 	wavecvt.len = chunk->alen & ~(samplesize-1);
   635 	wavecvt.buf = (Uint8 *)calloc(1, wavecvt.len*wavecvt.len_mult);
   636 	if ( wavecvt.buf == NULL ) {
   637 		SDL_SetError("Out of memory");
   638 		SDL_FreeWAV(chunk->abuf);
   639 		free(chunk);
   640 		return(NULL);
   641 	}
   642 	memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
   643 	SDL_FreeWAV(chunk->abuf);
   644 
   645 	/* Run the audio converter */
   646 	if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
   647 		free(wavecvt.buf);
   648 		free(chunk);
   649 		return(NULL);
   650 	}
   651 	chunk->allocated = 1;
   652 	chunk->abuf = wavecvt.buf;
   653 	chunk->alen = wavecvt.len_cvt;
   654 	chunk->volume = MIX_MAX_VOLUME;
   655 
   656 	return(chunk);
   657 }
   658 
   659 /* Load a wave file of the mixer format from a memory buffer */
   660 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
   661 {
   662 	Mix_Chunk *chunk;
   663 	Uint8 magic[4];
   664 
   665 	/* Make sure audio has been opened */
   666 	if ( ! audio_opened ) {
   667 		SDL_SetError("Audio device hasn't been opened");
   668 		return(NULL);
   669 	}
   670 
   671 	/* Allocate the chunk memory */
   672 	chunk = (Mix_Chunk *)calloc(1,sizeof(Mix_Chunk));
   673 	if ( chunk == NULL ) {
   674 		SDL_SetError("Out of memory");
   675 		return(NULL);
   676 	}
   677 
   678 	/* Essentially just skip to the audio data (no error checking - fast) */
   679 	chunk->allocated = 0;
   680 	mem += 12; /* WAV header */
   681 	do {
   682 		memcpy(magic, mem, 4);
   683 		mem += 4;
   684 		chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
   685 		mem += 4;
   686 		chunk->abuf = mem;
   687 		mem += chunk->alen;
   688 	} while ( memcmp(magic, "data", 4) != 0 );
   689 	chunk->volume = MIX_MAX_VOLUME;
   690 
   691 	return(chunk);
   692 }
   693 
   694 /* Load raw audio data of the mixer format from a memory buffer */
   695 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
   696 {
   697 	Mix_Chunk *chunk;
   698 
   699 	/* Make sure audio has been opened */
   700 	if ( ! audio_opened ) {
   701 		SDL_SetError("Audio device hasn't been opened");
   702 		return(NULL);
   703 	}
   704 
   705 	/* Allocate the chunk memory */
   706 	chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
   707 	if ( chunk == NULL ) {
   708 		SDL_SetError("Out of memory");
   709 		return(NULL);
   710 	}
   711 
   712 	/* Essentially just point at the audio data (no error checking - fast) */
   713 	chunk->allocated = 0;
   714 	chunk->alen = len;
   715 	chunk->abuf = mem;
   716 	chunk->volume = MIX_MAX_VOLUME;
   717 
   718 	return(chunk);
   719 }
   720 
   721 /* Free an audio chunk previously loaded */
   722 void Mix_FreeChunk(Mix_Chunk *chunk)
   723 {
   724 	int i;
   725 
   726 	/* Caution -- if the chunk is playing, the mixer will crash */
   727 	if ( chunk ) {
   728 		/* Guarantee that this chunk isn't playing */
   729 		SDL_LockAudio();
   730 		if ( mix_channel ) {
   731 			for ( i=0; i<num_channels; ++i ) {
   732 				if ( chunk == mix_channel[i].chunk ) {
   733 					mix_channel[i].playing = 0;
   734 					mix_channel[i].looping = 0;
   735 				}
   736 			}
   737 		}
   738 		SDL_UnlockAudio();
   739 		/* Actually free the chunk */
   740 		if ( chunk->allocated ) {
   741 			free(chunk->abuf);
   742 		}
   743 		free(chunk);
   744 	}
   745 }
   746 
   747 /* Set a function that is called after all mixing is performed.
   748    This can be used to provide real-time visual display of the audio stream
   749    or add a custom mixer filter for the stream data.
   750 */
   751 void Mix_SetPostMix(void (*mix_func)
   752                     (void *udata, Uint8 *stream, int len), void *arg)
   753 {
   754 	SDL_LockAudio();
   755 	mix_postmix_data = arg;
   756 	mix_postmix = mix_func;
   757 	SDL_UnlockAudio();
   758 }
   759 
   760 /* Add your own music player or mixer function.
   761    If 'mix_func' is NULL, the default music player is re-enabled.
   762  */
   763 void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
   764                                                                 void *arg)
   765 {
   766 	SDL_LockAudio();
   767 	if ( mix_func != NULL ) {
   768 		music_data = arg;
   769 		mix_music = mix_func;
   770 	} else {
   771 		music_data = NULL;
   772 		mix_music = music_mixer;
   773 	}
   774 	SDL_UnlockAudio();
   775 }
   776 
   777 void *Mix_GetMusicHookData(void)
   778 {
   779 	return(music_data);
   780 }
   781 
   782 void Mix_ChannelFinished(void (*channel_finished)(int channel))
   783 {
   784 	SDL_LockAudio();
   785 	channel_done_callback = channel_finished;
   786 	SDL_UnlockAudio();
   787 }
   788 
   789 
   790 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
   791    them dynamically to the next sample if requested with a -1 value below.
   792    Returns the number of reserved channels.
   793  */
   794 int Mix_ReserveChannels(int num)
   795 {
   796 	if (num > num_channels)
   797 		num = num_channels;
   798 	reserved_channels = num;
   799 	return num;
   800 }
   801 
   802 static int checkchunkintegral(Mix_Chunk *chunk)
   803 {
   804 	int frame_width = 1;
   805 
   806 	if ((mixer.format & 0xFF) == 16) frame_width = 2;
   807 	frame_width *= mixer.channels;
   808 	while (chunk->alen % frame_width) chunk->alen--;
   809 	return chunk->alen;
   810 }
   811 
   812 /* Play an audio chunk on a specific channel.
   813    If the specified channel is -1, play on the first free channel.
   814    'ticks' is the number of milliseconds at most to play the sample, or -1
   815    if there is no limit.
   816    Returns which channel was used to play the sound.
   817 */
   818 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   819 {
   820 	int i;
   821 
   822 	/* Don't play null pointers :-) */
   823 	if ( chunk == NULL ) {
   824 		Mix_SetError("Tried to play a NULL chunk");
   825 		return(-1);
   826 	}
   827 	if ( !checkchunkintegral(chunk)) {
   828 		Mix_SetError("Tried to play a chunk with a bad frame");
   829 		return(-1);
   830 	}
   831 
   832 	/* Lock the mixer while modifying the playing channels */
   833 	SDL_LockAudio();
   834 	{
   835 		/* If which is -1, play on the first free channel */
   836 		if ( which == -1 ) {
   837 			for ( i=reserved_channels; i<num_channels; ++i ) {
   838 				if ( mix_channel[i].playing <= 0 )
   839 					break;
   840 			}
   841 			if ( i == num_channels ) {
   842 				Mix_SetError("No free channels available");
   843 				which = -1;
   844 			} else {
   845 				which = i;
   846 			}
   847 		}
   848 
   849 		/* Queue up the audio data for this channel */
   850 		if ( which >= 0 && which < num_channels ) {
   851 			Uint32 sdl_ticks = SDL_GetTicks();
   852 			if (Mix_Playing(which))
   853 				_Mix_channel_done_playing(which);
   854 			mix_channel[which].samples = chunk->abuf;
   855 			mix_channel[which].playing = chunk->alen;
   856 			mix_channel[which].looping = loops;
   857 			mix_channel[which].chunk = chunk;
   858 			mix_channel[which].paused = 0;
   859 			mix_channel[which].fading = MIX_NO_FADING;
   860 			mix_channel[which].start_time = sdl_ticks;
   861 			mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
   862 		}
   863 	}
   864 	SDL_UnlockAudio();
   865 
   866 	/* Return the channel on which the sound is being played */
   867 	return(which);
   868 }
   869 
   870 /* Change the expiration delay for a channel */
   871 int Mix_ExpireChannel(int which, int ticks)
   872 {
   873 	int status = 0;
   874 
   875 	if ( which == -1 ) {
   876 		int i;
   877 		for ( i=0; i < num_channels; ++ i ) {
   878 			status += Mix_ExpireChannel(i, ticks);
   879 		}
   880 	} else if ( which < num_channels ) {
   881 		SDL_LockAudio();
   882 		mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
   883 		SDL_UnlockAudio();
   884 		++ status;
   885 	}
   886 	return(status);
   887 }
   888 
   889 /* Fade in a sound on a channel, over ms milliseconds */
   890 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
   891 {
   892 	int i;
   893 
   894 	/* Don't play null pointers :-) */
   895 	if ( chunk == NULL ) {
   896 		return(-1);
   897 	}
   898 	if ( !checkchunkintegral(chunk)) {
   899 		Mix_SetError("Tried to play a chunk with a bad frame");
   900 		return(-1);
   901 	}
   902 
   903 	/* Lock the mixer while modifying the playing channels */
   904 	SDL_LockAudio();
   905 	{
   906 		/* If which is -1, play on the first free channel */
   907 		if ( which == -1 ) {
   908 			for ( i=reserved_channels; i<num_channels; ++i ) {
   909 				if ( mix_channel[i].playing <= 0 )
   910 					break;
   911 			}
   912 			if ( i == num_channels ) {
   913 				which = -1;
   914 			} else {
   915 				which = i;
   916 			}
   917 		}
   918 
   919 		/* Queue up the audio data for this channel */
   920 		if ( which >= 0 && which < num_channels ) {
   921 			Uint32 sdl_ticks = SDL_GetTicks();
   922 			if (Mix_Playing(which))
   923 				_Mix_channel_done_playing(which);
   924 			mix_channel[which].samples = chunk->abuf;
   925 			mix_channel[which].playing = chunk->alen;
   926 			mix_channel[which].looping = loops;
   927 			mix_channel[which].chunk = chunk;
   928 			mix_channel[which].paused = 0;
   929 			mix_channel[which].fading = MIX_FADING_IN;
   930 			mix_channel[which].fade_volume = mix_channel[which].volume;
   931 			mix_channel[which].fade_volume_reset = mix_channel[which].volume;
   932 			mix_channel[which].volume = 0;
   933 			mix_channel[which].fade_length = (Uint32)ms;
   934 			mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
   935 			mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
   936 		}
   937 	}
   938 	SDL_UnlockAudio();
   939 
   940 	/* Return the channel on which the sound is being played */
   941 	return(which);
   942 }
   943 
   944 /* Set volume of a particular channel */
   945 int Mix_Volume(int which, int volume)
   946 {
   947 	int i;
   948 	int prev_volume = 0;
   949 
   950 	if ( which == -1 ) {
   951 		for ( i=0; i<num_channels; ++i ) {
   952 			prev_volume += Mix_Volume(i, volume);
   953 		}
   954 		prev_volume /= num_channels;
   955 	} else if ( which < num_channels ) {
   956 		prev_volume = mix_channel[which].volume;
   957 		if ( volume >= 0 ) {
   958 			if ( volume > SDL_MIX_MAXVOLUME ) {
   959 				volume = SDL_MIX_MAXVOLUME;
   960 			}
   961 			mix_channel[which].volume = volume;
   962 		}
   963 	}
   964 	return(prev_volume);
   965 }
   966 /* Set volume of a particular chunk */
   967 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
   968 {
   969 	int prev_volume;
   970 
   971 	prev_volume = chunk->volume;
   972 	if ( volume >= 0 ) {
   973 		if ( volume > MIX_MAX_VOLUME ) {
   974 			volume = MIX_MAX_VOLUME;
   975 		}
   976 		chunk->volume = volume;
   977 	}
   978 	return(prev_volume);
   979 }
   980 
   981 /* Halt playing of a particular channel */
   982 int Mix_HaltChannel(int which)
   983 {
   984 	int i;
   985 
   986 	if ( which == -1 ) {
   987 		for ( i=0; i<num_channels; ++i ) {
   988 			Mix_HaltChannel(i);
   989 		}
   990 	} else if ( which < num_channels ) {
   991 		SDL_LockAudio();
   992 		if (mix_channel[which].playing) {
   993 			_Mix_channel_done_playing(which);
   994 			mix_channel[which].playing = 0;
   995 			mix_channel[which].looping = 0;
   996 		}
   997 		mix_channel[which].expire = 0;
   998 		if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
   999 			mix_channel[which].volume = mix_channel[which].fade_volume_reset;
  1000 		mix_channel[which].fading = MIX_NO_FADING;
  1001 		SDL_UnlockAudio();
  1002 	}
  1003 	return(0);
  1004 }
  1005 
  1006 /* Halt playing of a particular group of channels */
  1007 int Mix_HaltGroup(int tag)
  1008 {
  1009 	int i;
  1010 
  1011 	for ( i=0; i<num_channels; ++i ) {
  1012 		if( mix_channel[i].tag == tag ) {
  1013 			Mix_HaltChannel(i);
  1014 		}
  1015 	}
  1016 	return(0);
  1017 }
  1018 
  1019 /* Fade out a channel and then stop it automatically */
  1020 int Mix_FadeOutChannel(int which, int ms)
  1021 {
  1022 	int status;
  1023 
  1024 	status = 0;
  1025 	if ( audio_opened ) {
  1026 		if ( which == -1 ) {
  1027 			int i;
  1028 
  1029 			for ( i=0; i<num_channels; ++i ) {
  1030 				status += Mix_FadeOutChannel(i, ms);
  1031 			}
  1032 		} else if ( which < num_channels ) {
  1033 			SDL_LockAudio();
  1034 			if ( mix_channel[which].playing && 
  1035 			    (mix_channel[which].volume > 0) &&
  1036 			    (mix_channel[which].fading != MIX_FADING_OUT) ) {
  1037 				mix_channel[which].fade_volume = mix_channel[which].volume;
  1038 				mix_channel[which].fading = MIX_FADING_OUT;
  1039 				mix_channel[which].fade_length = ms;
  1040 				mix_channel[which].ticks_fade = SDL_GetTicks();
  1041 
  1042 				/* only change fade_volume_reset if we're not fading. */
  1043 				if (mix_channel[which].fading == MIX_NO_FADING) {
  1044 				    mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1045 				}
  1046 				++status;
  1047 			}
  1048 			SDL_UnlockAudio();
  1049 		}
  1050 	}
  1051 	return(status);
  1052 }
  1053 
  1054 /* Halt playing of a particular group of channels */
  1055 int Mix_FadeOutGroup(int tag, int ms)
  1056 {
  1057 	int i;
  1058 	int status = 0;
  1059 	for ( i=0; i<num_channels; ++i ) {
  1060 		if( mix_channel[i].tag == tag ) {
  1061 			status += Mix_FadeOutChannel(i,ms);
  1062 		}
  1063 	}
  1064 	return(status);
  1065 }
  1066 
  1067 Mix_Fading Mix_FadingChannel(int which)
  1068 {
  1069 	if ( which < 0 || which >= num_channels ) {
  1070 		return MIX_NO_FADING;
  1071 	}
  1072 	return mix_channel[which].fading;
  1073 }
  1074 
  1075 /* Check the status of a specific channel.
  1076    If the specified mix_channel is -1, check all mix channels.
  1077 */
  1078 int Mix_Playing(int which)
  1079 {
  1080 	int status;
  1081 
  1082 	status = 0;
  1083 	if ( which == -1 ) {
  1084 		int i;
  1085 
  1086 		for ( i=0; i<num_channels; ++i ) {
  1087 			if ((mix_channel[i].playing > 0) ||
  1088 				(mix_channel[i].looping > 0))
  1089 			{
  1090 				++status;
  1091 			}
  1092 		}
  1093 	} else if ( which < num_channels ) {
  1094 		if ( (mix_channel[which].playing > 0) ||
  1095 		     (mix_channel[which].looping > 0) )
  1096 		{
  1097 			++status;
  1098 		}
  1099 	}
  1100 	return(status);
  1101 }
  1102 
  1103 /* rcg06072001 Get the chunk associated with a channel. */
  1104 Mix_Chunk *Mix_GetChunk(int channel)
  1105 {
  1106 	Mix_Chunk *retval = NULL;
  1107 
  1108 	if ((channel >= 0) && (channel < num_channels)) {
  1109 		retval = mix_channel[channel].chunk;
  1110 	}
  1111 
  1112 	return(retval);
  1113 }
  1114 
  1115 /* Close the mixer, halting all playing audio */
  1116 void Mix_CloseAudio(void)
  1117 {
  1118 	int i;
  1119 
  1120 	if ( audio_opened ) {
  1121 		if ( audio_opened == 1 ) {
  1122 			for (i = 0; i < num_channels; i++) {
  1123 				Mix_UnregisterAllEffects(i);
  1124 			}
  1125 			Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
  1126 			close_music();
  1127 			Mix_HaltChannel(-1);
  1128 			_Mix_DeinitEffects();
  1129 			SDL_CloseAudio();
  1130 			free(mix_channel);
  1131 			mix_channel = NULL;
  1132 
  1133 			/* rcg06042009 report available decoders at runtime. */
  1134 			free(chunk_decoders);
  1135 			chunk_decoders = NULL;
  1136 			num_decoders = 0;
  1137 		}
  1138 		--audio_opened;
  1139 	}
  1140 }
  1141 
  1142 /* Pause a particular channel (or all) */
  1143 void Mix_Pause(int which)
  1144 {
  1145 	Uint32 sdl_ticks = SDL_GetTicks();
  1146 	if ( which == -1 ) {
  1147 		int i;
  1148 
  1149 		for ( i=0; i<num_channels; ++i ) {
  1150 			if ( mix_channel[i].playing > 0 ) {
  1151 				mix_channel[i].paused = sdl_ticks;
  1152 			}
  1153 		}
  1154 	} else if ( which < num_channels ) {
  1155 		if ( mix_channel[which].playing > 0 ) {
  1156 			mix_channel[which].paused = sdl_ticks;
  1157 		}
  1158 	}
  1159 }
  1160 
  1161 /* Resume a paused channel */
  1162 void Mix_Resume(int which)
  1163 {
  1164 	Uint32 sdl_ticks = SDL_GetTicks();
  1165 
  1166 	SDL_LockAudio();
  1167 	if ( which == -1 ) {
  1168 		int i;
  1169 
  1170 		for ( i=0; i<num_channels; ++i ) {
  1171 			if ( mix_channel[i].playing > 0 ) {
  1172 				if(mix_channel[i].expire > 0)
  1173 					mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
  1174 				mix_channel[i].paused = 0;
  1175 			}
  1176 		}
  1177 	} else if ( which < num_channels ) {
  1178 		if ( mix_channel[which].playing > 0 ) {
  1179 			if(mix_channel[which].expire > 0)
  1180 				mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
  1181 			mix_channel[which].paused = 0;
  1182 		}
  1183 	}
  1184 	SDL_UnlockAudio();
  1185 }
  1186 
  1187 int Mix_Paused(int which)
  1188 {
  1189 	if ( which < 0 ) {
  1190 		int status = 0;
  1191 		int i;
  1192 		for( i=0; i < num_channels; ++i ) {
  1193 			if ( mix_channel[i].paused ) {
  1194 				++ status;
  1195 			}
  1196 		}
  1197 		return(status);
  1198 	} else if ( which < num_channels ) {
  1199 		return(mix_channel[which].paused != 0);
  1200 	} else {
  1201 		return(0);
  1202 	}
  1203 }
  1204 
  1205 /* Change the group of a channel */
  1206 int Mix_GroupChannel(int which, int tag)
  1207 {
  1208 	if ( which < 0 || which > num_channels )
  1209 		return(0);
  1210 
  1211 	SDL_LockAudio();
  1212 	mix_channel[which].tag = tag;
  1213 	SDL_UnlockAudio();
  1214 	return(1);
  1215 }
  1216 
  1217 /* Assign several consecutive channels to a group */
  1218 int Mix_GroupChannels(int from, int to, int tag)
  1219 {
  1220 	int status = 0;
  1221 	for( ; from <= to; ++ from ) {
  1222 		status += Mix_GroupChannel(from, tag);
  1223 	}
  1224 	return(status);
  1225 }
  1226 
  1227 /* Finds the first available channel in a group of channels */
  1228 int Mix_GroupAvailable(int tag)
  1229 {
  1230 	int i;
  1231 	for( i=0; i < num_channels; i ++ ) {
  1232 		if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
  1233 		                    (mix_channel[i].playing <= 0) )
  1234 			return i;
  1235 	}
  1236 	return(-1);
  1237 }
  1238 
  1239 int Mix_GroupCount(int tag)
  1240 {
  1241 	int count = 0;
  1242 	int i;
  1243 	for( i=0; i < num_channels; i ++ ) {
  1244 		if ( mix_channel[i].tag==tag || tag==-1 )
  1245 			++ count;
  1246 	}
  1247 	return(count);
  1248 }
  1249 
  1250 /* Finds the "oldest" sample playing in a group of channels */
  1251 int Mix_GroupOldest(int tag)
  1252 {
  1253 	int chan = -1;
  1254 	Uint32 mintime = SDL_GetTicks();
  1255 	int i;
  1256 	for( i=0; i < num_channels; i ++ ) {
  1257 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1258 			 && mix_channel[i].start_time <= mintime ) {
  1259 			mintime = mix_channel[i].start_time;
  1260 			chan = i;
  1261 		}
  1262 	}
  1263 	return(chan);
  1264 }
  1265 
  1266 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
  1267 int Mix_GroupNewer(int tag)
  1268 {
  1269 	int chan = -1;
  1270 	Uint32 maxtime = 0;
  1271 	int i;
  1272 	for( i=0; i < num_channels; i ++ ) {
  1273 		if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1274 			 && mix_channel[i].start_time >= maxtime ) {
  1275 			maxtime = mix_channel[i].start_time;
  1276 			chan = i;
  1277 		}
  1278 	}
  1279 	return(chan);
  1280 }
  1281 
  1282 
  1283 
  1284 /*
  1285  * rcg06122001 The special effects exportable API.
  1286  *  Please see effect_*.c for internally-implemented effects, such
  1287  *  as Mix_SetPanning().
  1288  */
  1289 
  1290 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1291 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
  1292 				Mix_EffectDone_t d, void *arg)
  1293 {
  1294 	effect_info *new_e;
  1295 
  1296 	if (!e) {
  1297 		Mix_SetError("Internal error");
  1298 		return(0);
  1299 	}
  1300 
  1301 	if (f == NULL) {
  1302 		Mix_SetError("NULL effect callback");
  1303 		return(0);
  1304 	}
  1305 
  1306 	new_e = malloc(sizeof (effect_info));
  1307 	if (new_e == NULL) {
  1308 		Mix_SetError("Out of memory");
  1309 		return(0);
  1310 	}
  1311 
  1312 	new_e->callback = f;
  1313 	new_e->done_callback = d;
  1314 	new_e->udata = arg;
  1315 	new_e->next = NULL;
  1316 
  1317 	/* add new effect to end of linked list... */
  1318 	if (*e == NULL) {
  1319 		*e = new_e;
  1320 	} else {
  1321 		effect_info *cur = *e;
  1322 		while (1) {
  1323 			if (cur->next == NULL) {
  1324 				cur->next = new_e;
  1325 				break;
  1326 			}
  1327 			cur = cur->next;
  1328 		}
  1329 	}
  1330 
  1331 	return(1);
  1332 }
  1333 
  1334 
  1335 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1336 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
  1337 {
  1338 	effect_info *cur;
  1339 	effect_info *prev = NULL;
  1340 	effect_info *next = NULL;
  1341 
  1342 	if (!e) {
  1343 		Mix_SetError("Internal error");
  1344 		return(0);
  1345 	}
  1346 
  1347 	for (cur = *e; cur != NULL; cur = cur->next) {
  1348 		if (cur->callback == f) {
  1349 			next = cur->next;
  1350 			if (cur->done_callback != NULL) {
  1351 				cur->done_callback(channel, cur->udata);
  1352 			}
  1353 			free(cur);
  1354 
  1355 			if (prev == NULL) {   /* removing first item of list? */
  1356 				*e = next;
  1357 			} else {
  1358 				prev->next = next;
  1359 			}
  1360 			return(1);
  1361 		}
  1362 		prev = cur;
  1363 	}
  1364 
  1365 	Mix_SetError("No such effect registered");
  1366 	return(0);
  1367 }
  1368 
  1369 
  1370 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1371 static int _Mix_remove_all_effects(int channel, effect_info **e)
  1372 {
  1373 	effect_info *cur;
  1374 	effect_info *next;
  1375 
  1376 	if (!e) {
  1377 		Mix_SetError("Internal error");
  1378 		return(0);
  1379 	}
  1380 
  1381 	for (cur = *e; cur != NULL; cur = next) {
  1382 		next = cur->next;
  1383 		if (cur->done_callback != NULL) {
  1384 			cur->done_callback(channel, cur->udata);
  1385 		}
  1386 		free(cur);
  1387 	}
  1388 	*e = NULL;
  1389 
  1390 	return(1);
  1391 }
  1392 
  1393 
  1394 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1395 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
  1396 			Mix_EffectDone_t d, void *arg)
  1397 {
  1398 	effect_info **e = NULL;
  1399 
  1400 	if (channel == MIX_CHANNEL_POST) {
  1401 		e = &posteffects;
  1402 	} else {
  1403 		if ((channel < 0) || (channel >= num_channels)) {
  1404 			Mix_SetError("Invalid channel number");
  1405 			return(0);
  1406 		}
  1407 		e = &mix_channel[channel].effects;
  1408 	}
  1409 
  1410 	return _Mix_register_effect(e, f, d, arg);
  1411 }
  1412 
  1413 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
  1414 			Mix_EffectDone_t d, void *arg)
  1415 {
  1416     int retval;
  1417 	SDL_LockAudio();
  1418 	retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
  1419 	SDL_UnlockAudio();
  1420     return retval;
  1421 }
  1422 
  1423 
  1424 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1425 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
  1426 {
  1427 	effect_info **e = NULL;
  1428 
  1429 	if (channel == MIX_CHANNEL_POST) {
  1430 		e = &posteffects;
  1431 	} else {
  1432 		if ((channel < 0) || (channel >= num_channels)) {
  1433 			Mix_SetError("Invalid channel number");
  1434 			return(0);
  1435 		}
  1436 		e = &mix_channel[channel].effects;
  1437 	}
  1438 
  1439 	return _Mix_remove_effect(channel, e, f);
  1440 }
  1441 
  1442 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
  1443 {
  1444 	int retval;
  1445 	SDL_LockAudio();
  1446 	retval = _Mix_UnregisterEffect_locked(channel, f);
  1447 	SDL_UnlockAudio();
  1448 	return(retval);
  1449 }
  1450 
  1451 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1452 int _Mix_UnregisterAllEffects_locked(int channel)
  1453 {
  1454 	effect_info **e = NULL;
  1455 
  1456 	if (channel == MIX_CHANNEL_POST) {
  1457 		e = &posteffects;
  1458 	} else {
  1459 		if ((channel < 0) || (channel >= num_channels)) {
  1460 			Mix_SetError("Invalid channel number");
  1461 			return(0);
  1462 		}
  1463 		e = &mix_channel[channel].effects;
  1464 	}
  1465 
  1466 	return _Mix_remove_all_effects(channel, e);
  1467 }
  1468 
  1469 int Mix_UnregisterAllEffects(int channel)
  1470 {
  1471 	int retval;
  1472 	SDL_LockAudio();
  1473 	retval = _Mix_UnregisterAllEffects_locked(channel);
  1474 	SDL_UnlockAudio();
  1475 	return(retval);
  1476 }
  1477 
  1478 /* end of mixer.c ... */
  1479