fix build.
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
30 #include "SDL_mixer.h"
33 #include "load_aiff.h"
36 #define MIX_INTERNAL_EFFECT__
37 #include "effects_internal.h"
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" */
45 static int audio_opened = 0;
46 static SDL_AudioSpec mixer;
47 static SDL_AudioDeviceID audio_device;
49 typedef struct _Mix_effectinfo
51 Mix_EffectFunc_t callback;
52 Mix_EffectDone_t done_callback;
54 struct _Mix_effectinfo *next;
57 static struct _Mix_Channel {
69 int fade_volume_reset;
73 } *mix_channel = NULL;
75 static effect_info *posteffects = NULL;
77 static int num_channels;
78 static int reserved_channels = 0;
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;
85 /* rcg07062001 callback to alert when channels are done playing. */
86 static void (SDLCALL *channel_done_callback)(int channel) = NULL;
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;
92 /* rcg06042009 report available decoders at runtime. */
93 static const char **chunk_decoders = NULL;
94 static int num_decoders = 0;
97 int Mix_GetNumChunkDecoders(void)
102 const char *Mix_GetChunkDecoder(int index)
104 if ((index < 0) || (index >= num_decoders)) {
107 return(chunk_decoders[index]);
110 SDL_bool Mix_HasChunkDecoder(const char *name)
113 for (index = 0; index < num_decoders; ++index) {
114 if (SDL_strcasecmp(name, chunk_decoders[index]) == 0) {
121 void add_chunk_decoder(const char *decoder)
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) {
133 ptr = SDL_realloc((void *)chunk_decoders, (size_t)(num_decoders + 1) * sizeof (const char *));
135 return; /* oh well, go on without it. */
137 chunk_decoders = (const char **) ptr;
138 chunk_decoders[num_decoders++] = decoder;
141 /* rcg06192001 get linked library's version. */
142 const SDL_version *Mix_Linked_Version(void)
144 static SDL_version linked_version;
145 SDL_MIXER_VERSION(&linked_version);
146 return(&linked_version);
149 int Mix_Init(int flags)
153 if (flags & MIX_INIT_FLAC) {
154 if (load_music_type(MUS_FLAC)) {
155 open_music_type(MUS_FLAC);
156 result |= MIX_INIT_FLAC;
158 Mix_SetError("FLAC support not available");
161 if (flags & MIX_INIT_MOD) {
162 if (load_music_type(MUS_MOD)) {
163 open_music_type(MUS_MOD);
164 result |= MIX_INIT_MOD;
166 Mix_SetError("MOD support not available");
169 if (flags & MIX_INIT_MP3) {
170 if (load_music_type(MUS_MP3)) {
171 open_music_type(MUS_MP3);
172 result |= MIX_INIT_MP3;
174 Mix_SetError("MP3 support not available");
177 if (flags & MIX_INIT_OGG) {
178 if (load_music_type(MUS_OGG)) {
179 open_music_type(MUS_OGG);
180 result |= MIX_INIT_OGG;
182 Mix_SetError("OGG support not available");
185 if (flags & MIX_INIT_OPUS) {
186 if (load_music_type(MUS_OPUS)) {
187 open_music_type(MUS_OPUS);
188 result |= MIX_INIT_OPUS;
190 Mix_SetError("OPUS support not available");
193 if (flags & MIX_INIT_MID) {
194 if (load_music_type(MUS_MID)) {
195 open_music_type(MUS_MID);
196 result |= MIX_INIT_MID;
198 Mix_SetError("MIDI support not available");
209 static int _Mix_remove_all_effects(int channel, effect_info **e);
212 * rcg06122001 Cleanup effect callbacks.
213 * MAKE SURE Mix_LockAudio() is called before this (or you're in the
216 static void _Mix_channel_done_playing(int channel)
218 if (channel_done_callback) {
219 channel_done_callback(channel);
223 * Call internal function directly, to avoid locking audio from
224 * inside audio callback.
226 _Mix_remove_all_effects(channel, &mix_channel[channel].effects);
230 static void *Mix_DoEffects(int chan, void *snd, int len)
232 int posteffect = (chan == MIX_CHANNEL_POST);
233 effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects);
236 if (e != NULL) { /* are there any registered effects? */
237 /* if this is the postmix, we can just overwrite the original. */
239 buf = SDL_malloc((size_t)len);
243 SDL_memcpy(buf, snd, (size_t)len);
246 for (; e != NULL; e = e->next) {
247 if (e->callback != NULL) {
248 e->callback(chan, buf, len, e->udata);
253 /* be sure to SDL_free() the return value if != snd ... */
258 /* Mixing function */
260 mix_channels(void *udata, Uint8 *stream, int len)
263 int i, mixable, volume = MIX_MAX_VOLUME;
268 #if SDL_VERSION_ATLEAST(1, 3, 0)
269 /* Need to initialize the stream in SDL 1.3+ */
270 SDL_memset(stream, mixer.silence, (size_t)len);
273 /* Mix the music (must be done before the channels are added) */
274 mix_music(music_data, stream, len);
276 /* Mix any playing channels... */
277 sdl_ticks = SDL_GetTicks();
278 for (i=0; i<num_channels; ++i) {
279 if (!mix_channel[i].paused) {
280 if (mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks) {
281 /* Expiration delay for that channel is reached */
282 mix_channel[i].playing = 0;
283 mix_channel[i].looping = 0;
284 mix_channel[i].fading = MIX_NO_FADING;
285 mix_channel[i].expire = 0;
286 _Mix_channel_done_playing(i);
287 } else if (mix_channel[i].fading != MIX_NO_FADING) {
288 Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
289 if (ticks >= mix_channel[i].fade_length) {
290 Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
291 if(mix_channel[i].fading == MIX_FADING_OUT) {
292 mix_channel[i].playing = 0;
293 mix_channel[i].looping = 0;
294 mix_channel[i].expire = 0;
295 _Mix_channel_done_playing(i);
297 mix_channel[i].fading = MIX_NO_FADING;
299 if (mix_channel[i].fading == MIX_FADING_OUT) {
300 Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
301 / mix_channel[i].fade_length);
303 Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length);
307 if (mix_channel[i].playing > 0) {
310 while (mix_channel[i].playing > 0 && index < len) {
311 remaining = len - index;
312 volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
313 mixable = mix_channel[i].playing;
314 if (mixable > remaining) {
318 mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
319 SDL_MixAudioFormat(stream+index,mix_input,mixer.format,mixable,volume);
320 if (mix_input != mix_channel[i].samples)
323 mix_channel[i].samples += mixable;
324 mix_channel[i].playing -= mixable;
327 /* rcg06072001 Alert app if channel is done playing. */
328 if (!mix_channel[i].playing && !mix_channel[i].looping) {
329 _Mix_channel_done_playing(i);
333 /* If looping the sample and we are at its end, make sure
334 we will still return a full buffer */
335 while (mix_channel[i].looping && index < len) {
336 int alen = mix_channel[i].chunk->alen;
337 remaining = len - index;
338 if (remaining > alen) {
342 mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
343 SDL_MixAudioFormat(stream+index, mix_input, mixer.format, remaining, volume);
344 if (mix_input != mix_channel[i].chunk->abuf)
347 if (mix_channel[i].looping > 0) {
348 --mix_channel[i].looping;
350 mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
351 mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
354 if (! mix_channel[i].playing && mix_channel[i].looping) {
355 if (mix_channel[i].looping > 0) {
356 --mix_channel[i].looping;
358 mix_channel[i].samples = mix_channel[i].chunk->abuf;
359 mix_channel[i].playing = mix_channel[i].chunk->alen;
365 /* rcg06122001 run posteffects... */
366 Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
369 mix_postmix(mix_postmix_data, stream, len);
374 static void PrintFormat(char *title, SDL_AudioSpec *fmt)
376 printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
377 (fmt->format&0x8000) ? "signed" : "unsigned",
378 (fmt->channels > 2) ? "surround" :
379 (fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
383 /* Open the mixer with a certain desired audio format */
384 int Mix_OpenAudioDevice(int frequency, Uint16 format, int nchannels, int chunksize,
385 const char* device, int allowed_changes)
388 SDL_AudioSpec desired;
390 /* This used to call SDL_OpenAudio(), which initializes the audio
391 subsystem if necessary. Since SDL_OpenAudioDevice() doesn't,
392 we have to handle this case here. */
393 if (!SDL_WasInit(SDL_INIT_AUDIO)) {
394 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
399 /* If the mixer is already opened, increment open count */
401 if (format == mixer.format && nchannels == mixer.channels) {
405 while (audio_opened) {
410 /* Set the desired format and frequency */
411 desired.freq = frequency;
412 desired.format = format;
413 desired.channels = nchannels;
414 desired.samples = chunksize;
415 desired.callback = mix_channels;
416 desired.userdata = NULL;
418 /* Accept nearly any audio format */
419 if ((audio_device = SDL_OpenAudioDevice(device, 0, &desired, &mixer, allowed_changes)) == 0) {
423 PrintFormat("Audio device", &mixer);
426 num_channels = MIX_CHANNELS;
427 mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
429 /* Clear out the audio channels */
430 for (i=0; i<num_channels; ++i) {
431 mix_channel[i].chunk = NULL;
432 mix_channel[i].playing = 0;
433 mix_channel[i].looping = 0;
434 mix_channel[i].volume = SDL_MIX_MAXVOLUME;
435 mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
436 mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
437 mix_channel[i].fading = MIX_NO_FADING;
438 mix_channel[i].tag = -1;
439 mix_channel[i].expire = 0;
440 mix_channel[i].effects = NULL;
441 mix_channel[i].paused = 0;
443 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
447 add_chunk_decoder("WAVE");
448 add_chunk_decoder("AIFF");
449 add_chunk_decoder("VOC");
451 /* Initialize the music players */
455 SDL_PauseAudioDevice(audio_device, 0);
459 /* Open the mixer with a certain desired audio format */
460 int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
462 return Mix_OpenAudioDevice(frequency, format, nchannels, chunksize, NULL,
463 SDL_AUDIO_ALLOW_FREQUENCY_CHANGE |
464 SDL_AUDIO_ALLOW_CHANNELS_CHANGE);
467 /* Dynamically change the number of channels managed by the mixer.
468 If decreasing the number of channels, the upper channels are
471 int Mix_AllocateChannels(int numchans)
473 if (numchans<0 || numchans==num_channels)
474 return(num_channels);
476 if (numchans < num_channels) {
477 /* Stop the affected channels */
479 for(i=numchans; i < num_channels; i++) {
480 Mix_UnregisterAllEffects(i);
485 mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
486 if (numchans > num_channels) {
487 /* Initialize the new channels */
489 for(i=num_channels; i < numchans; i++) {
490 mix_channel[i].chunk = NULL;
491 mix_channel[i].playing = 0;
492 mix_channel[i].looping = 0;
493 mix_channel[i].volume = MIX_MAX_VOLUME;
494 mix_channel[i].fade_volume = MIX_MAX_VOLUME;
495 mix_channel[i].fade_volume_reset = MIX_MAX_VOLUME;
496 mix_channel[i].fading = MIX_NO_FADING;
497 mix_channel[i].tag = -1;
498 mix_channel[i].expire = 0;
499 mix_channel[i].effects = NULL;
500 mix_channel[i].paused = 0;
503 num_channels = numchans;
505 return(num_channels);
508 /* Return the actual mixer parameters */
509 int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
513 *frequency = mixer.freq;
516 *format = mixer.format;
519 *channels = mixer.channels;
522 return(audio_opened);
525 typedef struct _MusicFragment
529 struct _MusicFragment *next;
532 static SDL_AudioSpec *Mix_LoadMusic_RW(SDL_RWops *src, int freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
535 Mix_MusicType music_type;
536 Mix_MusicInterface *interface = NULL;
540 MusicFragment *first = NULL, *last = NULL, *fragment = NULL;
544 music_type = detect_music_type(src);
545 if (!load_music_type(music_type) || !open_music_type(music_type)) {
551 /* Use fragments sized on full audio frame boundaries - this'll do */
552 fragment_size = spec->size;
554 start = SDL_RWtell(src);
555 for (i = 0; i < get_num_music_interfaces(); ++i) {
556 interface = get_music_interface(i);
557 if (!interface->opened) {
560 if (interface->type != music_type) {
563 if (!interface->CreateFromRW || !interface->GetAudio) {
567 /* These music interfaces are not safe to use while music is playing */
568 if (interface->api == MIX_MUSIC_CMD ||
569 interface->api == MIX_MUSIC_MIKMOD ||
570 interface->api == MIX_MUSIC_NATIVEMIDI) {
574 music = interface->CreateFromRW(src, freesrc);
576 /* The interface owns the data source now */
581 /* Reset the stream for the next decoder */
582 SDL_RWseek(src, start, RW_SEEK_SET);
589 Mix_SetError("Unrecognized audio format");
595 if (interface->Play) {
596 interface->Play(music, 1);
603 fragment = (MusicFragment *)SDL_malloc(sizeof(*fragment));
605 /* Uh oh, out of memory, let's return what we have */
608 fragment->data = (Uint8 *)SDL_malloc(fragment_size);
609 if (!fragment->data) {
610 /* Uh oh, out of memory, let's return what we have */
614 fragment->next = NULL;
616 left = interface->GetAudio(music, fragment->data, fragment_size);
619 } else if (interface->IsPlaying) {
620 playing = interface->IsPlaying(music);
622 fragment->size = (fragment_size - left);
628 last->next = fragment;
634 if (interface->Stop) {
635 interface->Stop(music);
639 interface->Delete(music);
645 *audio_len = (count - 1) * fragment_size + fragment->size;
646 *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
648 Uint8 *dst = *audio_buf;
649 for (fragment = first; fragment; fragment = fragment->next) {
650 SDL_memcpy(dst, fragment->data, fragment->size);
651 dst += fragment->size;
658 Mix_SetError("No audio data");
665 SDL_free(fragment->data);
675 /* Load a wave file */
676 Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
680 SDL_AudioSpec wavespec, *loaded;
681 SDL_AudioCVT wavecvt;
684 /* rcg06012001 Make sure src is valid */
686 SDL_SetError("Mix_LoadWAV_RW with NULL src");
690 /* Make sure audio has been opened */
692 SDL_SetError("Audio device hasn't been opened");
699 /* Allocate the chunk memory */
700 chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
702 SDL_SetError("Out of memory");
709 /* Find out what kind of audio file this is */
710 if (SDL_RWread(src, magic, 1, 4) != 4) {
714 Mix_SetError("Couldn't read first 4 bytes of audio data");
717 /* Seek backwards for compatibility with older loaders */
718 SDL_RWseek(src, -4, RW_SEEK_CUR);
720 if (SDL_memcmp(magic, "WAVE", 4) == 0 || SDL_memcmp(magic, "RIFF", 4) == 0) {
721 loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
722 } else if (SDL_memcmp(magic, "FORM", 4) == 0) {
723 loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
724 } else if (SDL_memcmp(magic, "Crea", 4) == 0) {
725 loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
727 loaded = Mix_LoadMusic_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
730 /* The individual loaders have closed src if needed */
736 PrintFormat("Audio device", &mixer);
737 PrintFormat("-- Wave file", &wavespec);
740 /* Build the audio converter and create conversion buffers */
741 if (wavespec.format != mixer.format ||
742 wavespec.channels != mixer.channels ||
743 wavespec.freq != mixer.freq) {
744 if (SDL_BuildAudioCVT(&wavecvt,
745 wavespec.format, wavespec.channels, wavespec.freq,
746 mixer.format, mixer.channels, mixer.freq) < 0) {
747 SDL_free(chunk->abuf);
751 samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
752 wavecvt.len = chunk->alen & ~(samplesize-1);
753 wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
754 if (wavecvt.buf == NULL) {
755 SDL_SetError("Out of memory");
756 SDL_free(chunk->abuf);
760 SDL_memcpy(wavecvt.buf, chunk->abuf, wavecvt.len);
761 SDL_free(chunk->abuf);
763 /* Run the audio converter */
764 if (SDL_ConvertAudio(&wavecvt) < 0) {
765 SDL_free(wavecvt.buf);
770 chunk->abuf = wavecvt.buf;
771 chunk->alen = wavecvt.len_cvt;
774 chunk->allocated = 1;
775 chunk->volume = MIX_MAX_VOLUME;
780 /* Load a wave file of the mixer format from a memory buffer */
781 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
786 /* Make sure audio has been opened */
787 if (! audio_opened) {
788 SDL_SetError("Audio device hasn't been opened");
792 /* Allocate the chunk memory */
793 chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
795 SDL_SetError("Out of memory");
799 /* Essentially just skip to the audio data (no error checking - fast) */
800 chunk->allocated = 0;
801 mem += 12; /* WAV header */
803 SDL_memcpy(magic, mem, 4);
805 chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
809 } while (memcmp(magic, "data", 4) != 0);
810 chunk->volume = MIX_MAX_VOLUME;
815 /* Load raw audio data of the mixer format from a memory buffer */
816 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
820 /* Make sure audio has been opened */
821 if (! audio_opened) {
822 SDL_SetError("Audio device hasn't been opened");
826 /* Allocate the chunk memory */
827 chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
829 SDL_SetError("Out of memory");
833 /* Essentially just point at the audio data (no error checking - fast) */
834 chunk->allocated = 0;
837 chunk->volume = MIX_MAX_VOLUME;
842 /* Free an audio chunk previously loaded */
843 void Mix_FreeChunk(Mix_Chunk *chunk)
847 /* Caution -- if the chunk is playing, the mixer will crash */
849 /* Guarantee that this chunk isn't playing */
852 for (i=0; i<num_channels; ++i) {
853 if (chunk == mix_channel[i].chunk) {
854 mix_channel[i].playing = 0;
855 mix_channel[i].looping = 0;
860 /* Actually free the chunk */
861 if (chunk->allocated) {
862 SDL_free(chunk->abuf);
868 /* Set a function that is called after all mixing is performed.
869 This can be used to provide real-time visual display of the audio stream
870 or add a custom mixer filter for the stream data.
872 void Mix_SetPostMix(void (SDLCALL *mix_func)
873 (void *udata, Uint8 *stream, int len), void *arg)
876 mix_postmix_data = arg;
877 mix_postmix = mix_func;
881 /* Add your own music player or mixer function.
882 If 'mix_func' is NULL, the default music player is re-enabled.
884 void Mix_HookMusic(void (SDLCALL *mix_func)(void *udata, Uint8 *stream, int len),
888 if (mix_func != NULL) {
890 mix_music = mix_func;
893 mix_music = music_mixer;
898 void *Mix_GetMusicHookData(void)
903 void Mix_ChannelFinished(void (SDLCALL *channel_finished)(int channel))
906 channel_done_callback = channel_finished;
911 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
912 them dynamically to the next sample if requested with a -1 value below.
913 Returns the number of reserved channels.
915 int Mix_ReserveChannels(int num)
917 if (num > num_channels)
919 reserved_channels = num;
923 static int checkchunkintegral(Mix_Chunk *chunk)
927 if ((mixer.format & 0xFF) == 16) frame_width = 2;
928 frame_width *= mixer.channels;
929 while (chunk->alen % frame_width) chunk->alen--;
933 /* Play an audio chunk on a specific channel.
934 If the specified channel is -1, play on the first free channel.
935 'ticks' is the number of milliseconds at most to play the sample, or -1
936 if there is no limit.
937 Returns which channel was used to play the sound.
939 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
943 /* Don't play null pointers :-) */
945 Mix_SetError("Tried to play a NULL chunk");
948 if (!checkchunkintegral(chunk)) {
949 Mix_SetError("Tried to play a chunk with a bad frame");
953 /* Lock the mixer while modifying the playing channels */
956 /* If which is -1, play on the first free channel */
958 for (i=reserved_channels; i<num_channels; ++i) {
959 if (mix_channel[i].playing <= 0)
962 if (i == num_channels) {
963 Mix_SetError("No free channels available");
970 /* Queue up the audio data for this channel */
971 if (which >= 0 && which < num_channels) {
972 Uint32 sdl_ticks = SDL_GetTicks();
973 if (Mix_Playing(which))
974 _Mix_channel_done_playing(which);
975 mix_channel[which].samples = chunk->abuf;
976 mix_channel[which].playing = (int)chunk->alen;
977 mix_channel[which].looping = loops;
978 mix_channel[which].chunk = chunk;
979 mix_channel[which].paused = 0;
980 mix_channel[which].fading = MIX_NO_FADING;
981 mix_channel[which].start_time = sdl_ticks;
982 mix_channel[which].expire = (ticks > 0) ? (sdl_ticks + (Uint32)ticks) : 0;
987 /* Return the channel on which the sound is being played */
991 /* Change the expiration delay for a channel */
992 int Mix_ExpireChannel(int which, int ticks)
998 for (i=0; i < num_channels; ++ i) {
999 status += Mix_ExpireChannel(i, ticks);
1001 } else if (which < num_channels) {
1003 mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + (Uint32)ticks) : 0;
1010 /* Fade in a sound on a channel, over ms milliseconds */
1011 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
1015 /* Don't play null pointers :-) */
1016 if (chunk == NULL) {
1019 if (!checkchunkintegral(chunk)) {
1020 Mix_SetError("Tried to play a chunk with a bad frame");
1024 /* Lock the mixer while modifying the playing channels */
1027 /* If which is -1, play on the first free channel */
1029 for (i=reserved_channels; i<num_channels; ++i) {
1030 if (mix_channel[i].playing <= 0)
1033 if (i == num_channels) {
1040 /* Queue up the audio data for this channel */
1041 if (which >= 0 && which < num_channels) {
1042 Uint32 sdl_ticks = SDL_GetTicks();
1043 if (Mix_Playing(which))
1044 _Mix_channel_done_playing(which);
1045 mix_channel[which].samples = chunk->abuf;
1046 mix_channel[which].playing = (int)chunk->alen;
1047 mix_channel[which].looping = loops;
1048 mix_channel[which].chunk = chunk;
1049 mix_channel[which].paused = 0;
1050 if (mix_channel[which].fading == MIX_NO_FADING) {
1051 mix_channel[which].fade_volume_reset = mix_channel[which].volume;
1053 mix_channel[which].fading = MIX_FADING_IN;
1054 mix_channel[which].fade_volume = mix_channel[which].volume;
1055 mix_channel[which].volume = 0;
1056 mix_channel[which].fade_length = (Uint32)ms;
1057 mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
1058 mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+(Uint32)ticks) : 0;
1063 /* Return the channel on which the sound is being played */
1067 /* Set volume of a particular channel */
1068 int Mix_Volume(int which, int volume)
1071 int prev_volume = 0;
1074 for (i=0; i<num_channels; ++i) {
1075 prev_volume += Mix_Volume(i, volume);
1077 prev_volume /= num_channels;
1078 } else if (which < num_channels) {
1079 prev_volume = mix_channel[which].volume;
1081 if (volume > MIX_MAX_VOLUME) {
1082 volume = MIX_MAX_VOLUME;
1084 mix_channel[which].volume = volume;
1087 return(prev_volume);
1089 /* Set volume of a particular chunk */
1090 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
1094 prev_volume = chunk->volume;
1096 if (volume > MIX_MAX_VOLUME) {
1097 volume = MIX_MAX_VOLUME;
1099 chunk->volume = volume;
1101 return(prev_volume);
1104 /* Halt playing of a particular channel */
1105 int Mix_HaltChannel(int which)
1110 for (i=0; i<num_channels; ++i) {
1113 } else if (which < num_channels) {
1115 if (mix_channel[which].playing) {
1116 _Mix_channel_done_playing(which);
1117 mix_channel[which].playing = 0;
1118 mix_channel[which].looping = 0;
1120 mix_channel[which].expire = 0;
1121 if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
1122 mix_channel[which].volume = mix_channel[which].fade_volume_reset;
1123 mix_channel[which].fading = MIX_NO_FADING;
1129 /* Halt playing of a particular group of channels */
1130 int Mix_HaltGroup(int tag)
1134 for (i=0; i<num_channels; ++i) {
1135 if(mix_channel[i].tag == tag) {
1142 /* Fade out a channel and then stop it automatically */
1143 int Mix_FadeOutChannel(int which, int ms)
1152 for (i=0; i<num_channels; ++i) {
1153 status += Mix_FadeOutChannel(i, ms);
1155 } else if (which < num_channels) {
1157 if (mix_channel[which].playing &&
1158 (mix_channel[which].volume > 0) &&
1159 (mix_channel[which].fading != MIX_FADING_OUT)) {
1160 mix_channel[which].fade_volume = mix_channel[which].volume;
1161 mix_channel[which].fade_length = (Uint32)ms;
1162 mix_channel[which].ticks_fade = SDL_GetTicks();
1164 /* only change fade_volume_reset if we're not fading. */
1165 if (mix_channel[which].fading == MIX_NO_FADING) {
1166 mix_channel[which].fade_volume_reset = mix_channel[which].volume;
1169 mix_channel[which].fading = MIX_FADING_OUT;
1179 /* Halt playing of a particular group of channels */
1180 int Mix_FadeOutGroup(int tag, int ms)
1184 for (i=0; i<num_channels; ++i) {
1185 if(mix_channel[i].tag == tag) {
1186 status += Mix_FadeOutChannel(i,ms);
1192 Mix_Fading Mix_FadingChannel(int which)
1194 if (which < 0 || which >= num_channels) {
1195 return MIX_NO_FADING;
1197 return mix_channel[which].fading;
1200 /* Check the status of a specific channel.
1201 If the specified mix_channel is -1, check all mix channels.
1203 int Mix_Playing(int which)
1211 for (i=0; i<num_channels; ++i) {
1212 if ((mix_channel[i].playing > 0) ||
1213 mix_channel[i].looping)
1218 } else if (which < num_channels) {
1219 if ((mix_channel[which].playing > 0) ||
1220 mix_channel[which].looping)
1228 /* rcg06072001 Get the chunk associated with a channel. */
1229 Mix_Chunk *Mix_GetChunk(int channel)
1231 Mix_Chunk *retval = NULL;
1233 if ((channel >= 0) && (channel < num_channels)) {
1234 retval = mix_channel[channel].chunk;
1240 /* Close the mixer, halting all playing audio */
1241 void Mix_CloseAudio(void)
1246 if (audio_opened == 1) {
1247 for (i = 0; i < num_channels; i++) {
1248 Mix_UnregisterAllEffects(i);
1250 Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
1252 Mix_SetMusicCMD(NULL);
1253 Mix_HaltChannel(-1);
1254 _Mix_DeinitEffects();
1255 SDL_CloseAudioDevice(audio_device);
1257 SDL_free(mix_channel);
1260 /* rcg06042009 report available decoders at runtime. */
1261 SDL_free((void *)chunk_decoders);
1262 chunk_decoders = NULL;
1269 /* Pause a particular channel (or all) */
1270 void Mix_Pause(int which)
1272 Uint32 sdl_ticks = SDL_GetTicks();
1276 for (i=0; i<num_channels; ++i) {
1277 if (mix_channel[i].playing > 0) {
1278 mix_channel[i].paused = sdl_ticks;
1281 } else if (which < num_channels) {
1282 if (mix_channel[which].playing > 0) {
1283 mix_channel[which].paused = sdl_ticks;
1288 /* Resume a paused channel */
1289 void Mix_Resume(int which)
1291 Uint32 sdl_ticks = SDL_GetTicks();
1297 for (i=0; i<num_channels; ++i) {
1298 if (mix_channel[i].playing > 0) {
1299 if(mix_channel[i].expire > 0)
1300 mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
1301 mix_channel[i].paused = 0;
1304 } else if (which < num_channels) {
1305 if (mix_channel[which].playing > 0) {
1306 if(mix_channel[which].expire > 0)
1307 mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
1308 mix_channel[which].paused = 0;
1314 int Mix_Paused(int which)
1319 for(i=0; i < num_channels; ++i) {
1320 if (mix_channel[i].paused) {
1325 } else if (which < num_channels) {
1326 return(mix_channel[which].paused != 0);
1332 /* Change the group of a channel */
1333 int Mix_GroupChannel(int which, int tag)
1335 if (which < 0 || which > num_channels)
1339 mix_channel[which].tag = tag;
1344 /* Assign several consecutive channels to a group */
1345 int Mix_GroupChannels(int from, int to, int tag)
1348 for(; from <= to; ++ from) {
1349 status += Mix_GroupChannel(from, tag);
1354 /* Finds the first available channel in a group of channels */
1355 int Mix_GroupAvailable(int tag)
1358 for(i=0; i < num_channels; i ++) {
1359 if (((tag == -1) || (tag == mix_channel[i].tag)) &&
1360 (mix_channel[i].playing <= 0))
1366 int Mix_GroupCount(int tag)
1370 for(i=0; i < num_channels; i ++) {
1371 if (mix_channel[i].tag==tag || tag==-1)
1377 /* Finds the "oldest" sample playing in a group of channels */
1378 int Mix_GroupOldest(int tag)
1381 Uint32 mintime = SDL_GetTicks();
1383 for(i=0; i < num_channels; i ++) {
1384 if ((mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
1385 && mix_channel[i].start_time <= mintime) {
1386 mintime = mix_channel[i].start_time;
1393 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
1394 int Mix_GroupNewer(int tag)
1399 for(i=0; i < num_channels; i ++) {
1400 if ((mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
1401 && mix_channel[i].start_time >= maxtime) {
1402 maxtime = mix_channel[i].start_time;
1412 * rcg06122001 The special effects exportable API.
1413 * Please see effect_*.c for internally-implemented effects, such
1414 * as Mix_SetPanning().
1417 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1418 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
1419 Mix_EffectDone_t d, void *arg)
1424 Mix_SetError("Internal error");
1429 Mix_SetError("NULL effect callback");
1433 new_e = SDL_malloc(sizeof (effect_info));
1434 if (new_e == NULL) {
1435 Mix_SetError("Out of memory");
1439 new_e->callback = f;
1440 new_e->done_callback = d;
1444 /* add new effect to end of linked list... */
1448 effect_info *cur = *e;
1450 if (cur->next == NULL) {
1462 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1463 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
1466 effect_info *prev = NULL;
1467 effect_info *next = NULL;
1470 Mix_SetError("Internal error");
1474 for (cur = *e; cur != NULL; cur = cur->next) {
1475 if (cur->callback == f) {
1477 if (cur->done_callback != NULL) {
1478 cur->done_callback(channel, cur->udata);
1482 if (prev == NULL) { /* removing first item of list? */
1492 Mix_SetError("No such effect registered");
1497 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1498 static int _Mix_remove_all_effects(int channel, effect_info **e)
1504 Mix_SetError("Internal error");
1508 for (cur = *e; cur != NULL; cur = next) {
1510 if (cur->done_callback != NULL) {
1511 cur->done_callback(channel, cur->udata);
1521 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1522 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
1523 Mix_EffectDone_t d, void *arg)
1525 effect_info **e = NULL;
1527 if (channel == MIX_CHANNEL_POST) {
1530 if ((channel < 0) || (channel >= num_channels)) {
1531 Mix_SetError("Invalid channel number");
1534 e = &mix_channel[channel].effects;
1537 return _Mix_register_effect(e, f, d, arg);
1540 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
1541 Mix_EffectDone_t d, void *arg)
1545 retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
1551 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1552 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
1554 effect_info **e = NULL;
1556 if (channel == MIX_CHANNEL_POST) {
1559 if ((channel < 0) || (channel >= num_channels)) {
1560 Mix_SetError("Invalid channel number");
1563 e = &mix_channel[channel].effects;
1566 return _Mix_remove_effect(channel, e, f);
1569 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
1573 retval = _Mix_UnregisterEffect_locked(channel, f);
1578 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
1579 int _Mix_UnregisterAllEffects_locked(int channel)
1581 effect_info **e = NULL;
1583 if (channel == MIX_CHANNEL_POST) {
1586 if ((channel < 0) || (channel >= num_channels)) {
1587 Mix_SetError("Invalid channel number");
1590 e = &mix_channel[channel].effects;
1593 return _Mix_remove_all_effects(channel, e);
1596 int Mix_UnregisterAllEffects(int channel)
1600 retval = _Mix_UnregisterAllEffects_locked(channel);
1605 void Mix_LockAudio(void)
1607 SDL_LockAudioDevice(audio_device);
1610 void Mix_UnlockAudio(void)
1612 SDL_UnlockAudioDevice(audio_device);
1615 /* end of mixer.c ... */
1617 /* vi: set ts=4 sw=4 expandtab: */