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