mixer.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 17 Oct 2017 02:33:47 -0700
changeset 777 92882ef2ab81
parent 771 fa081ec2940e
child 782 e7d3a8f73e88
permissions -rw-r--r--
Rewrote music.c to support any number of decode libraries using a compiled-in plugin interface
Mix_LoadWAV_RW() can now load sound formats that were previously available only as music.

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