mixer.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Jan 2016 10:46:07 -0800
changeset 711 f40c5ac95b12
parent 710 1aca2b6d570f
child 718 fb0562cc1559
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2016 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_mutex.h"
    29 #include "SDL_endian.h"
    30 #include "SDL_timer.h"
    31 
    32 #include "SDL_mixer.h"
    33 #include "load_aiff.h"
    34 #include "load_voc.h"
    35 #include "load_mp3.h"
    36 #include "load_ogg.h"
    37 #include "load_flac.h"
    38 #include "dynamic_flac.h"
    39 #include "dynamic_fluidsynth.h"
    40 #include "dynamic_modplug.h"
    41 #include "dynamic_mod.h"
    42 #include "dynamic_mp3.h"
    43 #include "dynamic_ogg.h"
    44 
    45 #define __MIX_INTERNAL_EFFECT__
    46 #include "effects_internal.h"
    47 
    48 /* Magic numbers for various audio file formats */
    49 #define RIFF        0x46464952      /* "RIFF" */
    50 #define WAVE        0x45564157      /* "WAVE" */
    51 #define FORM        0x4d524f46      /* "FORM" */
    52 #define OGGS        0x5367674f      /* "OggS" */
    53 #define CREA        0x61657243      /* "Crea" */
    54 #define FLAC        0x43614C66      /* "fLaC" */
    55 
    56 static int audio_opened = 0;
    57 static SDL_AudioSpec mixer;
    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 #ifdef MP3_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 #ifdef MP3_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 SDL_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_MixAudio(stream+index,mix_input,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_MixAudio(stream+index, mix_input, 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 
   430 /* Open the mixer with a certain desired audio format */
   431 int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
   432 {
   433     int i;
   434     SDL_AudioSpec desired;
   435 
   436     /* If the mixer is already opened, increment open count */
   437     if ( audio_opened ) {
   438         if ( format == mixer.format && nchannels == mixer.channels ) {
   439             ++audio_opened;
   440             return(0);
   441         }
   442         while ( audio_opened ) {
   443             Mix_CloseAudio();
   444         }
   445     }
   446 
   447     /* Set the desired format and frequency */
   448     desired.freq = frequency;
   449     desired.format = format;
   450     desired.channels = nchannels;
   451     desired.samples = chunksize;
   452     desired.callback = mix_channels;
   453     desired.userdata = NULL;
   454 
   455     /* Accept nearly any audio format */
   456     if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
   457         return(-1);
   458     }
   459 #if 0
   460     PrintFormat("Audio device", &mixer);
   461 #endif
   462 
   463     /* Initialize the music players */
   464     if ( open_music(&mixer) < 0 ) {
   465         SDL_CloseAudio();
   466         return(-1);
   467     }
   468 
   469     num_channels = MIX_CHANNELS;
   470     mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
   471 
   472     /* Clear out the audio channels */
   473     for ( i=0; i<num_channels; ++i ) {
   474         mix_channel[i].chunk = NULL;
   475         mix_channel[i].playing = 0;
   476         mix_channel[i].looping = 0;
   477         mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   478         mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   479         mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   480         mix_channel[i].fading = MIX_NO_FADING;
   481         mix_channel[i].tag = -1;
   482         mix_channel[i].expire = 0;
   483         mix_channel[i].effects = NULL;
   484         mix_channel[i].paused = 0;
   485     }
   486     Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   487 
   488     _Mix_InitEffects();
   489 
   490     /* This list is (currently) decided at build time. */
   491     add_chunk_decoder("WAVE");
   492     add_chunk_decoder("AIFF");
   493     add_chunk_decoder("VOC");
   494 #ifdef OGG_MUSIC
   495     add_chunk_decoder("OGG");
   496 #endif
   497 #ifdef FLAC_MUSIC
   498     add_chunk_decoder("FLAC");
   499 #endif
   500 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
   501     add_chunk_decoder("MP3");
   502 #endif
   503 
   504     audio_opened = 1;
   505     SDL_PauseAudio(0);
   506     return(0);
   507 }
   508 
   509 /* Dynamically change the number of channels managed by the mixer.
   510    If decreasing the number of channels, the upper channels are
   511    stopped.
   512  */
   513 int Mix_AllocateChannels(int numchans)
   514 {
   515     if ( numchans<0 || numchans==num_channels )
   516         return(num_channels);
   517 
   518     if ( numchans < num_channels ) {
   519         /* Stop the affected channels */
   520         int i;
   521         for(i=numchans; i < num_channels; i++) {
   522             Mix_UnregisterAllEffects(i);
   523             Mix_HaltChannel(i);
   524         }
   525     }
   526     SDL_LockAudio();
   527     mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
   528     if ( numchans > num_channels ) {
   529         /* Initialize the new channels */
   530         int i;
   531         for(i=num_channels; i < numchans; i++) {
   532             mix_channel[i].chunk = NULL;
   533             mix_channel[i].playing = 0;
   534             mix_channel[i].looping = 0;
   535             mix_channel[i].volume = SDL_MIX_MAXVOLUME;
   536             mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
   537             mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
   538             mix_channel[i].fading = MIX_NO_FADING;
   539             mix_channel[i].tag = -1;
   540             mix_channel[i].expire = 0;
   541             mix_channel[i].effects = NULL;
   542             mix_channel[i].paused = 0;
   543         }
   544     }
   545     num_channels = numchans;
   546     SDL_UnlockAudio();
   547     return(num_channels);
   548 }
   549 
   550 /* Return the actual mixer parameters */
   551 int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
   552 {
   553     if ( audio_opened ) {
   554         if ( frequency ) {
   555             *frequency = mixer.freq;
   556         }
   557         if ( format ) {
   558             *format = mixer.format;
   559         }
   560         if ( channels ) {
   561             *channels = mixer.channels;
   562         }
   563     }
   564     return(audio_opened);
   565 }
   566 
   567 static int detect_mp3(Uint8 *magic)
   568 {
   569     if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
   570         return 1;
   571     }
   572 
   573     /* Detection code lifted from SMPEG */
   574     if(((magic[0] & 0xff) != 0xff) || // No sync bits
   575        ((magic[1] & 0xf0) != 0xf0) || //
   576        ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
   577        ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
   578        ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
   579        ((magic[1] & 0x06) == 0x00)) { // Layer is 4
   580         return(0);
   581     }
   582     return 1;
   583 }
   584 
   585 /* Load a wave file */
   586 Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
   587 {
   588     Uint32 magic;
   589     Mix_Chunk *chunk;
   590     SDL_AudioSpec wavespec, *loaded;
   591     SDL_AudioCVT wavecvt;
   592     int samplesize;
   593 
   594     /* rcg06012001 Make sure src is valid */
   595     if ( ! src ) {
   596         SDL_SetError("Mix_LoadWAV_RW with NULL src");
   597         return(NULL);
   598     }
   599 
   600     /* Make sure audio has been opened */
   601     if ( ! audio_opened ) {
   602         SDL_SetError("Audio device hasn't been opened");
   603         if ( freesrc ) {
   604             SDL_RWclose(src);
   605         }
   606         return(NULL);
   607     }
   608 
   609     /* Allocate the chunk memory */
   610     chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   611     if ( chunk == NULL ) {
   612         SDL_SetError("Out of memory");
   613         if ( freesrc ) {
   614             SDL_RWclose(src);
   615         }
   616         return(NULL);
   617     }
   618 
   619     /* Find out what kind of audio file this is */
   620     magic = SDL_ReadLE32(src);
   621     /* Seek backwards for compatibility with older loaders */
   622     SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
   623 
   624     switch (magic) {
   625         case WAVE:
   626         case RIFF:
   627             loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
   628                     (Uint8 **)&chunk->abuf, &chunk->alen);
   629             break;
   630         case FORM:
   631             loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
   632                     (Uint8 **)&chunk->abuf, &chunk->alen);
   633             break;
   634 #ifdef OGG_MUSIC
   635         case OGGS:
   636             loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
   637                     (Uint8 **)&chunk->abuf, &chunk->alen);
   638             break;
   639 #endif
   640 #ifdef FLAC_MUSIC
   641         case FLAC:
   642             loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
   643                     (Uint8 **)&chunk->abuf, &chunk->alen);
   644             break;
   645 #endif
   646         case CREA:
   647             loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
   648                     (Uint8 **)&chunk->abuf, &chunk->alen);
   649             break;
   650         default:
   651 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
   652 			if (detect_mp3((Uint8*)&magic))
   653 			{
   654 				/* note: send a copy of the mixer spec */
   655 				wavespec = mixer;
   656 				loaded = Mix_LoadMP3_RW(src, freesrc, &wavespec,
   657 						(Uint8 **)&chunk->abuf, &chunk->alen);
   658 				break;
   659 			}
   660 #endif
   661             SDL_SetError("Unrecognized sound file type");
   662             if ( freesrc ) {
   663                 SDL_RWclose(src);
   664             }
   665             loaded = NULL;
   666             break;
   667     }
   668     if ( !loaded ) {
   669         /* The individual loaders have closed src if needed */
   670         SDL_free(chunk);
   671         return(NULL);
   672     }
   673 
   674 #if 0
   675     PrintFormat("Audio device", &mixer);
   676     PrintFormat("-- Wave file", &wavespec);
   677 #endif
   678 
   679     /* Build the audio converter and create conversion buffers */
   680     if ( wavespec.format != mixer.format ||
   681          wavespec.channels != mixer.channels ||
   682          wavespec.freq != mixer.freq ) {
   683         if ( SDL_BuildAudioCVT(&wavecvt,
   684                 wavespec.format, wavespec.channels, wavespec.freq,
   685                 mixer.format, mixer.channels, mixer.freq) < 0 ) {
   686             SDL_free(chunk->abuf);
   687             SDL_free(chunk);
   688             return(NULL);
   689         }
   690         samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
   691         wavecvt.len = chunk->alen & ~(samplesize-1);
   692         wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
   693         if ( wavecvt.buf == NULL ) {
   694             SDL_SetError("Out of memory");
   695             SDL_free(chunk->abuf);
   696             SDL_free(chunk);
   697             return(NULL);
   698         }
   699         SDL_memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
   700         SDL_free(chunk->abuf);
   701 
   702         /* Run the audio converter */
   703         if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
   704             SDL_free(wavecvt.buf);
   705             SDL_free(chunk);
   706             return(NULL);
   707         }
   708 
   709         chunk->abuf = wavecvt.buf;
   710         chunk->alen = wavecvt.len_cvt;
   711     }
   712 
   713     chunk->allocated = 1;
   714     chunk->volume = MIX_MAX_VOLUME;
   715 
   716     return(chunk);
   717 }
   718 
   719 /* Load a wave file of the mixer format from a memory buffer */
   720 Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
   721 {
   722     Mix_Chunk *chunk;
   723     Uint8 magic[4];
   724 
   725     /* Make sure audio has been opened */
   726     if ( ! audio_opened ) {
   727         SDL_SetError("Audio device hasn't been opened");
   728         return(NULL);
   729     }
   730 
   731     /* Allocate the chunk memory */
   732     chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
   733     if ( chunk == NULL ) {
   734         SDL_SetError("Out of memory");
   735         return(NULL);
   736     }
   737 
   738     /* Essentially just skip to the audio data (no error checking - fast) */
   739     chunk->allocated = 0;
   740     mem += 12; /* WAV header */
   741     do {
   742         SDL_memcpy(magic, mem, 4);
   743         mem += 4;
   744         chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
   745         mem += 4;
   746         chunk->abuf = mem;
   747         mem += chunk->alen;
   748     } while ( memcmp(magic, "data", 4) != 0 );
   749     chunk->volume = MIX_MAX_VOLUME;
   750 
   751     return(chunk);
   752 }
   753 
   754 /* Load raw audio data of the mixer format from a memory buffer */
   755 Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
   756 {
   757     Mix_Chunk *chunk;
   758 
   759     /* Make sure audio has been opened */
   760     if ( ! audio_opened ) {
   761         SDL_SetError("Audio device hasn't been opened");
   762         return(NULL);
   763     }
   764 
   765     /* Allocate the chunk memory */
   766     chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
   767     if ( chunk == NULL ) {
   768         SDL_SetError("Out of memory");
   769         return(NULL);
   770     }
   771 
   772     /* Essentially just point at the audio data (no error checking - fast) */
   773     chunk->allocated = 0;
   774     chunk->alen = len;
   775     chunk->abuf = mem;
   776     chunk->volume = MIX_MAX_VOLUME;
   777 
   778     return(chunk);
   779 }
   780 
   781 /* Free an audio chunk previously loaded */
   782 void Mix_FreeChunk(Mix_Chunk *chunk)
   783 {
   784     int i;
   785 
   786     /* Caution -- if the chunk is playing, the mixer will crash */
   787     if ( chunk ) {
   788         /* Guarantee that this chunk isn't playing */
   789         SDL_LockAudio();
   790         if ( mix_channel ) {
   791             for ( i=0; i<num_channels; ++i ) {
   792                 if ( chunk == mix_channel[i].chunk ) {
   793                     mix_channel[i].playing = 0;
   794                     mix_channel[i].looping = 0;
   795                 }
   796             }
   797         }
   798         SDL_UnlockAudio();
   799         /* Actually free the chunk */
   800         if ( chunk->allocated ) {
   801             SDL_free(chunk->abuf);
   802         }
   803         SDL_free(chunk);
   804     }
   805 }
   806 
   807 /* Set a function that is called after all mixing is performed.
   808    This can be used to provide real-time visual display of the audio stream
   809    or add a custom mixer filter for the stream data.
   810 */
   811 void Mix_SetPostMix(void (*mix_func)
   812                     (void *udata, Uint8 *stream, int len), void *arg)
   813 {
   814     SDL_LockAudio();
   815     mix_postmix_data = arg;
   816     mix_postmix = mix_func;
   817     SDL_UnlockAudio();
   818 }
   819 
   820 /* Add your own music player or mixer function.
   821    If 'mix_func' is NULL, the default music player is re-enabled.
   822  */
   823 void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
   824                                                                 void *arg)
   825 {
   826     SDL_LockAudio();
   827     if ( mix_func != NULL ) {
   828         music_data = arg;
   829         mix_music = mix_func;
   830     } else {
   831         music_data = NULL;
   832         mix_music = music_mixer;
   833     }
   834     SDL_UnlockAudio();
   835 }
   836 
   837 void *Mix_GetMusicHookData(void)
   838 {
   839     return(music_data);
   840 }
   841 
   842 void Mix_ChannelFinished(void (*channel_finished)(int channel))
   843 {
   844     SDL_LockAudio();
   845     channel_done_callback = channel_finished;
   846     SDL_UnlockAudio();
   847 }
   848 
   849 
   850 /* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
   851    them dynamically to the next sample if requested with a -1 value below.
   852    Returns the number of reserved channels.
   853  */
   854 int Mix_ReserveChannels(int num)
   855 {
   856     if (num > num_channels)
   857         num = num_channels;
   858     reserved_channels = num;
   859     return num;
   860 }
   861 
   862 static int checkchunkintegral(Mix_Chunk *chunk)
   863 {
   864     int frame_width = 1;
   865 
   866     if ((mixer.format & 0xFF) == 16) frame_width = 2;
   867     frame_width *= mixer.channels;
   868     while (chunk->alen % frame_width) chunk->alen--;
   869     return chunk->alen;
   870 }
   871 
   872 /* Play an audio chunk on a specific channel.
   873    If the specified channel is -1, play on the first free channel.
   874    'ticks' is the number of milliseconds at most to play the sample, or -1
   875    if there is no limit.
   876    Returns which channel was used to play the sound.
   877 */
   878 int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   879 {
   880     int i;
   881 
   882     /* Don't play null pointers :-) */
   883     if ( chunk == NULL ) {
   884         Mix_SetError("Tried to play a NULL chunk");
   885         return(-1);
   886     }
   887     if ( !checkchunkintegral(chunk)) {
   888         Mix_SetError("Tried to play a chunk with a bad frame");
   889         return(-1);
   890     }
   891 
   892     /* Lock the mixer while modifying the playing channels */
   893     SDL_LockAudio();
   894     {
   895         /* If which is -1, play on the first free channel */
   896         if ( which == -1 ) {
   897             for ( i=reserved_channels; i<num_channels; ++i ) {
   898                 if ( mix_channel[i].playing <= 0 )
   899                     break;
   900             }
   901             if ( i == num_channels ) {
   902                 Mix_SetError("No free channels available");
   903                 which = -1;
   904             } else {
   905                 which = i;
   906             }
   907         }
   908 
   909         /* Queue up the audio data for this channel */
   910         if ( which >= 0 && which < num_channels ) {
   911             Uint32 sdl_ticks = SDL_GetTicks();
   912             if (Mix_Playing(which))
   913                 _Mix_channel_done_playing(which);
   914             mix_channel[which].samples = chunk->abuf;
   915             mix_channel[which].playing = chunk->alen;
   916             mix_channel[which].looping = loops;
   917             mix_channel[which].chunk = chunk;
   918             mix_channel[which].paused = 0;
   919             mix_channel[which].fading = MIX_NO_FADING;
   920             mix_channel[which].start_time = sdl_ticks;
   921             mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
   922         }
   923     }
   924     SDL_UnlockAudio();
   925 
   926     /* Return the channel on which the sound is being played */
   927     return(which);
   928 }
   929 
   930 /* Change the expiration delay for a channel */
   931 int Mix_ExpireChannel(int which, int ticks)
   932 {
   933     int status = 0;
   934 
   935     if ( which == -1 ) {
   936         int i;
   937         for ( i=0; i < num_channels; ++ i ) {
   938             status += Mix_ExpireChannel(i, ticks);
   939         }
   940     } else if ( which < num_channels ) {
   941         SDL_LockAudio();
   942         mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
   943         SDL_UnlockAudio();
   944         ++ status;
   945     }
   946     return(status);
   947 }
   948 
   949 /* Fade in a sound on a channel, over ms milliseconds */
   950 int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
   951 {
   952     int i;
   953 
   954     /* Don't play null pointers :-) */
   955     if ( chunk == NULL ) {
   956         return(-1);
   957     }
   958     if ( !checkchunkintegral(chunk)) {
   959         Mix_SetError("Tried to play a chunk with a bad frame");
   960         return(-1);
   961     }
   962 
   963     /* Lock the mixer while modifying the playing channels */
   964     SDL_LockAudio();
   965     {
   966         /* If which is -1, play on the first free channel */
   967         if ( which == -1 ) {
   968             for ( i=reserved_channels; i<num_channels; ++i ) {
   969                 if ( mix_channel[i].playing <= 0 )
   970                     break;
   971             }
   972             if ( i == num_channels ) {
   973                 which = -1;
   974             } else {
   975                 which = i;
   976             }
   977         }
   978 
   979         /* Queue up the audio data for this channel */
   980         if ( which >= 0 && which < num_channels ) {
   981             Uint32 sdl_ticks = SDL_GetTicks();
   982             if (Mix_Playing(which))
   983                 _Mix_channel_done_playing(which);
   984             mix_channel[which].samples = chunk->abuf;
   985             mix_channel[which].playing = chunk->alen;
   986             mix_channel[which].looping = loops;
   987             mix_channel[which].chunk = chunk;
   988             mix_channel[which].paused = 0;
   989             mix_channel[which].fading = MIX_FADING_IN;
   990             mix_channel[which].fade_volume = mix_channel[which].volume;
   991             mix_channel[which].fade_volume_reset = mix_channel[which].volume;
   992             mix_channel[which].volume = 0;
   993             mix_channel[which].fade_length = (Uint32)ms;
   994             mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
   995             mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
   996         }
   997     }
   998     SDL_UnlockAudio();
   999 
  1000     /* Return the channel on which the sound is being played */
  1001     return(which);
  1002 }
  1003 
  1004 /* Set volume of a particular channel */
  1005 int Mix_Volume(int which, int volume)
  1006 {
  1007     int i;
  1008     int prev_volume = 0;
  1009 
  1010     if ( which == -1 ) {
  1011         for ( i=0; i<num_channels; ++i ) {
  1012             prev_volume += Mix_Volume(i, volume);
  1013         }
  1014         prev_volume /= num_channels;
  1015     } else if ( which < num_channels ) {
  1016         prev_volume = mix_channel[which].volume;
  1017         if ( volume >= 0 ) {
  1018             if ( volume > SDL_MIX_MAXVOLUME ) {
  1019                 volume = SDL_MIX_MAXVOLUME;
  1020             }
  1021             mix_channel[which].volume = volume;
  1022         }
  1023     }
  1024     return(prev_volume);
  1025 }
  1026 /* Set volume of a particular chunk */
  1027 int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
  1028 {
  1029     int prev_volume;
  1030 
  1031     prev_volume = chunk->volume;
  1032     if ( volume >= 0 ) {
  1033         if ( volume > MIX_MAX_VOLUME ) {
  1034             volume = MIX_MAX_VOLUME;
  1035         }
  1036         chunk->volume = volume;
  1037     }
  1038     return(prev_volume);
  1039 }
  1040 
  1041 /* Halt playing of a particular channel */
  1042 int Mix_HaltChannel(int which)
  1043 {
  1044     int i;
  1045 
  1046     if ( which == -1 ) {
  1047         for ( i=0; i<num_channels; ++i ) {
  1048             Mix_HaltChannel(i);
  1049         }
  1050     } else if ( which < num_channels ) {
  1051         SDL_LockAudio();
  1052         if (mix_channel[which].playing) {
  1053             _Mix_channel_done_playing(which);
  1054             mix_channel[which].playing = 0;
  1055             mix_channel[which].looping = 0;
  1056         }
  1057         mix_channel[which].expire = 0;
  1058         if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
  1059             mix_channel[which].volume = mix_channel[which].fade_volume_reset;
  1060         mix_channel[which].fading = MIX_NO_FADING;
  1061         SDL_UnlockAudio();
  1062     }
  1063     return(0);
  1064 }
  1065 
  1066 /* Halt playing of a particular group of channels */
  1067 int Mix_HaltGroup(int tag)
  1068 {
  1069     int i;
  1070 
  1071     for ( i=0; i<num_channels; ++i ) {
  1072         if( mix_channel[i].tag == tag ) {
  1073             Mix_HaltChannel(i);
  1074         }
  1075     }
  1076     return(0);
  1077 }
  1078 
  1079 /* Fade out a channel and then stop it automatically */
  1080 int Mix_FadeOutChannel(int which, int ms)
  1081 {
  1082     int status;
  1083 
  1084     status = 0;
  1085     if ( audio_opened ) {
  1086         if ( which == -1 ) {
  1087             int i;
  1088 
  1089             for ( i=0; i<num_channels; ++i ) {
  1090                 status += Mix_FadeOutChannel(i, ms);
  1091             }
  1092         } else if ( which < num_channels ) {
  1093             SDL_LockAudio();
  1094             if ( mix_channel[which].playing &&
  1095                 (mix_channel[which].volume > 0) &&
  1096                 (mix_channel[which].fading != MIX_FADING_OUT) ) {
  1097                 mix_channel[which].fade_volume = mix_channel[which].volume;
  1098                 mix_channel[which].fading = MIX_FADING_OUT;
  1099                 mix_channel[which].fade_length = (Uint32)ms;
  1100                 mix_channel[which].ticks_fade = SDL_GetTicks();
  1101 
  1102                 /* only change fade_volume_reset if we're not fading. */
  1103                 if (mix_channel[which].fading == MIX_NO_FADING) {
  1104                     mix_channel[which].fade_volume_reset = mix_channel[which].volume;
  1105                 }
  1106                 ++status;
  1107             }
  1108             SDL_UnlockAudio();
  1109         }
  1110     }
  1111     return(status);
  1112 }
  1113 
  1114 /* Halt playing of a particular group of channels */
  1115 int Mix_FadeOutGroup(int tag, int ms)
  1116 {
  1117     int i;
  1118     int status = 0;
  1119     for ( i=0; i<num_channels; ++i ) {
  1120         if( mix_channel[i].tag == tag ) {
  1121             status += Mix_FadeOutChannel(i,ms);
  1122         }
  1123     }
  1124     return(status);
  1125 }
  1126 
  1127 Mix_Fading Mix_FadingChannel(int which)
  1128 {
  1129     if ( which < 0 || which >= num_channels ) {
  1130         return MIX_NO_FADING;
  1131     }
  1132     return mix_channel[which].fading;
  1133 }
  1134 
  1135 /* Check the status of a specific channel.
  1136    If the specified mix_channel is -1, check all mix channels.
  1137 */
  1138 int Mix_Playing(int which)
  1139 {
  1140     int status;
  1141 
  1142     status = 0;
  1143     if ( which == -1 ) {
  1144         int i;
  1145 
  1146         for ( i=0; i<num_channels; ++i ) {
  1147             if ((mix_channel[i].playing > 0) ||
  1148                 mix_channel[i].looping)
  1149             {
  1150                 ++status;
  1151             }
  1152         }
  1153     } else if ( which < num_channels ) {
  1154         if ( (mix_channel[which].playing > 0) ||
  1155              mix_channel[which].looping )
  1156         {
  1157             ++status;
  1158         }
  1159     }
  1160     return(status);
  1161 }
  1162 
  1163 /* rcg06072001 Get the chunk associated with a channel. */
  1164 Mix_Chunk *Mix_GetChunk(int channel)
  1165 {
  1166     Mix_Chunk *retval = NULL;
  1167 
  1168     if ((channel >= 0) && (channel < num_channels)) {
  1169         retval = mix_channel[channel].chunk;
  1170     }
  1171 
  1172     return(retval);
  1173 }
  1174 
  1175 /* Close the mixer, halting all playing audio */
  1176 void Mix_CloseAudio(void)
  1177 {
  1178     int i;
  1179 
  1180     if ( audio_opened ) {
  1181         if ( audio_opened == 1 ) {
  1182             for (i = 0; i < num_channels; i++) {
  1183                 Mix_UnregisterAllEffects(i);
  1184             }
  1185             Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
  1186             close_music();
  1187             Mix_HaltChannel(-1);
  1188             _Mix_DeinitEffects();
  1189             SDL_CloseAudio();
  1190             SDL_free(mix_channel);
  1191             mix_channel = NULL;
  1192 
  1193             /* rcg06042009 report available decoders at runtime. */
  1194             SDL_free((void *)chunk_decoders);
  1195             chunk_decoders = NULL;
  1196             num_decoders = 0;
  1197         }
  1198         --audio_opened;
  1199     }
  1200 }
  1201 
  1202 /* Pause a particular channel (or all) */
  1203 void Mix_Pause(int which)
  1204 {
  1205     Uint32 sdl_ticks = SDL_GetTicks();
  1206     if ( which == -1 ) {
  1207         int i;
  1208 
  1209         for ( i=0; i<num_channels; ++i ) {
  1210             if ( mix_channel[i].playing > 0 ) {
  1211                 mix_channel[i].paused = sdl_ticks;
  1212             }
  1213         }
  1214     } else if ( which < num_channels ) {
  1215         if ( mix_channel[which].playing > 0 ) {
  1216             mix_channel[which].paused = sdl_ticks;
  1217         }
  1218     }
  1219 }
  1220 
  1221 /* Resume a paused channel */
  1222 void Mix_Resume(int which)
  1223 {
  1224     Uint32 sdl_ticks = SDL_GetTicks();
  1225 
  1226     SDL_LockAudio();
  1227     if ( which == -1 ) {
  1228         int i;
  1229 
  1230         for ( i=0; i<num_channels; ++i ) {
  1231             if ( mix_channel[i].playing > 0 ) {
  1232                 if(mix_channel[i].expire > 0)
  1233                     mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
  1234                 mix_channel[i].paused = 0;
  1235             }
  1236         }
  1237     } else if ( which < num_channels ) {
  1238         if ( mix_channel[which].playing > 0 ) {
  1239             if(mix_channel[which].expire > 0)
  1240                 mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
  1241             mix_channel[which].paused = 0;
  1242         }
  1243     }
  1244     SDL_UnlockAudio();
  1245 }
  1246 
  1247 int Mix_Paused(int which)
  1248 {
  1249     if ( which < 0 ) {
  1250         int status = 0;
  1251         int i;
  1252         for( i=0; i < num_channels; ++i ) {
  1253             if ( mix_channel[i].paused ) {
  1254                 ++ status;
  1255             }
  1256         }
  1257         return(status);
  1258     } else if ( which < num_channels ) {
  1259         return(mix_channel[which].paused != 0);
  1260     } else {
  1261         return(0);
  1262     }
  1263 }
  1264 
  1265 /* Change the group of a channel */
  1266 int Mix_GroupChannel(int which, int tag)
  1267 {
  1268     if ( which < 0 || which > num_channels )
  1269         return(0);
  1270 
  1271     SDL_LockAudio();
  1272     mix_channel[which].tag = tag;
  1273     SDL_UnlockAudio();
  1274     return(1);
  1275 }
  1276 
  1277 /* Assign several consecutive channels to a group */
  1278 int Mix_GroupChannels(int from, int to, int tag)
  1279 {
  1280     int status = 0;
  1281     for( ; from <= to; ++ from ) {
  1282         status += Mix_GroupChannel(from, tag);
  1283     }
  1284     return(status);
  1285 }
  1286 
  1287 /* Finds the first available channel in a group of channels */
  1288 int Mix_GroupAvailable(int tag)
  1289 {
  1290     int i;
  1291     for( i=0; i < num_channels; i ++ ) {
  1292         if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
  1293                             (mix_channel[i].playing <= 0) )
  1294             return i;
  1295     }
  1296     return(-1);
  1297 }
  1298 
  1299 int Mix_GroupCount(int tag)
  1300 {
  1301     int count = 0;
  1302     int i;
  1303     for( i=0; i < num_channels; i ++ ) {
  1304         if ( mix_channel[i].tag==tag || tag==-1 )
  1305             ++ count;
  1306     }
  1307     return(count);
  1308 }
  1309 
  1310 /* Finds the "oldest" sample playing in a group of channels */
  1311 int Mix_GroupOldest(int tag)
  1312 {
  1313     int chan = -1;
  1314     Uint32 mintime = SDL_GetTicks();
  1315     int i;
  1316     for( i=0; i < num_channels; i ++ ) {
  1317         if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1318              && mix_channel[i].start_time <= mintime ) {
  1319             mintime = mix_channel[i].start_time;
  1320             chan = i;
  1321         }
  1322     }
  1323     return(chan);
  1324 }
  1325 
  1326 /* Finds the "most recent" (i.e. last) sample playing in a group of channels */
  1327 int Mix_GroupNewer(int tag)
  1328 {
  1329     int chan = -1;
  1330     Uint32 maxtime = 0;
  1331     int i;
  1332     for( i=0; i < num_channels; i ++ ) {
  1333         if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
  1334              && mix_channel[i].start_time >= maxtime ) {
  1335             maxtime = mix_channel[i].start_time;
  1336             chan = i;
  1337         }
  1338     }
  1339     return(chan);
  1340 }
  1341 
  1342 
  1343 
  1344 /*
  1345  * rcg06122001 The special effects exportable API.
  1346  *  Please see effect_*.c for internally-implemented effects, such
  1347  *  as Mix_SetPanning().
  1348  */
  1349 
  1350 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1351 static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
  1352                 Mix_EffectDone_t d, void *arg)
  1353 {
  1354     effect_info *new_e;
  1355 
  1356     if (!e) {
  1357         Mix_SetError("Internal error");
  1358         return(0);
  1359     }
  1360 
  1361     if (f == NULL) {
  1362         Mix_SetError("NULL effect callback");
  1363         return(0);
  1364     }
  1365 
  1366     new_e = SDL_malloc(sizeof (effect_info));
  1367     if (new_e == NULL) {
  1368         Mix_SetError("Out of memory");
  1369         return(0);
  1370     }
  1371 
  1372     new_e->callback = f;
  1373     new_e->done_callback = d;
  1374     new_e->udata = arg;
  1375     new_e->next = NULL;
  1376 
  1377     /* add new effect to end of linked list... */
  1378     if (*e == NULL) {
  1379         *e = new_e;
  1380     } else {
  1381         effect_info *cur = *e;
  1382         while (1) {
  1383             if (cur->next == NULL) {
  1384                 cur->next = new_e;
  1385                 break;
  1386             }
  1387             cur = cur->next;
  1388         }
  1389     }
  1390 
  1391     return(1);
  1392 }
  1393 
  1394 
  1395 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1396 static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
  1397 {
  1398     effect_info *cur;
  1399     effect_info *prev = NULL;
  1400     effect_info *next = NULL;
  1401 
  1402     if (!e) {
  1403         Mix_SetError("Internal error");
  1404         return(0);
  1405     }
  1406 
  1407     for (cur = *e; cur != NULL; cur = cur->next) {
  1408         if (cur->callback == f) {
  1409             next = cur->next;
  1410             if (cur->done_callback != NULL) {
  1411                 cur->done_callback(channel, cur->udata);
  1412             }
  1413             SDL_free(cur);
  1414 
  1415             if (prev == NULL) {   /* removing first item of list? */
  1416                 *e = next;
  1417             } else {
  1418                 prev->next = next;
  1419             }
  1420             return(1);
  1421         }
  1422         prev = cur;
  1423     }
  1424 
  1425     Mix_SetError("No such effect registered");
  1426     return(0);
  1427 }
  1428 
  1429 
  1430 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1431 static int _Mix_remove_all_effects(int channel, effect_info **e)
  1432 {
  1433     effect_info *cur;
  1434     effect_info *next;
  1435 
  1436     if (!e) {
  1437         Mix_SetError("Internal error");
  1438         return(0);
  1439     }
  1440 
  1441     for (cur = *e; cur != NULL; cur = next) {
  1442         next = cur->next;
  1443         if (cur->done_callback != NULL) {
  1444             cur->done_callback(channel, cur->udata);
  1445         }
  1446         SDL_free(cur);
  1447     }
  1448     *e = NULL;
  1449 
  1450     return(1);
  1451 }
  1452 
  1453 
  1454 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1455 int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
  1456             Mix_EffectDone_t d, void *arg)
  1457 {
  1458     effect_info **e = NULL;
  1459 
  1460     if (channel == MIX_CHANNEL_POST) {
  1461         e = &posteffects;
  1462     } else {
  1463         if ((channel < 0) || (channel >= num_channels)) {
  1464             Mix_SetError("Invalid channel number");
  1465             return(0);
  1466         }
  1467         e = &mix_channel[channel].effects;
  1468     }
  1469 
  1470     return _Mix_register_effect(e, f, d, arg);
  1471 }
  1472 
  1473 int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
  1474             Mix_EffectDone_t d, void *arg)
  1475 {
  1476     int retval;
  1477     SDL_LockAudio();
  1478     retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
  1479     SDL_UnlockAudio();
  1480     return retval;
  1481 }
  1482 
  1483 
  1484 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1485 int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
  1486 {
  1487     effect_info **e = NULL;
  1488 
  1489     if (channel == MIX_CHANNEL_POST) {
  1490         e = &posteffects;
  1491     } else {
  1492         if ((channel < 0) || (channel >= num_channels)) {
  1493             Mix_SetError("Invalid channel number");
  1494             return(0);
  1495         }
  1496         e = &mix_channel[channel].effects;
  1497     }
  1498 
  1499     return _Mix_remove_effect(channel, e, f);
  1500 }
  1501 
  1502 int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
  1503 {
  1504     int retval;
  1505     SDL_LockAudio();
  1506     retval = _Mix_UnregisterEffect_locked(channel, f);
  1507     SDL_UnlockAudio();
  1508     return(retval);
  1509 }
  1510 
  1511 /* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
  1512 int _Mix_UnregisterAllEffects_locked(int channel)
  1513 {
  1514     effect_info **e = NULL;
  1515 
  1516     if (channel == MIX_CHANNEL_POST) {
  1517         e = &posteffects;
  1518     } else {
  1519         if ((channel < 0) || (channel >= num_channels)) {
  1520             Mix_SetError("Invalid channel number");
  1521             return(0);
  1522         }
  1523         e = &mix_channel[channel].effects;
  1524     }
  1525 
  1526     return _Mix_remove_all_effects(channel, e);
  1527 }
  1528 
  1529 int Mix_UnregisterAllEffects(int channel)
  1530 {
  1531     int retval;
  1532     SDL_LockAudio();
  1533     retval = _Mix_UnregisterAllEffects_locked(channel);
  1534     SDL_UnlockAudio();
  1535     return(retval);
  1536 }
  1537 
  1538 /* end of mixer.c ... */
  1539