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