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