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