Subversion Repositories Kolibri OS

Rev

Rev 9097 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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