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