music.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 17 Jun 2015 00:11:41 -0700
changeset 705 fe757163b8f7
parent 687 3af92aa761d2
child 711 f40c5ac95b12
permissions -rw-r--r--
Fixed bug 3018 - Loading MIDI music using FluidSynth leaks memory.

Philipp Wiesemann

There is a memory leak in fluidsynth.c and fluidsynth_loadsong_RW_internal(). The allocated temporary buffer is not deleted if fluid_player_add_mem() returns FLUID_OK.
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2013 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 <stdlib.h>
    25 #include <string.h>
    26 #include <ctype.h>
    27 #include <assert.h>
    28 #include "SDL_endian.h"
    29 #include "SDL_audio.h"
    30 #include "SDL_timer.h"
    31 
    32 #include "SDL_mixer.h"
    33 
    34 #ifdef CMD_MUSIC
    35 #include "music_cmd.h"
    36 #endif
    37 #ifdef WAV_MUSIC
    38 #include "wavestream.h"
    39 #endif
    40 #ifdef MODPLUG_MUSIC
    41 #include "music_modplug.h"
    42 #endif
    43 #ifdef MOD_MUSIC
    44 #include "music_mod.h"
    45 #endif
    46 #ifdef MID_MUSIC
    47 #  ifdef USE_TIMIDITY_MIDI
    48 #    include "timidity.h"
    49 #  endif
    50 #  ifdef USE_FLUIDSYNTH_MIDI
    51 #    include "fluidsynth.h"
    52 #  endif
    53 #  ifdef USE_NATIVE_MIDI
    54 #    include "native_midi.h"
    55 #  endif
    56 #endif
    57 #ifdef OGG_MUSIC
    58 #include "music_ogg.h"
    59 #endif
    60 #ifdef MP3_MUSIC
    61 #include "dynamic_mp3.h"
    62 #endif
    63 #ifdef MP3_MAD_MUSIC
    64 #include "music_mad.h"
    65 #endif
    66 #ifdef FLAC_MUSIC
    67 #include "music_flac.h"
    68 #endif
    69 
    70 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    71 static SDL_AudioSpec used_mixer;
    72 #endif
    73 
    74 
    75 int volatile music_active = 1;
    76 static int volatile music_stopped = 0;
    77 static int music_loops = 0;
    78 static char *music_cmd = NULL;
    79 static Mix_Music * volatile music_playing = NULL;
    80 static int music_volume = MIX_MAX_VOLUME;
    81 
    82 struct _Mix_Music {
    83     Mix_MusicType type;
    84     union {
    85 #ifdef CMD_MUSIC
    86         MusicCMD *cmd;
    87 #endif
    88 #ifdef WAV_MUSIC
    89         WAVStream *wave;
    90 #endif
    91 #ifdef MODPLUG_MUSIC
    92         modplug_data *modplug;
    93 #endif
    94 #ifdef MOD_MUSIC
    95         struct MODULE *module;
    96 #endif
    97 #ifdef MID_MUSIC
    98 #ifdef USE_TIMIDITY_MIDI
    99         MidiSong *midi;
   100 #endif
   101 #ifdef USE_FLUIDSYNTH_MIDI
   102         FluidSynthMidiSong *fluidsynthmidi;
   103 #endif
   104 #ifdef USE_NATIVE_MIDI
   105         NativeMidiSong *nativemidi;
   106 #endif
   107 #endif
   108 #ifdef OGG_MUSIC
   109         OGG_music *ogg;
   110 #endif
   111 #ifdef MP3_MUSIC
   112         SMPEG *mp3;
   113 #endif
   114 #ifdef MP3_MAD_MUSIC
   115         mad_data *mp3_mad;
   116 #endif
   117 #ifdef FLAC_MUSIC
   118         FLAC_music *flac;
   119 #endif
   120     } data;
   121     Mix_Fading fading;
   122     int fade_step;
   123     int fade_steps;
   124     int error;
   125 };
   126 #ifdef MID_MUSIC
   127 #ifdef USE_TIMIDITY_MIDI
   128 static int timidity_ok;
   129 static int samplesize;
   130 #endif
   131 #ifdef USE_FLUIDSYNTH_MIDI
   132 static int fluidsynth_ok;
   133 #endif
   134 #ifdef USE_NATIVE_MIDI
   135 static int native_midi_ok;
   136 #endif
   137 #endif
   138 
   139 /* Used to calculate fading steps */
   140 static int ms_per_step;
   141 
   142 /* rcg06042009 report available decoders at runtime. */
   143 static const char **music_decoders = NULL;
   144 static int num_decoders = 0;
   145 
   146 /* Semicolon-separated SoundFont paths */
   147 #ifdef MID_MUSIC
   148 char* soundfont_paths = NULL;
   149 #endif
   150 
   151 int Mix_GetNumMusicDecoders(void)
   152 {
   153     return(num_decoders);
   154 }
   155 
   156 const char *Mix_GetMusicDecoder(int index)
   157 {
   158     if ((index < 0) || (index >= num_decoders)) {
   159         return NULL;
   160     }
   161     return(music_decoders[index]);
   162 }
   163 
   164 static void add_music_decoder(const char *decoder)
   165 {
   166     void *ptr = SDL_realloc((void *)music_decoders, (num_decoders + 1) * sizeof (const char *));
   167     if (ptr == NULL) {
   168         return;  /* oh well, go on without it. */
   169     }
   170     music_decoders = (const char **) ptr;
   171     music_decoders[num_decoders++] = decoder;
   172 }
   173 
   174 /* Local low-level functions prototypes */
   175 static void music_internal_initialize_volume(void);
   176 static void music_internal_volume(int volume);
   177 static int  music_internal_play(Mix_Music *music, double position);
   178 static int  music_internal_position(double position);
   179 static int  music_internal_playing();
   180 static void music_internal_halt(void);
   181 
   182 
   183 /* Support for hooking when the music has finished */
   184 static void (*music_finished_hook)(void) = NULL;
   185 
   186 void Mix_HookMusicFinished(void (*music_finished)(void))
   187 {
   188     SDL_LockAudio();
   189     music_finished_hook = music_finished;
   190     SDL_UnlockAudio();
   191 }
   192 
   193 
   194 /* If music isn't playing, halt it if no looping is required, restart it */
   195 /* othesrchise. NOP if the music is playing */
   196 static int music_halt_or_loop (void)
   197 {
   198     /* Restart music if it has to loop */
   199 
   200     if (!music_internal_playing())
   201     {
   202 #ifdef USE_NATIVE_MIDI
   203         /* Native MIDI handles looping internally */
   204         if (music_playing->type == MUS_MID && native_midi_ok) {
   205             music_loops = 0;
   206         }
   207 #endif
   208 
   209         /* Restart music if it has to loop at a high level */
   210         if (music_loops)
   211         {
   212             Mix_Fading current_fade;
   213             if (music_loops > 0) {
   214                 --music_loops;
   215             }
   216             current_fade = music_playing->fading;
   217             music_internal_play(music_playing, 0.0);
   218             music_playing->fading = current_fade;
   219         }
   220         else
   221         {
   222             music_internal_halt();
   223             if (music_finished_hook)
   224                 music_finished_hook();
   225 
   226             return 0;
   227         }
   228     }
   229 
   230     return 1;
   231 }
   232 
   233 
   234 
   235 /* Mixing function */
   236 void music_mixer(void *udata, Uint8 *stream, int len)
   237 {
   238     int left = 0;
   239 
   240     if ( music_playing && music_active ) {
   241         /* Handle fading */
   242         if ( music_playing->fading != MIX_NO_FADING ) {
   243             if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   244                 int volume;
   245                 int fade_step = music_playing->fade_step;
   246                 int fade_steps = music_playing->fade_steps;
   247 
   248                 if ( music_playing->fading == MIX_FADING_OUT ) {
   249                     volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
   250                 } else { /* Fading in */
   251                     volume = (music_volume * fade_step) / fade_steps;
   252                 }
   253                 music_internal_volume(volume);
   254             } else {
   255                 if ( music_playing->fading == MIX_FADING_OUT ) {
   256                     music_internal_halt();
   257                     if ( music_finished_hook ) {
   258                         music_finished_hook();
   259                     }
   260                     return;
   261                 }
   262                 music_playing->fading = MIX_NO_FADING;
   263             }
   264         }
   265 
   266         music_halt_or_loop();
   267         if (!music_internal_playing())
   268             return;
   269 
   270         switch (music_playing->type) {
   271 #ifdef CMD_MUSIC
   272             case MUS_CMD:
   273                 /* The playing is done externally */
   274                 break;
   275 #endif
   276 #ifdef WAV_MUSIC
   277             case MUS_WAV:
   278                 left = WAVStream_PlaySome(stream, len);
   279                 break;
   280 #endif
   281 #ifdef MODPLUG_MUSIC
   282             case MUS_MODPLUG:
   283                 left = modplug_playAudio(music_playing->data.modplug, stream, len);
   284                 break;
   285 #endif
   286 #ifdef MOD_MUSIC
   287             case MUS_MOD:
   288                 left = MOD_playAudio(music_playing->data.module, stream, len);
   289                 break;
   290 #endif
   291 #ifdef MID_MUSIC
   292             case MUS_MID:
   293 #ifdef USE_NATIVE_MIDI
   294                 if ( native_midi_ok ) {
   295                     /* Native midi is handled asynchronously */
   296                     goto skip;
   297                 }
   298 #endif
   299 #ifdef USE_FLUIDSYNTH_MIDI
   300                 if ( fluidsynth_ok ) {
   301                     fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
   302                     goto skip;
   303                 }
   304 #endif
   305 #ifdef USE_TIMIDITY_MIDI
   306                 if ( timidity_ok ) {
   307                     int samples = len / samplesize;
   308                     Timidity_PlaySome(stream, samples);
   309                     goto skip;
   310                 }
   311 #endif
   312                 break;
   313 #endif
   314 #ifdef OGG_MUSIC
   315             case MUS_OGG:
   316 
   317                 left = OGG_playAudio(music_playing->data.ogg, stream, len);
   318                 break;
   319 #endif
   320 #ifdef FLAC_MUSIC
   321             case MUS_FLAC:
   322                 left = FLAC_playAudio(music_playing->data.flac, stream, len);
   323                 break;
   324 #endif
   325 #ifdef MP3_MUSIC
   326             case MUS_MP3:
   327                 left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
   328                 break;
   329 #endif
   330 #ifdef MP3_MAD_MUSIC
   331             case MUS_MP3_MAD:
   332                 left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
   333                 break;
   334 #endif
   335             default:
   336                 /* Unknown music type?? */
   337                 break;
   338         }
   339     }
   340 
   341 skip:
   342     /* Handle seamless music looping */
   343     if (left > 0 && left < len) {
   344         music_halt_or_loop();
   345         if (music_internal_playing())
   346             music_mixer(udata, stream+(len-left), left);
   347     }
   348 }
   349 
   350 /* Initialize the music players with a certain desired audio format */
   351 int open_music(SDL_AudioSpec *mixer)
   352 {
   353 #ifdef WAV_MUSIC
   354     if ( WAVStream_Init(mixer) == 0 ) {
   355         add_music_decoder("WAVE");
   356     }
   357 #endif
   358 #ifdef MODPLUG_MUSIC
   359     if ( modplug_init(mixer) == 0 ) {
   360         add_music_decoder("MODPLUG");
   361     }
   362 #endif
   363 #ifdef MOD_MUSIC
   364     if ( MOD_init(mixer) == 0 ) {
   365         add_music_decoder("MIKMOD");
   366     }
   367 #endif
   368 #ifdef MID_MUSIC
   369 #ifdef USE_TIMIDITY_MIDI
   370     samplesize = mixer->size / mixer->samples;
   371     if ( Timidity_Init(mixer->freq, mixer->format,
   372                         mixer->channels, mixer->samples) == 0 ) {
   373         timidity_ok = 1;
   374         add_music_decoder("TIMIDITY");
   375     } else {
   376         timidity_ok = 0;
   377     }
   378 #endif
   379 #ifdef USE_FLUIDSYNTH_MIDI
   380     if ( fluidsynth_init(mixer) == 0 ) {
   381         fluidsynth_ok = 1;
   382         add_music_decoder("FLUIDSYNTH");
   383     } else {
   384         fluidsynth_ok = 0;
   385     }
   386 #endif
   387 #ifdef USE_NATIVE_MIDI
   388 #ifdef USE_FLUIDSYNTH_MIDI
   389     native_midi_ok = !fluidsynth_ok;
   390     if ( native_midi_ok )
   391 #endif
   392 #ifdef USE_TIMIDITY_MIDI
   393         native_midi_ok = !timidity_ok;
   394     if ( !native_midi_ok ) {
   395         native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
   396     }
   397     if ( native_midi_ok )
   398 #endif
   399         native_midi_ok = native_midi_detect();
   400     if ( native_midi_ok )
   401         add_music_decoder("NATIVEMIDI");
   402 #endif
   403 #endif
   404 #ifdef OGG_MUSIC
   405     if ( OGG_init(mixer) == 0 ) {
   406         add_music_decoder("OGG");
   407     }
   408 #endif
   409 #ifdef FLAC_MUSIC
   410     if ( FLAC_init(mixer) == 0 ) {
   411         add_music_decoder("FLAC");
   412     }
   413 #endif
   414 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
   415     /* Keep a copy of the mixer */
   416     used_mixer = *mixer;
   417     add_music_decoder("MP3");
   418 #endif
   419 
   420     music_playing = NULL;
   421     music_stopped = 0;
   422     Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   423 
   424     /* Calculate the number of ms for each callback */
   425     ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   426 
   427     return(0);
   428 }
   429 
   430 /* Portable case-insensitive string compare function */
   431 int MIX_string_equals(const char *str1, const char *str2)
   432 {
   433     while ( *str1 && *str2 ) {
   434         if ( toupper((unsigned char)*str1) !=
   435              toupper((unsigned char)*str2) )
   436             break;
   437         ++str1;
   438         ++str2;
   439     }
   440     return (!*str1 && !*str2);
   441 }
   442 
   443 static int detect_mp3(Uint8 *magic)
   444 {
   445     if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
   446         return 1;
   447     }
   448 
   449     /* Detection code lifted from SMPEG */
   450     if(((magic[0] & 0xff) != 0xff) || // No sync bits
   451        ((magic[1] & 0xf0) != 0xf0) || //
   452        ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
   453        ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
   454        ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
   455        ((magic[1] & 0x06) == 0x00)) { // Layer is 4
   456         return(0);
   457     }
   458     return 1;
   459 }
   460 
   461 /* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
   462  * assumed and MUS_MOD will be returned, meaning that the format might not
   463  * actually be MOD-based.
   464  *
   465  * Returns MUS_NONE in case of errors. */
   466 static Mix_MusicType detect_music_type(SDL_RWops *src)
   467 {
   468     Uint8 magic[5];
   469     Uint8 moremagic[9];
   470 
   471     Sint64 start = SDL_RWtell(src);
   472     if (SDL_RWread(src, magic, 1, 4) != 4 || SDL_RWread(src, moremagic, 1, 8) != 8 ) {
   473         Mix_SetError("Couldn't read from RWops");
   474         return MUS_NONE;
   475     }
   476     SDL_RWseek(src, start, RW_SEEK_SET);
   477     magic[4]='\0';
   478     moremagic[8] = '\0';
   479 
   480     /* WAVE files have the magic four bytes "RIFF"
   481        AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
   482     if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
   483         (strcmp((char *)magic, "FORM") == 0)) {
   484         return MUS_WAV;
   485     }
   486 
   487     /* Ogg Vorbis files have the magic four bytes "OggS" */
   488     if (strcmp((char *)magic, "OggS") == 0) {
   489         return MUS_OGG;
   490     }
   491 
   492     /* FLAC files have the magic four bytes "fLaC" */
   493     if (strcmp((char *)magic, "fLaC") == 0) {
   494         return MUS_FLAC;
   495     }
   496 
   497     /* MIDI files have the magic four bytes "MThd" */
   498     if (strcmp((char *)magic, "MThd") == 0) {
   499         return MUS_MID;
   500     }
   501 
   502     if (detect_mp3(magic)) {
   503         return MUS_MP3;
   504     }
   505 
   506     /* Assume MOD format.
   507      *
   508      * Apparently there is no way to check if the file is really a MOD,
   509      * or there are too many formats supported by MikMod/ModPlug, or
   510      * MikMod/ModPlug does this check by itself. */
   511     return MUS_MOD;
   512 }
   513 
   514 /* Load a music file */
   515 Mix_Music *Mix_LoadMUS(const char *file)
   516 {
   517     SDL_RWops *src;
   518     Mix_Music *music;
   519     Mix_MusicType type;
   520     char *ext = strrchr(file, '.');
   521 
   522 #ifdef CMD_MUSIC
   523     if ( music_cmd ) {
   524         /* Allocate memory for the music structure */
   525         music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
   526         if ( music == NULL ) {
   527             Mix_SetError("Out of memory");
   528             return(NULL);
   529         }
   530         music->error = 0;
   531         music->type = MUS_CMD;
   532         music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   533         if ( music->data.cmd == NULL ) {
   534             SDL_free(music);
   535             music = NULL;
   536         }
   537         return music;
   538     }
   539 #endif
   540 
   541     src = SDL_RWFromFile(file, "rb");
   542     if ( src == NULL ) {
   543         Mix_SetError("Couldn't open '%s'", file);
   544         return NULL;
   545     }
   546 
   547     /* Use the extension as a first guess on the file type */
   548     type = MUS_NONE;
   549     ext = strrchr(file, '.');
   550     /* No need to guard these with #ifdef *_MUSIC stuff,
   551      * since we simply call Mix_LoadMUSType_RW() later */
   552     if ( ext ) {
   553         ++ext; /* skip the dot in the extension */
   554         if ( MIX_string_equals(ext, "WAV") ) {
   555             type = MUS_WAV;
   556         } else if ( MIX_string_equals(ext, "MID") ||
   557                     MIX_string_equals(ext, "MIDI") ||
   558                     MIX_string_equals(ext, "KAR") ) {
   559             type = MUS_MID;
   560         } else if ( MIX_string_equals(ext, "OGG") ) {
   561             type = MUS_OGG;
   562         } else if ( MIX_string_equals(ext, "FLAC") ) {
   563             type = MUS_FLAC;
   564         } else  if ( MIX_string_equals(ext, "MPG") ||
   565                      MIX_string_equals(ext, "MPEG") ||
   566                      MIX_string_equals(ext, "MP3") ||
   567                      MIX_string_equals(ext, "MAD") ) {
   568             type = MUS_MP3;
   569         }
   570     }
   571     if ( type == MUS_NONE ) {
   572         type = detect_music_type(src);
   573     }
   574 
   575     /* We need to know if a specific error occurs; if not, we'll set a
   576      * generic one, so we clear the current one. */
   577     SDL_ClearError();
   578     music = Mix_LoadMUSType_RW(src, type, SDL_TRUE);
   579     if ( music == NULL && Mix_GetError()[0] == '\0' ) {
   580         Mix_SetError("Unrecognized music format");
   581     }
   582     return music;
   583 }
   584 
   585 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
   586 {
   587     return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
   588 }
   589 
   590 Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
   591 {
   592     Mix_Music *music;
   593     Sint64 start;
   594 
   595     if (!src) {
   596         Mix_SetError("RWops pointer is NULL");
   597         return NULL;
   598     }
   599     start = SDL_RWtell(src);
   600 
   601     /* If the caller wants auto-detection, figure out what kind of file
   602      * this is. */
   603     if (type == MUS_NONE) {
   604         if ((type = detect_music_type(src)) == MUS_NONE) {
   605             /* Don't call Mix_SetError() here since detect_music_type()
   606              * does that. */
   607             if (freesrc) {
   608                 SDL_RWclose(src);
   609             }
   610             return NULL;
   611         }
   612     }
   613 
   614     /* Allocate memory for the music structure */
   615     music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
   616     if (music == NULL ) {
   617         Mix_SetError("Out of memory");
   618         if (freesrc) {
   619             SDL_RWclose(src);
   620         }
   621         return NULL;
   622     }
   623     music->error = 1;
   624 
   625     switch (type) {
   626 #ifdef WAV_MUSIC
   627     case MUS_WAV:
   628         music->type = MUS_WAV;
   629         music->data.wave = WAVStream_LoadSong_RW(src, freesrc);
   630         if (music->data.wave) {
   631             music->error = 0;
   632         }
   633         break;
   634 #endif
   635 #ifdef OGG_MUSIC
   636     case MUS_OGG:
   637         music->type = MUS_OGG;
   638         music->data.ogg = OGG_new_RW(src, freesrc);
   639         if (music->data.ogg) {
   640             music->error = 0;
   641         }
   642         break;
   643 #endif
   644 #ifdef FLAC_MUSIC
   645     case MUS_FLAC:
   646         music->type = MUS_FLAC;
   647         music->data.flac = FLAC_new_RW(src, freesrc);
   648         if (music->data.flac) {
   649             music->error = 0;
   650         }
   651         break;
   652 #endif
   653 #ifdef MP3_MUSIC
   654     case MUS_MP3:
   655         if (Mix_Init(MIX_INIT_MP3)) {
   656             SMPEG_Info info;
   657             music->type = MUS_MP3;
   658             music->data.mp3 = smpeg.SMPEG_new_rwops(src, &info, freesrc, 0);
   659             if (!info.has_audio) {
   660                 Mix_SetError("MPEG file does not have any audio stream.");
   661                 smpeg.SMPEG_delete(music->data.mp3);
   662                 /* Deleting the MP3 closed the source if desired */
   663                 freesrc = SDL_FALSE;
   664             } else {
   665                 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   666                 music->error = 0;
   667             }
   668         }
   669         break;
   670 #elif defined(MP3_MAD_MUSIC)
   671     case MUS_MP3:
   672         music->type = MUS_MP3_MAD;
   673         music->data.mp3_mad = mad_openFileRW(src, &used_mixer, freesrc);
   674         if (music->data.mp3_mad) {
   675             music->error = 0;
   676         } else {
   677             Mix_SetError("Could not initialize MPEG stream.");
   678         }
   679         break;
   680 #endif
   681 #ifdef MID_MUSIC
   682     case MUS_MID:
   683         music->type = MUS_MID;
   684 #ifdef USE_NATIVE_MIDI
   685         if (native_midi_ok) {
   686             SDL_RWseek(src, start, RW_SEEK_SET);
   687             music->data.nativemidi = native_midi_loadsong_RW(src, freesrc);
   688             if (music->data.nativemidi) {
   689                 music->error = 0;
   690             } else {
   691                 Mix_SetError("%s", native_midi_error());
   692             }
   693             break;
   694         }
   695 #endif
   696 #ifdef USE_FLUIDSYNTH_MIDI
   697         if (fluidsynth_ok) {
   698             SDL_RWseek(src, start, RW_SEEK_SET);
   699             music->data.fluidsynthmidi = fluidsynth_loadsong_RW(src, freesrc);
   700             if (music->data.fluidsynthmidi) {
   701                 music->error = 0;
   702             }
   703             break;
   704         }
   705 #endif
   706 #ifdef USE_TIMIDITY_MIDI
   707         if (timidity_ok) {
   708             SDL_RWseek(src, start, RW_SEEK_SET);
   709             music->data.midi = Timidity_LoadSong_RW(src, freesrc);
   710             if (music->data.midi) {
   711                 music->error = 0;
   712             } else {
   713                 Mix_SetError("%s", Timidity_Error());
   714             }
   715         } else {
   716             Mix_SetError("%s", Timidity_Error());
   717         }
   718 #endif
   719         break;
   720 #endif
   721 #if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
   722     case MUS_MOD:
   723 #ifdef MODPLUG_MUSIC
   724         if (music->error) {
   725             SDL_RWseek(src, start, RW_SEEK_SET);
   726             music->type = MUS_MODPLUG;
   727             music->data.modplug = modplug_new_RW(src, freesrc);
   728             if (music->data.modplug) {
   729                 music->error = 0;
   730             }
   731         }
   732 #endif
   733 #ifdef MOD_MUSIC
   734         if (music->error) {
   735             SDL_RWseek(src, start, RW_SEEK_SET);
   736             music->type = MUS_MOD;
   737             music->data.module = MOD_new_RW(src, freesrc);
   738             if (music->data.module) {
   739                 music->error = 0;
   740             }
   741         }
   742 #endif
   743         break;
   744 #endif
   745 
   746     default:
   747         Mix_SetError("Unrecognized music format");
   748         break;
   749     } /* switch (want) */
   750 
   751     if (music->error) {
   752         SDL_free(music);
   753         if (freesrc) {
   754             SDL_RWclose(src);
   755         } else {
   756             SDL_RWseek(src, start, RW_SEEK_SET);
   757         }
   758         music = NULL;
   759     }
   760     return music;
   761 }
   762 
   763 /* Free a music chunk previously loaded */
   764 void Mix_FreeMusic(Mix_Music *music)
   765 {
   766     if ( music ) {
   767         /* Stop the music if it's currently playing */
   768         SDL_LockAudio();
   769         if ( music == music_playing ) {
   770             /* Wait for any fade out to finish */
   771             while ( music->fading == MIX_FADING_OUT ) {
   772                 SDL_UnlockAudio();
   773                 SDL_Delay(100);
   774                 SDL_LockAudio();
   775             }
   776             if ( music == music_playing ) {
   777                 music_internal_halt();
   778             }
   779         }
   780         SDL_UnlockAudio();
   781         switch (music->type) {
   782 #ifdef CMD_MUSIC
   783             case MUS_CMD:
   784                 MusicCMD_FreeSong(music->data.cmd);
   785                 break;
   786 #endif
   787 #ifdef WAV_MUSIC
   788             case MUS_WAV:
   789                 WAVStream_FreeSong(music->data.wave);
   790                 break;
   791 #endif
   792 #ifdef MODPLUG_MUSIC
   793             case MUS_MODPLUG:
   794                 modplug_delete(music->data.modplug);
   795                 break;
   796 #endif
   797 #ifdef MOD_MUSIC
   798             case MUS_MOD:
   799                 MOD_delete(music->data.module);
   800                 break;
   801 #endif
   802 #ifdef MID_MUSIC
   803             case MUS_MID:
   804 #ifdef USE_NATIVE_MIDI
   805                 if ( native_midi_ok ) {
   806                     native_midi_freesong(music->data.nativemidi);
   807                     goto skip;
   808                 }
   809 #endif
   810 #ifdef USE_FLUIDSYNTH_MIDI
   811                 if ( fluidsynth_ok ) {
   812                     fluidsynth_freesong(music->data.fluidsynthmidi);
   813                     goto skip;
   814                 }
   815 #endif
   816 #ifdef USE_TIMIDITY_MIDI
   817                 if ( timidity_ok ) {
   818                     Timidity_FreeSong(music->data.midi);
   819                     goto skip;
   820                 }
   821 #endif
   822                 break;
   823 #endif
   824 #ifdef OGG_MUSIC
   825             case MUS_OGG:
   826                 OGG_delete(music->data.ogg);
   827                 break;
   828 #endif
   829 #ifdef FLAC_MUSIC
   830             case MUS_FLAC:
   831                 FLAC_delete(music->data.flac);
   832                 break;
   833 #endif
   834 #ifdef MP3_MUSIC
   835             case MUS_MP3:
   836                 smpeg.SMPEG_delete(music->data.mp3);
   837                 break;
   838 #endif
   839 #ifdef MP3_MAD_MUSIC
   840             case MUS_MP3_MAD:
   841                 mad_closeFile(music->data.mp3_mad);
   842                 break;
   843 #endif
   844             default:
   845                 /* Unknown music type?? */
   846                 break;
   847         }
   848 
   849     skip:
   850         SDL_free(music);
   851     }
   852 }
   853 
   854 /* Find out the music format of a mixer music, or the currently playing
   855    music, if 'music' is NULL.
   856 */
   857 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   858 {
   859     Mix_MusicType type = MUS_NONE;
   860 
   861     if ( music ) {
   862         type = music->type;
   863     } else {
   864         SDL_LockAudio();
   865         if ( music_playing ) {
   866             type = music_playing->type;
   867         }
   868         SDL_UnlockAudio();
   869     }
   870     return(type);
   871 }
   872 
   873 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   874  */
   875 static int music_internal_play(Mix_Music *music, double position)
   876 {
   877     int retval = 0;
   878 
   879 #if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
   880     /* This fixes a bug with native MIDI on Mac OS X, where you
   881        can't really stop and restart MIDI from the audio callback.
   882     */
   883     if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
   884         /* Just a seek suffices to restart playing */
   885         music_internal_position(position);
   886         return 0;
   887     }
   888 #endif
   889 
   890     /* Note the music we're playing */
   891     if ( music_playing ) {
   892         music_internal_halt();
   893     }
   894     music_playing = music;
   895 
   896     /* Set the initial volume */
   897     if ( music->type != MUS_MOD ) {
   898         music_internal_initialize_volume();
   899     }
   900 
   901     /* Set up for playback */
   902     switch (music->type) {
   903 #ifdef CMD_MUSIC
   904         case MUS_CMD:
   905         MusicCMD_Start(music->data.cmd);
   906         break;
   907 #endif
   908 #ifdef WAV_MUSIC
   909         case MUS_WAV:
   910         WAVStream_Start(music->data.wave);
   911         break;
   912 #endif
   913 #ifdef MODPLUG_MUSIC
   914         case MUS_MODPLUG:
   915         /* can't set volume until file is loaded, so finally set it now */
   916         music_internal_initialize_volume();
   917         modplug_play(music->data.modplug);
   918         break;
   919 #endif
   920 #ifdef MOD_MUSIC
   921         case MUS_MOD:
   922         MOD_play(music->data.module);
   923         /* Player_SetVolume() does nothing before Player_Start() */
   924         music_internal_initialize_volume();
   925         break;
   926 #endif
   927 #ifdef MID_MUSIC
   928         case MUS_MID:
   929 #ifdef USE_NATIVE_MIDI
   930         if ( native_midi_ok ) {
   931             native_midi_start(music->data.nativemidi, music_loops);
   932             goto skip;
   933         }
   934 #endif
   935 #ifdef USE_FLUIDSYNTH_MIDI
   936         if (fluidsynth_ok ) {
   937             fluidsynth_start(music->data.fluidsynthmidi);
   938             goto skip;
   939         }
   940 #endif
   941 #ifdef USE_TIMIDITY_MIDI
   942         if ( timidity_ok ) {
   943             Timidity_Start(music->data.midi);
   944             goto skip;
   945         }
   946 #endif
   947         break;
   948 #endif
   949 #ifdef OGG_MUSIC
   950         case MUS_OGG:
   951         OGG_play(music->data.ogg);
   952         break;
   953 #endif
   954 #ifdef FLAC_MUSIC
   955         case MUS_FLAC:
   956         FLAC_play(music->data.flac);
   957         break;
   958 #endif
   959 #ifdef MP3_MUSIC
   960         case MUS_MP3:
   961         smpeg.SMPEG_enableaudio(music->data.mp3,1);
   962         smpeg.SMPEG_enablevideo(music->data.mp3,0);
   963         smpeg.SMPEG_play(music_playing->data.mp3);
   964         break;
   965 #endif
   966 #ifdef MP3_MAD_MUSIC
   967         case MUS_MP3_MAD:
   968         mad_start(music->data.mp3_mad);
   969         break;
   970 #endif
   971         default:
   972         Mix_SetError("Can't play unknown music type");
   973         retval = -1;
   974         break;
   975     }
   976 
   977 skip:
   978     /* Set the playback position, note any errors if an offset is used */
   979     if ( retval == 0 ) {
   980         if ( position > 0.0 ) {
   981             if ( music_internal_position(position) < 0 ) {
   982                 Mix_SetError("Position not implemented for music type");
   983                 retval = -1;
   984             }
   985         } else {
   986             music_internal_position(0.0);
   987         }
   988     }
   989 
   990     /* If the setup failed, we're not playing any music anymore */
   991     if ( retval < 0 ) {
   992         music_playing = NULL;
   993     }
   994     return(retval);
   995 }
   996 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   997 {
   998     int retval;
   999 
  1000     if ( ms_per_step == 0 ) {
  1001         SDL_SetError("Audio device hasn't been opened");
  1002         return(-1);
  1003     }
  1004 
  1005     /* Don't play null pointers :-) */
  1006     if ( music == NULL ) {
  1007         Mix_SetError("music parameter was NULL");
  1008         return(-1);
  1009     }
  1010 
  1011     /* Setup the data */
  1012     if ( ms ) {
  1013         music->fading = MIX_FADING_IN;
  1014     } else {
  1015         music->fading = MIX_NO_FADING;
  1016     }
  1017     music->fade_step = 0;
  1018     music->fade_steps = ms/ms_per_step;
  1019 
  1020     /* Play the puppy */
  1021     SDL_LockAudio();
  1022     /* If the current music is fading out, wait for the fade to complete */
  1023     while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
  1024         SDL_UnlockAudio();
  1025         SDL_Delay(100);
  1026         SDL_LockAudio();
  1027     }
  1028     music_active = 1;
  1029     if (loops == 1) {
  1030         /* Loop is the number of times to play the audio */
  1031         loops = 0;
  1032     }
  1033     music_loops = loops;
  1034     retval = music_internal_play(music, position);
  1035     SDL_UnlockAudio();
  1036 
  1037     return(retval);
  1038 }
  1039 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
  1040 {
  1041     return Mix_FadeInMusicPos(music, loops, ms, 0.0);
  1042 }
  1043 int Mix_PlayMusic(Mix_Music *music, int loops)
  1044 {
  1045     return Mix_FadeInMusicPos(music, loops, 0, 0.0);
  1046 }
  1047 
  1048 /* Set the playing music position */
  1049 int music_internal_position(double position)
  1050 {
  1051     int retval = 0;
  1052 
  1053     switch (music_playing->type) {
  1054 #ifdef MODPLUG_MUSIC
  1055         case MUS_MODPLUG:
  1056         modplug_jump_to_time(music_playing->data.modplug, position);
  1057         break;
  1058 #endif
  1059 #ifdef MOD_MUSIC
  1060         case MUS_MOD:
  1061         MOD_jump_to_time(music_playing->data.module, position);
  1062         break;
  1063 #endif
  1064 #ifdef OGG_MUSIC
  1065         case MUS_OGG:
  1066         OGG_jump_to_time(music_playing->data.ogg, position);
  1067         break;
  1068 #endif
  1069 #ifdef FLAC_MUSIC
  1070         case MUS_FLAC:
  1071         FLAC_jump_to_time(music_playing->data.flac, position);
  1072         break;
  1073 #endif
  1074 #ifdef MP3_MUSIC
  1075         case MUS_MP3:
  1076         smpeg.SMPEG_rewind(music_playing->data.mp3);
  1077         smpeg.SMPEG_play(music_playing->data.mp3);
  1078         if ( position > 0.0 ) {
  1079             smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
  1080         }
  1081         break;
  1082 #endif
  1083 #ifdef MP3_MAD_MUSIC
  1084         case MUS_MP3_MAD:
  1085         mad_seek(music_playing->data.mp3_mad, position);
  1086         break;
  1087 #endif
  1088         default:
  1089         /* TODO: Implement this for other music backends */
  1090         retval = -1;
  1091         break;
  1092     }
  1093     return(retval);
  1094 }
  1095 int Mix_SetMusicPosition(double position)
  1096 {
  1097     int retval;
  1098 
  1099     SDL_LockAudio();
  1100     if ( music_playing ) {
  1101         retval = music_internal_position(position);
  1102         if ( retval < 0 ) {
  1103             Mix_SetError("Position not implemented for music type");
  1104         }
  1105     } else {
  1106         Mix_SetError("Music isn't playing");
  1107         retval = -1;
  1108     }
  1109     SDL_UnlockAudio();
  1110 
  1111     return(retval);
  1112 }
  1113 
  1114 /* Set the music's initial volume */
  1115 static void music_internal_initialize_volume(void)
  1116 {
  1117     if ( music_playing->fading == MIX_FADING_IN ) {
  1118         music_internal_volume(0);
  1119     } else {
  1120         music_internal_volume(music_volume);
  1121     }
  1122 }
  1123 
  1124 /* Set the music volume */
  1125 static void music_internal_volume(int volume)
  1126 {
  1127     switch (music_playing->type) {
  1128 #ifdef CMD_MUSIC
  1129         case MUS_CMD:
  1130         MusicCMD_SetVolume(volume);
  1131         break;
  1132 #endif
  1133 #ifdef WAV_MUSIC
  1134         case MUS_WAV:
  1135         WAVStream_SetVolume(volume);
  1136         break;
  1137 #endif
  1138 #ifdef MODPLUG_MUSIC
  1139         case MUS_MODPLUG:
  1140         modplug_setvolume(music_playing->data.modplug, volume);
  1141         break;
  1142 #endif
  1143 #ifdef MOD_MUSIC
  1144         case MUS_MOD:
  1145         MOD_setvolume(music_playing->data.module, volume);
  1146         break;
  1147 #endif
  1148 #ifdef MID_MUSIC
  1149         case MUS_MID:
  1150 #ifdef USE_NATIVE_MIDI
  1151         if ( native_midi_ok ) {
  1152             native_midi_setvolume(volume);
  1153             return;
  1154         }
  1155 #endif
  1156 #ifdef USE_FLUIDSYNTH_MIDI
  1157         if ( fluidsynth_ok ) {
  1158             fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1159             return;
  1160         }
  1161 #endif
  1162 #ifdef USE_TIMIDITY_MIDI
  1163         if ( timidity_ok ) {
  1164             Timidity_SetVolume(volume);
  1165             return;
  1166         }
  1167 #endif
  1168         break;
  1169 #endif
  1170 #ifdef OGG_MUSIC
  1171         case MUS_OGG:
  1172         OGG_setvolume(music_playing->data.ogg, volume);
  1173         break;
  1174 #endif
  1175 #ifdef FLAC_MUSIC
  1176         case MUS_FLAC:
  1177         FLAC_setvolume(music_playing->data.flac, volume);
  1178         break;
  1179 #endif
  1180 #ifdef MP3_MUSIC
  1181         case MUS_MP3:
  1182         smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1183         break;
  1184 #endif
  1185 #ifdef MP3_MAD_MUSIC
  1186         case MUS_MP3_MAD:
  1187         mad_setVolume(music_playing->data.mp3_mad, volume);
  1188         break;
  1189 #endif
  1190         default:
  1191         /* Unknown music type?? */
  1192         break;
  1193     }
  1194 }
  1195 int Mix_VolumeMusic(int volume)
  1196 {
  1197     int prev_volume;
  1198 
  1199     prev_volume = music_volume;
  1200     if ( volume < 0 ) {
  1201         return prev_volume;
  1202     }
  1203     if ( volume > SDL_MIX_MAXVOLUME ) {
  1204         volume = SDL_MIX_MAXVOLUME;
  1205     }
  1206     music_volume = volume;
  1207     SDL_LockAudio();
  1208     if ( music_playing ) {
  1209         music_internal_volume(music_volume);
  1210     }
  1211     SDL_UnlockAudio();
  1212     return(prev_volume);
  1213 }
  1214 
  1215 /* Halt playing of music */
  1216 static void music_internal_halt(void)
  1217 {
  1218     switch (music_playing->type) {
  1219 #ifdef CMD_MUSIC
  1220         case MUS_CMD:
  1221         MusicCMD_Stop(music_playing->data.cmd);
  1222         break;
  1223 #endif
  1224 #ifdef WAV_MUSIC
  1225         case MUS_WAV:
  1226         WAVStream_Stop();
  1227         break;
  1228 #endif
  1229 #ifdef MODPLUG_MUSIC
  1230         case MUS_MODPLUG:
  1231         modplug_stop(music_playing->data.modplug);
  1232         break;
  1233 #endif
  1234 #ifdef MOD_MUSIC
  1235         case MUS_MOD:
  1236         MOD_stop(music_playing->data.module);
  1237         break;
  1238 #endif
  1239 #ifdef MID_MUSIC
  1240         case MUS_MID:
  1241 #ifdef USE_NATIVE_MIDI
  1242         if ( native_midi_ok ) {
  1243             native_midi_stop();
  1244             goto skip;
  1245         }
  1246 #endif
  1247 #ifdef USE_FLUIDSYNTH_MIDI
  1248         if ( fluidsynth_ok ) {
  1249             fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1250             goto skip;
  1251         }
  1252 #endif
  1253 #ifdef USE_TIMIDITY_MIDI
  1254         if ( timidity_ok ) {
  1255             Timidity_Stop();
  1256             goto skip;
  1257         }
  1258 #endif
  1259         break;
  1260 #endif
  1261 #ifdef OGG_MUSIC
  1262         case MUS_OGG:
  1263         OGG_stop(music_playing->data.ogg);
  1264         break;
  1265 #endif
  1266 #ifdef FLAC_MUSIC
  1267         case MUS_FLAC:
  1268         FLAC_stop(music_playing->data.flac);
  1269         break;
  1270 #endif
  1271 #ifdef MP3_MUSIC
  1272         case MUS_MP3:
  1273         smpeg.SMPEG_stop(music_playing->data.mp3);
  1274         break;
  1275 #endif
  1276 #ifdef MP3_MAD_MUSIC
  1277         case MUS_MP3_MAD:
  1278         mad_stop(music_playing->data.mp3_mad);
  1279         break;
  1280 #endif
  1281         default:
  1282         /* Unknown music type?? */
  1283         return;
  1284     }
  1285 
  1286 skip:
  1287     music_playing->fading = MIX_NO_FADING;
  1288     music_playing = NULL;
  1289 }
  1290 int Mix_HaltMusic(void)
  1291 {
  1292     SDL_LockAudio();
  1293     if ( music_playing ) {
  1294         music_internal_halt();
  1295         if ( music_finished_hook ) {
  1296             music_finished_hook();
  1297         }
  1298     }
  1299     SDL_UnlockAudio();
  1300 
  1301     return(0);
  1302 }
  1303 
  1304 /* Progressively stop the music */
  1305 int Mix_FadeOutMusic(int ms)
  1306 {
  1307     int retval = 0;
  1308 
  1309     if ( ms_per_step == 0 ) {
  1310         SDL_SetError("Audio device hasn't been opened");
  1311         return 0;
  1312     }
  1313 
  1314     if (ms <= 0) {  /* just halt immediately. */
  1315         Mix_HaltMusic();
  1316         return 1;
  1317     }
  1318 
  1319     SDL_LockAudio();
  1320     if ( music_playing) {
  1321                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1322                 if ( music_playing->fading == MIX_NO_FADING ) {
  1323                 music_playing->fade_step = 0;
  1324                 } else {
  1325                         int step;
  1326                         int old_fade_steps = music_playing->fade_steps;
  1327                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1328                                 step = music_playing->fade_step;
  1329                         } else {
  1330                                 step = old_fade_steps
  1331                                         - music_playing->fade_step + 1;
  1332                         }
  1333                         music_playing->fade_step = (step * fade_steps)
  1334                                 / old_fade_steps;
  1335                 }
  1336         music_playing->fading = MIX_FADING_OUT;
  1337         music_playing->fade_steps = fade_steps;
  1338         retval = 1;
  1339     }
  1340     SDL_UnlockAudio();
  1341 
  1342     return(retval);
  1343 }
  1344 
  1345 Mix_Fading Mix_FadingMusic(void)
  1346 {
  1347     Mix_Fading fading = MIX_NO_FADING;
  1348 
  1349     SDL_LockAudio();
  1350     if ( music_playing ) {
  1351         fading = music_playing->fading;
  1352     }
  1353     SDL_UnlockAudio();
  1354 
  1355     return(fading);
  1356 }
  1357 
  1358 /* Pause/Resume the music stream */
  1359 void Mix_PauseMusic(void)
  1360 {
  1361     music_active = 0;
  1362 }
  1363 
  1364 void Mix_ResumeMusic(void)
  1365 {
  1366     music_active = 1;
  1367 }
  1368 
  1369 void Mix_RewindMusic(void)
  1370 {
  1371     Mix_SetMusicPosition(0.0);
  1372 }
  1373 
  1374 int Mix_PausedMusic(void)
  1375 {
  1376     return (music_active == 0);
  1377 }
  1378 
  1379 /* Check the status of the music */
  1380 static int music_internal_playing()
  1381 {
  1382     int playing = 1;
  1383 
  1384     if (music_playing == NULL) {
  1385         return 0;
  1386     }
  1387 
  1388     switch (music_playing->type) {
  1389 #ifdef CMD_MUSIC
  1390         case MUS_CMD:
  1391         if (!MusicCMD_Active(music_playing->data.cmd)) {
  1392             playing = 0;
  1393         }
  1394         break;
  1395 #endif
  1396 #ifdef WAV_MUSIC
  1397         case MUS_WAV:
  1398         if ( ! WAVStream_Active() ) {
  1399             playing = 0;
  1400         }
  1401         break;
  1402 #endif
  1403 #ifdef MODPLUG_MUSIC
  1404         case MUS_MODPLUG:
  1405         if ( ! modplug_playing(music_playing->data.modplug) ) {
  1406             playing = 0;
  1407         }
  1408         break;
  1409 #endif
  1410 #ifdef MOD_MUSIC
  1411         case MUS_MOD:
  1412         if ( ! MOD_playing(music_playing->data.module) ) {
  1413             playing = 0;
  1414         }
  1415         break;
  1416 #endif
  1417 #ifdef MID_MUSIC
  1418         case MUS_MID:
  1419 #ifdef USE_NATIVE_MIDI
  1420         if ( native_midi_ok ) {
  1421             if ( ! native_midi_active() )
  1422                 playing = 0;
  1423             goto skip;
  1424         }
  1425 #endif
  1426 #ifdef USE_FLUIDSYNTH_MIDI
  1427         if ( fluidsynth_ok ) {
  1428             if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1429                 playing = 0;
  1430             goto skip;
  1431         }
  1432 #endif
  1433 #ifdef USE_TIMIDITY_MIDI
  1434         if ( timidity_ok ) {
  1435             if ( ! Timidity_Active() )
  1436                 playing = 0;
  1437             goto skip;
  1438         }
  1439 #endif
  1440         break;
  1441 #endif
  1442 #ifdef OGG_MUSIC
  1443         case MUS_OGG:
  1444         if ( ! OGG_playing(music_playing->data.ogg) ) {
  1445             playing = 0;
  1446         }
  1447         break;
  1448 #endif
  1449 #ifdef FLAC_MUSIC
  1450         case MUS_FLAC:
  1451         if ( ! FLAC_playing(music_playing->data.flac) ) {
  1452             playing = 0;
  1453         }
  1454         break;
  1455 #endif
  1456 #ifdef MP3_MUSIC
  1457         case MUS_MP3:
  1458         if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1459             playing = 0;
  1460         break;
  1461 #endif
  1462 #ifdef MP3_MAD_MUSIC
  1463         case MUS_MP3_MAD:
  1464         if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1465             playing = 0;
  1466         }
  1467         break;
  1468 #endif
  1469         default:
  1470         playing = 0;
  1471         break;
  1472     }
  1473 
  1474 skip:
  1475     return(playing);
  1476 }
  1477 int Mix_PlayingMusic(void)
  1478 {
  1479     int playing = 0;
  1480 
  1481     SDL_LockAudio();
  1482     if ( music_playing ) {
  1483         playing = music_loops || music_internal_playing();
  1484     }
  1485     SDL_UnlockAudio();
  1486 
  1487     return(playing);
  1488 }
  1489 
  1490 /* Set the external music playback command */
  1491 int Mix_SetMusicCMD(const char *command)
  1492 {
  1493     Mix_HaltMusic();
  1494     if ( music_cmd ) {
  1495         SDL_free(music_cmd);
  1496         music_cmd = NULL;
  1497     }
  1498     if ( command ) {
  1499         music_cmd = (char *)SDL_malloc(strlen(command)+1);
  1500         if ( music_cmd == NULL ) {
  1501             return(-1);
  1502         }
  1503         strcpy(music_cmd, command);
  1504     }
  1505     return(0);
  1506 }
  1507 
  1508 int Mix_SetSynchroValue(int i)
  1509 {
  1510     /* Not supported by any players at this time */
  1511     return(-1);
  1512 }
  1513 
  1514 int Mix_GetSynchroValue(void)
  1515 {
  1516     /* Not supported by any players at this time */
  1517     return(-1);
  1518 }
  1519 
  1520 
  1521 /* Uninitialize the music players */
  1522 void close_music(void)
  1523 {
  1524     Mix_HaltMusic();
  1525 #ifdef CMD_MUSIC
  1526     Mix_SetMusicCMD(NULL);
  1527 #endif
  1528 #ifdef MODPLUG_MUSIC
  1529     modplug_exit();
  1530 #endif
  1531 #ifdef MOD_MUSIC
  1532     MOD_exit();
  1533 #endif
  1534 #ifdef MID_MUSIC
  1535 # ifdef USE_TIMIDITY_MIDI
  1536     Timidity_Close();
  1537 # endif
  1538 #endif
  1539 
  1540     /* rcg06042009 report available decoders at runtime. */
  1541     SDL_free((void *)music_decoders);
  1542     music_decoders = NULL;
  1543     num_decoders = 0;
  1544 
  1545     ms_per_step = 0;
  1546 }
  1547 
  1548 int Mix_SetSoundFonts(const char *paths)
  1549 {
  1550 #ifdef MID_MUSIC
  1551     if (soundfont_paths) {
  1552         SDL_free(soundfont_paths);
  1553         soundfont_paths = NULL;
  1554     }
  1555 
  1556     if (paths) {
  1557         if (!(soundfont_paths = SDL_strdup(paths))) {
  1558             Mix_SetError("Insufficient memory to set SoundFonts");
  1559             return 0;
  1560         }
  1561     }
  1562 #endif
  1563     return 1;
  1564 }
  1565 
  1566 #ifdef MID_MUSIC
  1567 const char* Mix_GetSoundFonts(void)
  1568 {
  1569     const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1570 
  1571     if (!soundfont_paths || (force && force[0] == '1')) {
  1572         return getenv("SDL_SOUNDFONTS");
  1573     } else {
  1574         return soundfont_paths;
  1575     }
  1576 }
  1577 
  1578 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1579 {
  1580     char *context, *path, *paths;
  1581     const char* cpaths = Mix_GetSoundFonts();
  1582 
  1583     if (!cpaths) {
  1584         Mix_SetError("No SoundFonts have been requested");
  1585         return 0;
  1586     }
  1587 
  1588     if (!(paths = SDL_strdup(cpaths))) {
  1589         Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1590         return 0;
  1591     }
  1592 
  1593 #if defined(__MINGW32__) || defined(__MINGW64__)
  1594     for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1595 #elif defined(_WIN32)
  1596     for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1597 #else
  1598     for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1599 #endif
  1600         if (!function(path, data)) {
  1601             SDL_free(paths);
  1602             return 0;
  1603         }
  1604     }
  1605 
  1606     SDL_free(paths);
  1607     return 1;
  1608 }
  1609 #endif