mixer.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 24 May 2017 16:41:47 -0400
changeset 727 119df1a05eb7
parent 725 bdf7b8d20566
child 738 e6fa426a79dd
permissions -rw-r--r--
Initialize the SDL audio subsystem if necessary.

SDL_OpenAudio() did this for us (legacy 1.2 behavior), but
SDL_OpenAudioDevice() doesn't, leaving us to manage it.

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