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