mixer.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 14 Oct 2017 01:49:37 -0700
changeset 766 1e215d1f9492
parent 765 fca02fccc6ab
child 771 fa081ec2940e
permissions -rw-r--r--
The soundfont API functions are public and should always be available.

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