mixer.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 18 Jun 2013 00:44:41 -0700
changeset 644 030181ff9f59
parent 639 f8901a7ff3f1
child 648 bd8389c6dd20
permissions -rw-r--r--
Fixed bugs 1914, 1915 - sizeof(const char**) is suspicious

Nitz

In function:
static void add_music_decoder(const char *decoder)
{
void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
}

Passing argument sizeof(char const **) to function SDL_realloc is suspicious.

Logically it should be sizeof(char const *) instead of sizeof (char const **)

In this particular case sizeof(char const **) happens to be equal to sizeof(char const *), but this is not a portable assumption.
It reduces the understanding of the user.

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