music.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 21 May 2013 21:09:26 -0700
changeset 616 7ead8213dfb0
parent 613 6fa075aa693e
child 621 944412baab72
permissions -rw-r--r--
Fixed bug 1833 - Memory leak issue in SDL_mixer-1.2.12/music.c file

Nitz

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