mixer.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 17 Oct 2017 21:54:04 -0700
changeset 782 e7d3a8f73e88
parent 777 92882ef2ab81
child 797 b4b6adff699a
permissions -rw-r--r--
Merged over timidity from SDL_sound
This has changes to make it safe to load MIDI files as sound chunks and adds the ability to seek in MIDI files
Also cherry picked some patches from the original SDL_mixer timidity to fix buffer overruns and so forth.
     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_NATIVEMIDI) {
   572             continue;
   573         }
   574 
   575         music = interface->CreateFromRW(src, freesrc);
   576         if (music) {
   577             /* The interface owns the data source now */
   578             freesrc = SDL_FALSE;
   579             break;
   580         }
   581 
   582         if (interface->api == MIX_MUSIC_SMPEG) {
   583             /* Uh oh, if SMPEG couldn't create anything, it freed the src */
   584             freesrc = SDL_FALSE;
   585             break;
   586         }
   587 
   588         /* Reset the stream for the next decoder */
   589         SDL_RWseek(src, start, RW_SEEK_SET);
   590     }
   591 
   592     if (!music) {
   593         if (freesrc) {
   594             SDL_RWclose(src);
   595         }
   596         Mix_SetError("Unrecognized audio format");
   597         return NULL;
   598     }
   599 
   600     Mix_LockAudio();
   601     original_volume = music_volume;
   602  
   603     if (interface->SetVolume) {
   604         interface->SetVolume(music, MIX_MAX_VOLUME);
   605     }
   606 
   607     if (interface->Play) {
   608         interface->Play(music);
   609 	}
   610     playing = SDL_TRUE;
   611 
   612     while (playing) {
   613         int left;
   614 
   615         fragment = (MusicFragment *)SDL_malloc(sizeof(*fragment));
   616         if (!fragment) {
   617             /* Uh oh, out of memory, let's return what we have */
   618             break;
   619         }
   620         fragment->data = (Uint8 *)SDL_malloc(fragment_size);
   621         if (!fragment->data) {
   622             /* Uh oh, out of memory, let's return what we have */
   623             SDL_free(fragment);
   624             break;
   625         }
   626         fragment->next = NULL;
   627 
   628         left = interface->GetAudio(music, fragment->data, fragment_size);
   629         if (left > 0) {
   630             playing = SDL_FALSE;
   631         } else if (interface->IsPlaying) {
   632             playing = interface->IsPlaying(music);
   633         }
   634         fragment->size = (fragment_size - left);
   635 
   636         if (!first) {
   637             first = fragment;
   638         }
   639         if (last) {
   640             last->next = fragment;
   641         }
   642         last = fragment;
   643         ++count;
   644     }
   645 
   646     if (interface->Stop) {
   647         interface->Stop(music);
   648     }
   649 
   650     if (interface->SetVolume) {
   651         interface->SetVolume(music, original_volume);
   652     }
   653 
   654     if (music) {
   655         interface->Delete(music);
   656     }
   657 
   658     Mix_UnlockAudio();
   659 
   660     if (count > 0) {
   661         *audio_len = (count - 1) * fragment_size + fragment->size;
   662         *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
   663         if (*audio_buf) {
   664             Uint8 *dst = *audio_buf;
   665             for (fragment = first; fragment; fragment = fragment->next) {
   666                 SDL_memcpy(dst, fragment->data, fragment->size);
   667                 dst += fragment->size;
   668             }
   669         } else {
   670             SDL_OutOfMemory();
   671             spec = NULL;
   672         }
   673     } else {
   674         Mix_SetError("No audio data");
   675         spec = NULL;
   676     }
   677 
   678     while (first) {
   679         fragment = first;
   680         first = first->next;
   681         SDL_free(fragment->data);
   682         SDL_free(fragment);
   683     }
   684 
   685     if (freesrc) {
   686         SDL_RWclose(src);
   687     }
   688     return spec;
   689 }
   690 
   691 /* Load a wave file */
   692 Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
   693 {
   694     Uint8 magic[4];
   695     Mix_Chunk *chunk;
   696     SDL_AudioSpec wavespec, *loaded;
   697     SDL_AudioCVT wavecvt;
   698     int samplesize;
   699 
   700     /* rcg06012001 Make sure src is valid */
   701     if (!src) {
   702         SDL_SetError("Mix_LoadWAV_RW with NULL src");
   703         return(NULL);
   704     }
   705 
   706     /* Make sure audio has been opened */
   707     if (!audio_opened) {
   708         SDL_SetError("Audio device hasn't been opened");
   709         if (freesrc) {
   710             SDL_RWclose(src);
   711         }
   712         return(NULL);
   713     }
   714 
   715     /* Allocate the chunk memory */
   716     chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   717     if (chunk == NULL) {
   718         SDL_SetError("Out of memory");
   719         if (freesrc) {
   720             SDL_RWclose(src);
   721         }
   722         return(NULL);
   723     }
   724 
   725     /* Find out what kind of audio file this is */
   726     if (SDL_RWread(src, magic, 1, 4) != 4) {
   727         if (freesrc) {
   728             SDL_RWclose(src);
   729         }
   730         Mix_SetError("Couldn't read first 4 bytes of audio data");
   731         return NULL;
   732     }
   733     /* Seek backwards for compatibility with older loaders */
   734     SDL_RWseek(src, -4, RW_SEEK_CUR);
   735 
   736     if (SDL_memcmp(magic, "WAVE", 4) == 0 || SDL_memcmp(magic, "RIFF", 4) == 0) {
   737         loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
   738     } else if (SDL_memcmp(magic, "FORM", 4) == 0) {
   739         loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
   740     } else if (SDL_memcmp(magic, "CREA", 4) == 0) {
   741         loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
   742     } else {
   743         Mix_MusicType music_type = detect_music_type_from_magic(magic);
   744         loaded = Mix_LoadMusic_RW(music_type, src, freesrc, &wavespec, (Uint8 **)&chunk->abuf, &chunk->alen);
   745     }
   746     if (!loaded) {
   747         /* The individual loaders have closed src if needed */
   748         SDL_free(chunk);
   749         return(NULL);
   750     }
   751 
   752 #if 0
   753     PrintFormat("Audio device", &mixer);
   754     PrintFormat("-- Wave file", &wavespec);
   755 #endif
   756 
   757     /* Build the audio converter and create conversion buffers */
   758     if (wavespec.format != mixer.format ||
   759          wavespec.channels != mixer.channels ||
   760          wavespec.freq != mixer.freq) {
   761         if (SDL_BuildAudioCVT(&wavecvt,
   762                 wavespec.format, wavespec.channels, wavespec.freq,
   763                 mixer.format, mixer.channels, mixer.freq) < 0) {
   764             SDL_free(chunk->abuf);
   765             SDL_free(chunk);
   766             return(NULL);
   767         }
   768         samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
   769         wavecvt.len = chunk->alen & ~(samplesize-1);
   770         wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
   771         if (wavecvt.buf == NULL) {
   772             SDL_SetError("Out of memory");
   773             SDL_free(chunk->abuf);
   774             SDL_free(chunk);
   775             return(NULL);
   776         }
   777         SDL_memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
   778         SDL_free(chunk->abuf);
   779 
   780         /* Run the audio converter */
   781         if (SDL_ConvertAudio(&wavecvt) < 0) {
   782             SDL_free(wavecvt.buf);
   783             SDL_free(chunk);
   784             return(NULL);
   785         }
   786 
   787         chunk->abuf = wavecvt.buf;
   788         chunk->alen = wavecvt.len_cvt;
   789     }
   790 
   791     chunk->allocated = 1;
   792     chunk->volume = MIX_MAX_VOLUME;
   793 
   794     return(chunk);
   795 }
   796 
   797 /* Load a wave file of the mixer format from a memory buffer */
   798 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
   799 {
   800     Mix_Chunk *chunk;
   801     Uint8 magic[4];
   802 
   803     /* Make sure audio has been opened */
   804     if (! audio_opened) {
   805         SDL_SetError("Audio device hasn't been opened");
   806         return(NULL);
   807     }
   808 
   809     /* Allocate the chunk memory */
   810     chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
   811     if (chunk == NULL) {
   812         SDL_SetError("Out of memory");
   813         return(NULL);
   814     }
   815 
   816     /* Essentially just skip to the audio data (no error checking - fast) */
   817     chunk->allocated = 0;
   818     mem += 12; /* WAV header */
   819     do {
   820         SDL_memcpy(magic, mem, 4);
   821         mem += 4;
   822         chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
   823         mem += 4;
   824         chunk->abuf = mem;
   825         mem += chunk->alen;
   826     } while (memcmp(magic, "data", 4) != 0);
   827     chunk->volume = MIX_MAX_VOLUME;
   828 
   829     return(chunk);
   830 }
   831 
   832 /* Load raw audio data of the mixer format from a memory buffer */
   833 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
   834 {
   835     Mix_Chunk *chunk;
   836 
   837     /* Make sure audio has been opened */
   838     if (! audio_opened) {
   839         SDL_SetError("Audio device hasn't been opened");
   840         return(NULL);
   841     }
   842 
   843     /* Allocate the chunk memory */
   844     chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   845     if (chunk == NULL) {
   846         SDL_SetError("Out of memory");
   847         return(NULL);
   848     }
   849 
   850     /* Essentially just point at the audio data (no error checking - fast) */
   851     chunk->allocated = 0;
   852     chunk->alen = len;
   853     chunk->abuf = mem;
   854     chunk->volume = MIX_MAX_VOLUME;
   855 
   856     return(chunk);
   857 }
   858 
   859 /* Free an audio chunk previously loaded */
   860 void Mix_FreeChunk(Mix_Chunk *chunk)
   861 {
   862     int i;
   863 
   864     /* Caution -- if the chunk is playing, the mixer will crash */
   865     if (chunk) {
   866         /* Guarantee that this chunk isn't playing */
   867         Mix_LockAudio();
   868         if (mix_channel) {
   869             for (i=0; i<num_channels; ++i) {
   870                 if (chunk == mix_channel[i].chunk) {
   871                     mix_channel[i].playing = 0;
   872                     mix_channel[i].looping = 0;
   873                 }
   874             }
   875         }
   876         Mix_UnlockAudio();
   877         /* Actually free the chunk */
   878         if (chunk->allocated) {
   879             SDL_free(chunk->abuf);
   880         }
   881         SDL_free(chunk);
   882     }
   883 }
   884 
   885 /* Set a function that is called after all mixing is performed.
   886    This can be used to provide real-time visual display of the audio stream
   887    or add a custom mixer filter for the stream data.
   888 */
   889 void Mix_SetPostMix(void (*mix_func)
   890                     (void *udata, Uint8 *stream, int len), void *arg)
   891 {
   892     Mix_LockAudio();
   893     mix_postmix_data = arg;
   894     mix_postmix = mix_func;
   895     Mix_UnlockAudio();
   896 }
   897 
   898 /* Add your own music player or mixer function.
   899    If 'mix_func' is NULL, the default music player is re-enabled.
   900  */
   901 void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
   902                                                                 void *arg)
   903 {
   904     Mix_LockAudio();
   905     if (mix_func != NULL) {
   906         music_data = arg;
   907         mix_music = mix_func;
   908     } else {
   909         music_data = NULL;
   910         mix_music = music_mixer;
   911     }
   912     Mix_UnlockAudio();
   913 }
   914 
   915 void *Mix_GetMusicHookData(void)
   916 {
   917     return(music_data);
   918 }
   919 
   920 void Mix_ChannelFinished(void (*channel_finished)(int channel))
   921 {
   922     Mix_LockAudio();
   923     channel_done_callback = channel_finished;
   924     Mix_UnlockAudio();
   925 }
   926 
   927 
   928 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
   929    them dynamically to the next sample if requested with a -1 value below.
   930    Returns the number of reserved channels.
   931  */
   932 int Mix_ReserveChannels(int num)
   933 {
   934     if (num > num_channels)
   935         num = num_channels;
   936     reserved_channels = num;
   937     return num;
   938 }
   939 
   940 static int checkchunkintegral(Mix_Chunk *chunk)
   941 {
   942     int frame_width = 1;
   943 
   944     if ((mixer.format & 0xFF) == 16) frame_width = 2;
   945     frame_width *= mixer.channels;
   946     while (chunk->alen % frame_width) chunk->alen--;
   947     return chunk->alen;
   948 }
   949 
   950 /* Play an audio chunk on a specific channel.
   951    If the specified channel is -1, play on the first free channel.
   952    'ticks' is the number of milliseconds at most to play the sample, or -1
   953    if there is no limit.
   954    Returns which channel was used to play the sound.
   955 */
   956 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   957 {
   958     int i;
   959 
   960     /* Don't play null pointers :-) */
   961     if (chunk == NULL) {
   962         Mix_SetError("Tried to play a NULL chunk");
   963         return(-1);
   964     }
   965     if (!checkchunkintegral(chunk)) {
   966         Mix_SetError("Tried to play a chunk with a bad frame");
   967         return(-1);
   968     }
   969 
   970     /* Lock the mixer while modifying the playing channels */
   971     Mix_LockAudio();
   972     {
   973         /* If which is -1, play on the first free channel */
   974         if (which == -1) {
   975             for (i=reserved_channels; i<num_channels; ++i) {
   976                 if (mix_channel[i].playing <= 0)
   977                     break;
   978             }
   979             if (i == num_channels) {
   980                 Mix_SetError("No free channels available");
   981                 which = -1;
   982             } else {
   983                 which = i;
   984             }
   985         }
   986 
   987         /* Queue up the audio data for this channel */
   988         if (which >= 0 && which < num_channels) {
   989             Uint32 sdl_ticks = SDL_GetTicks();
   990             if (Mix_Playing(which))
   991                 _Mix_channel_done_playing(which);
   992             mix_channel[which].samples = chunk->abuf;
   993             mix_channel[which].playing = chunk->alen;
   994             mix_channel[which].looping = loops;
   995             mix_channel[which].chunk = chunk;
   996             mix_channel[which].paused = 0;
   997             mix_channel[which].fading = MIX_NO_FADING;
   998             mix_channel[which].start_time = sdl_ticks;
   999             mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
  1000         }
  1001     }
  1002     Mix_UnlockAudio();
  1003 
  1004     /* Return the channel on which the sound is being played */
  1005     return(which);
  1006 }
  1007 
  1008 /* Change the expiration delay for a channel */
  1009 int Mix_ExpireChannel(int which, int ticks)
  1010 {
  1011     int status = 0;
  1012 
  1013     if (which == -1) {
  1014         int i;
  1015         for (i=0; i < num_channels; ++ i) {
  1016             status += Mix_ExpireChannel(i, ticks);
  1017         }
  1018     } else if (which < num_channels) {
  1019         Mix_LockAudio();
  1020         mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
  1021         Mix_UnlockAudio();
  1022         ++ status;
  1023     }
  1024     return(status);
  1025 }
  1026 
  1027 /* Fade in a sound on a channel, over ms milliseconds */
  1028 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
  1029 {
  1030     int i;
  1031 
  1032     /* Don't play null pointers :-) */
  1033     if (chunk == NULL) {
  1034         return(-1);
  1035     }
  1036     if (!checkchunkintegral(chunk)) {
  1037         Mix_SetError("Tried to play a chunk with a bad frame");
  1038         return(-1);
  1039     }
  1040 
  1041     /* Lock the mixer while modifying the playing channels */
  1042     Mix_LockAudio();
  1043     {
  1044         /* If which is -1, play on the first free channel */
  1045         if (which == -1) {
  1046             for (i=reserved_channels; i<num_channels; ++i) {
  1047                 if (mix_channel[i].playing <= 0)
  1048                     break;
  1049             }
  1050             if (i == num_channels) {
  1051                 which = -1;
  1052             } else {
  1053                 which = i;
  1054             }
  1055         }
  1056 
  1057         /* Queue up the audio data for this channel */
  1058         if (which >= 0 && which < num_channels) {
  1059             Uint32 sdl_ticks = SDL_GetTicks();
  1060             if (Mix_Playing(which))
  1061                 _Mix_channel_done_playing(which);
  1062             mix_channel[which].samples = chunk->abuf;
  1063             mix_channel[which].playing = chunk->alen;
  1064             mix_channel[which].looping = loops;
  1065             mix_channel[which].chunk = chunk;
  1066             mix_channel[which].paused = 0;
  1067             mix_channel[which].fading = MIX_FADING_IN;
  1068             mix_channel[which].fade_volume = mix_channel[which].volume;
  1069             mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1070             mix_channel[which].volume = 0;
  1071             mix_channel[which].fade_length = (Uint32)ms;
  1072             mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
  1073             mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
  1074         }
  1075     }
  1076     Mix_UnlockAudio();
  1077 
  1078     /* Return the channel on which the sound is being played */
  1079     return(which);
  1080 }
  1081 
  1082 /* Set volume of a particular channel */
  1083 int Mix_Volume(int which, int volume)
  1084 {
  1085     int i;
  1086     int prev_volume = 0;
  1087 
  1088     if (which == -1) {
  1089         for (i=0; i<num_channels; ++i) {
  1090             prev_volume += Mix_Volume(i, volume);
  1091         }
  1092         prev_volume /= num_channels;
  1093     } else if (which < num_channels) {
  1094         prev_volume = mix_channel[which].volume;
  1095         if (volume >= 0) {
  1096             if (volume > MIX_MAX_VOLUME) {
  1097                 volume = MIX_MAX_VOLUME;
  1098             }
  1099             mix_channel[which].volume = volume;
  1100         }
  1101     }
  1102     return(prev_volume);
  1103 }
  1104 /* Set volume of a particular chunk */
  1105 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
  1106 {
  1107     int prev_volume;
  1108 
  1109     prev_volume = chunk->volume;
  1110     if (volume >= 0) {
  1111         if (volume > MIX_MAX_VOLUME) {
  1112             volume = MIX_MAX_VOLUME;
  1113         }
  1114         chunk->volume = volume;
  1115     }
  1116     return(prev_volume);
  1117 }
  1118 
  1119 /* Halt playing of a particular channel */
  1120 int Mix_HaltChannel(int which)
  1121 {
  1122     int i;
  1123 
  1124     if (which == -1) {
  1125         for (i=0; i<num_channels; ++i) {
  1126             Mix_HaltChannel(i);
  1127         }
  1128     } else if (which < num_channels) {
  1129         Mix_LockAudio();
  1130         if (mix_channel[which].playing) {
  1131             _Mix_channel_done_playing(which);
  1132             mix_channel[which].playing = 0;
  1133             mix_channel[which].looping = 0;
  1134         }
  1135         mix_channel[which].expire = 0;
  1136         if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
  1137             mix_channel[which].volume = mix_channel[which].fade_volume_reset;
  1138         mix_channel[which].fading = MIX_NO_FADING;
  1139         Mix_UnlockAudio();
  1140     }
  1141     return(0);
  1142 }
  1143 
  1144 /* Halt playing of a particular group of channels */
  1145 int Mix_HaltGroup(int tag)
  1146 {
  1147     int i;
  1148 
  1149     for (i=0; i<num_channels; ++i) {
  1150         if(mix_channel[i].tag == tag) {
  1151             Mix_HaltChannel(i);
  1152         }
  1153     }
  1154     return(0);
  1155 }
  1156 
  1157 /* Fade out a channel and then stop it automatically */
  1158 int Mix_FadeOutChannel(int which, int ms)
  1159 {
  1160     int status;
  1161 
  1162     status = 0;
  1163     if (audio_opened) {
  1164         if (which == -1) {
  1165             int i;
  1166 
  1167             for (i=0; i<num_channels; ++i) {
  1168                 status += Mix_FadeOutChannel(i, ms);
  1169             }
  1170         } else if (which < num_channels) {
  1171             Mix_LockAudio();
  1172             if (mix_channel[which].playing &&
  1173                 (mix_channel[which].volume > 0) &&
  1174                 (mix_channel[which].fading != MIX_FADING_OUT)) {
  1175                 mix_channel[which].fade_volume = mix_channel[which].volume;
  1176                 mix_channel[which].fading = MIX_FADING_OUT;
  1177                 mix_channel[which].fade_length = (Uint32)ms;
  1178                 mix_channel[which].ticks_fade = SDL_GetTicks();
  1179 
  1180                 /* only change fade_volume_reset if we're not fading. */
  1181                 if (mix_channel[which].fading == MIX_NO_FADING) {
  1182                     mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1183                 }
  1184                 ++status;
  1185             }
  1186             Mix_UnlockAudio();
  1187         }
  1188     }
  1189     return(status);
  1190 }
  1191 
  1192 /* Halt playing of a particular group of channels */
  1193 int Mix_FadeOutGroup(int tag, int ms)
  1194 {
  1195     int i;
  1196     int status = 0;
  1197     for (i=0; i<num_channels; ++i) {
  1198         if(mix_channel[i].tag == tag) {
  1199             status += Mix_FadeOutChannel(i,ms);
  1200         }
  1201     }
  1202     return(status);
  1203 }
  1204 
  1205 Mix_Fading Mix_FadingChannel(int which)
  1206 {
  1207     if (which < 0 || which >= num_channels) {
  1208         return MIX_NO_FADING;
  1209     }
  1210     return mix_channel[which].fading;
  1211 }
  1212 
  1213 /* Check the status of a specific channel.
  1214    If the specified mix_channel is -1, check all mix channels.
  1215 */
  1216 int Mix_Playing(int which)
  1217 {
  1218     int status;
  1219 
  1220     status = 0;
  1221     if (which == -1) {
  1222         int i;
  1223 
  1224         for (i=0; i<num_channels; ++i) {
  1225             if ((mix_channel[i].playing > 0) ||
  1226                 mix_channel[i].looping)
  1227             {
  1228                 ++status;
  1229             }
  1230         }
  1231     } else if (which < num_channels) {
  1232         if ((mix_channel[which].playing > 0) ||
  1233              mix_channel[which].looping)
  1234         {
  1235             ++status;
  1236         }
  1237     }
  1238     return(status);
  1239 }
  1240 
  1241 /* rcg06072001 Get the chunk associated with a channel. */
  1242 Mix_Chunk *Mix_GetChunk(int channel)
  1243 {
  1244     Mix_Chunk *retval = NULL;
  1245 
  1246     if ((channel >= 0) && (channel < num_channels)) {
  1247         retval = mix_channel[channel].chunk;
  1248     }
  1249 
  1250     return(retval);
  1251 }
  1252 
  1253 /* Close the mixer, halting all playing audio */
  1254 void Mix_CloseAudio(void)
  1255 {
  1256     int i;
  1257 
  1258     if (audio_opened) {
  1259         if (audio_opened == 1) {
  1260             for (i = 0; i < num_channels; i++) {
  1261                 Mix_UnregisterAllEffects(i);
  1262             }
  1263             Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
  1264             close_music();
  1265             Mix_SetMusicCMD(NULL);
  1266             Mix_HaltChannel(-1);
  1267             _Mix_DeinitEffects();
  1268             SDL_CloseAudioDevice(audio_device);
  1269             audio_device = 0;
  1270             SDL_free(mix_channel);
  1271             mix_channel = NULL;
  1272 
  1273             /* rcg06042009 report available decoders at runtime. */
  1274             SDL_free((void *)chunk_decoders);
  1275             chunk_decoders = NULL;
  1276             num_decoders = 0;
  1277         }
  1278         --audio_opened;
  1279     }
  1280 }
  1281 
  1282 /* Pause a particular channel (or all) */
  1283 void Mix_Pause(int which)
  1284 {
  1285     Uint32 sdl_ticks = SDL_GetTicks();
  1286     if (which == -1) {
  1287         int i;
  1288 
  1289         for (i=0; i<num_channels; ++i) {
  1290             if (mix_channel[i].playing > 0) {
  1291                 mix_channel[i].paused = sdl_ticks;
  1292             }
  1293         }
  1294     } else if (which < num_channels) {
  1295         if (mix_channel[which].playing > 0) {
  1296             mix_channel[which].paused = sdl_ticks;
  1297         }
  1298     }
  1299 }
  1300 
  1301 /* Resume a paused channel */
  1302 void Mix_Resume(int which)
  1303 {
  1304     Uint32 sdl_ticks = SDL_GetTicks();
  1305 
  1306     Mix_LockAudio();
  1307     if (which == -1) {
  1308         int i;
  1309 
  1310         for (i=0; i<num_channels; ++i) {
  1311             if (mix_channel[i].playing > 0) {
  1312                 if(mix_channel[i].expire > 0)
  1313                     mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
  1314                 mix_channel[i].paused = 0;
  1315             }
  1316         }
  1317     } else if (which < num_channels) {
  1318         if (mix_channel[which].playing > 0) {
  1319             if(mix_channel[which].expire > 0)
  1320                 mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
  1321             mix_channel[which].paused = 0;
  1322         }
  1323     }
  1324     Mix_UnlockAudio();
  1325 }
  1326 
  1327 int Mix_Paused(int which)
  1328 {
  1329     if (which < 0) {
  1330         int status = 0;
  1331         int i;
  1332         for(i=0; i < num_channels; ++i) {
  1333             if (mix_channel[i].paused) {
  1334                 ++ status;
  1335             }
  1336         }
  1337         return(status);
  1338     } else if (which < num_channels) {
  1339         return(mix_channel[which].paused != 0);
  1340     } else {
  1341         return(0);
  1342     }
  1343 }
  1344 
  1345 /* Change the group of a channel */
  1346 int Mix_GroupChannel(int which, int tag)
  1347 {
  1348     if (which < 0 || which > num_channels)
  1349         return(0);
  1350 
  1351     Mix_LockAudio();
  1352     mix_channel[which].tag = tag;
  1353     Mix_UnlockAudio();
  1354     return(1);
  1355 }
  1356 
  1357 /* Assign several consecutive channels to a group */
  1358 int Mix_GroupChannels(int from, int to, int tag)
  1359 {
  1360     int status = 0;
  1361     for(; from <= to; ++ from) {
  1362         status += Mix_GroupChannel(from, tag);
  1363     }
  1364     return(status);
  1365 }
  1366 
  1367 /* Finds the first available channel in a group of channels */
  1368 int Mix_GroupAvailable(int tag)
  1369 {
  1370     int i;
  1371     for(i=0; i < num_channels; i ++) {
  1372         if (((tag == -1) || (tag == mix_channel[i].tag)) &&
  1373                             (mix_channel[i].playing <= 0))
  1374             return i;
  1375     }
  1376     return(-1);
  1377 }
  1378 
  1379 int Mix_GroupCount(int tag)
  1380 {
  1381     int count = 0;
  1382     int i;
  1383     for(i=0; i < num_channels; i ++) {
  1384         if (mix_channel[i].tag==tag || tag==-1)
  1385             ++ count;
  1386     }
  1387     return(count);
  1388 }
  1389 
  1390 /* Finds the "oldest" sample playing in a group of channels */
  1391 int Mix_GroupOldest(int tag)
  1392 {
  1393     int chan = -1;
  1394     Uint32 mintime = SDL_GetTicks();
  1395     int i;
  1396     for(i=0; i < num_channels; i ++) {
  1397         if ((mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1398              && mix_channel[i].start_time <= mintime) {
  1399             mintime = mix_channel[i].start_time;
  1400             chan = i;
  1401         }
  1402     }
  1403     return(chan);
  1404 }
  1405 
  1406 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
  1407 int Mix_GroupNewer(int tag)
  1408 {
  1409     int chan = -1;
  1410     Uint32 maxtime = 0;
  1411     int i;
  1412     for(i=0; i < num_channels; i ++) {
  1413         if ((mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1414              && mix_channel[i].start_time >= maxtime) {
  1415             maxtime = mix_channel[i].start_time;
  1416             chan = i;
  1417         }
  1418     }
  1419     return(chan);
  1420 }
  1421 
  1422 
  1423 
  1424 /*
  1425  * rcg06122001 The special effects exportable API.
  1426  *  Please see effect_*.c for internally-implemented effects, such
  1427  *  as Mix_SetPanning().
  1428  */
  1429 
  1430 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1431 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
  1432                 Mix_EffectDone_t d, void *arg)
  1433 {
  1434     effect_info *new_e;
  1435 
  1436     if (!e) {
  1437         Mix_SetError("Internal error");
  1438         return(0);
  1439     }
  1440 
  1441     if (f == NULL) {
  1442         Mix_SetError("NULL effect callback");
  1443         return(0);
  1444     }
  1445 
  1446     new_e = SDL_malloc(sizeof (effect_info));
  1447     if (new_e == NULL) {
  1448         Mix_SetError("Out of memory");
  1449         return(0);
  1450     }
  1451 
  1452     new_e->callback = f;
  1453     new_e->done_callback = d;
  1454     new_e->udata = arg;
  1455     new_e->next = NULL;
  1456 
  1457     /* add new effect to end of linked list... */
  1458     if (*e == NULL) {
  1459         *e = new_e;
  1460     } else {
  1461         effect_info *cur = *e;
  1462         while (1) {
  1463             if (cur->next == NULL) {
  1464                 cur->next = new_e;
  1465                 break;
  1466             }
  1467             cur = cur->next;
  1468         }
  1469     }
  1470 
  1471     return(1);
  1472 }
  1473 
  1474 
  1475 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1476 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
  1477 {
  1478     effect_info *cur;
  1479     effect_info *prev = NULL;
  1480     effect_info *next = NULL;
  1481 
  1482     if (!e) {
  1483         Mix_SetError("Internal error");
  1484         return(0);
  1485     }
  1486 
  1487     for (cur = *e; cur != NULL; cur = cur->next) {
  1488         if (cur->callback == f) {
  1489             next = cur->next;
  1490             if (cur->done_callback != NULL) {
  1491                 cur->done_callback(channel, cur->udata);
  1492             }
  1493             SDL_free(cur);
  1494 
  1495             if (prev == NULL) {   /* removing first item of list? */
  1496                 *e = next;
  1497             } else {
  1498                 prev->next = next;
  1499             }
  1500             return(1);
  1501         }
  1502         prev = cur;
  1503     }
  1504 
  1505     Mix_SetError("No such effect registered");
  1506     return(0);
  1507 }
  1508 
  1509 
  1510 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1511 static int _Mix_remove_all_effects(int channel, effect_info **e)
  1512 {
  1513     effect_info *cur;
  1514     effect_info *next;
  1515 
  1516     if (!e) {
  1517         Mix_SetError("Internal error");
  1518         return(0);
  1519     }
  1520 
  1521     for (cur = *e; cur != NULL; cur = next) {
  1522         next = cur->next;
  1523         if (cur->done_callback != NULL) {
  1524             cur->done_callback(channel, cur->udata);
  1525         }
  1526         SDL_free(cur);
  1527     }
  1528     *e = NULL;
  1529 
  1530     return(1);
  1531 }
  1532 
  1533 
  1534 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1535 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
  1536             Mix_EffectDone_t d, void *arg)
  1537 {
  1538     effect_info **e = NULL;
  1539 
  1540     if (channel == MIX_CHANNEL_POST) {
  1541         e = &posteffects;
  1542     } else {
  1543         if ((channel < 0) || (channel >= num_channels)) {
  1544             Mix_SetError("Invalid channel number");
  1545             return(0);
  1546         }
  1547         e = &mix_channel[channel].effects;
  1548     }
  1549 
  1550     return _Mix_register_effect(e, f, d, arg);
  1551 }
  1552 
  1553 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
  1554             Mix_EffectDone_t d, void *arg)
  1555 {
  1556     int retval;
  1557     Mix_LockAudio();
  1558     retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
  1559     Mix_UnlockAudio();
  1560     return retval;
  1561 }
  1562 
  1563 
  1564 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1565 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
  1566 {
  1567     effect_info **e = NULL;
  1568 
  1569     if (channel == MIX_CHANNEL_POST) {
  1570         e = &posteffects;
  1571     } else {
  1572         if ((channel < 0) || (channel >= num_channels)) {
  1573             Mix_SetError("Invalid channel number");
  1574             return(0);
  1575         }
  1576         e = &mix_channel[channel].effects;
  1577     }
  1578 
  1579     return _Mix_remove_effect(channel, e, f);
  1580 }
  1581 
  1582 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
  1583 {
  1584     int retval;
  1585     Mix_LockAudio();
  1586     retval = _Mix_UnregisterEffect_locked(channel, f);
  1587     Mix_UnlockAudio();
  1588     return(retval);
  1589 }
  1590 
  1591 /* MAKE SURE you hold the audio lock (Mix_LockAudio()) before calling this! */
  1592 int _Mix_UnregisterAllEffects_locked(int channel)
  1593 {
  1594     effect_info **e = NULL;
  1595 
  1596     if (channel == MIX_CHANNEL_POST) {
  1597         e = &posteffects;
  1598     } else {
  1599         if ((channel < 0) || (channel >= num_channels)) {
  1600             Mix_SetError("Invalid channel number");
  1601             return(0);
  1602         }
  1603         e = &mix_channel[channel].effects;
  1604     }
  1605 
  1606     return _Mix_remove_all_effects(channel, e);
  1607 }
  1608 
  1609 int Mix_UnregisterAllEffects(int channel)
  1610 {
  1611     int retval;
  1612     Mix_LockAudio();
  1613     retval = _Mix_UnregisterAllEffects_locked(channel);
  1614     Mix_UnlockAudio();
  1615     return(retval);
  1616 }
  1617 
  1618 void Mix_LockAudio(void)
  1619 {
  1620     SDL_LockAudioDevice(audio_device);
  1621 }
  1622 
  1623 void Mix_UnlockAudio(void)
  1624 {
  1625     SDL_UnlockAudioDevice(audio_device);
  1626 }
  1627 
  1628 /* end of mixer.c ... */
  1629 
  1630 /* vi: set ts=4 sw=4 expandtab: */