mixer.c
author Ozkan Sezer
Sat, 14 Dec 2019 18:14:10 +0300
branchSDL-1.2
changeset 1081 119300487b73
parent 943 b57842dc6349
child 1136 33a3817d1066
permissions -rw-r--r--
backport default/2.0 commits 6c6adcc and 1e215d1 for fluidsynth support:

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