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