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