Subversion Repositories Kolibri OS

Rev

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