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