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