music.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 18 Jun 2013 00:44:41 -0700
changeset 644 030181ff9f59
parent 629 87c536d57d92
child 648 bd8389c6dd20
permissions -rw-r--r--
Fixed bugs 1914, 1915 - sizeof(const char**) is suspicious

Nitz

In function:
static void add_music_decoder(const char *decoder)
{
void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
}

Passing argument sizeof(char const **) to function SDL_realloc is suspicious.

Logically it should be sizeof(char const *) instead of sizeof (char const **)

In this particular case sizeof(char const **) happens to be equal to sizeof(char const *), but this is not a portable assumption.
It reduces the understanding of the user.

So Patch should be,
void *ptr=SDL_realloc(music_decoders,(num_decoders+1) * sizeof(const char *));
     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             --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 *src)
   465 {
   466     Uint8 magic[5];
   467     Uint8 moremagic[9];
   468 
   469     Sint64 start = SDL_RWtell(src);
   470     if (SDL_RWread(src, magic, 1, 4) != 4 || SDL_RWread(src, moremagic, 1, 8) != 8 ) {
   471         Mix_SetError("Couldn't read from RWops");
   472         return MUS_NONE;
   473     }
   474     SDL_RWseek(src, 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 *src;
   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     src = SDL_RWFromFile(file, "rb");
   540     if ( src == 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(src);
   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(src, type, SDL_TRUE);
   577     if ( music == NULL && Mix_GetError()[0] == '\0' ) {
   578         Mix_SetError("Unrecognized music format");
   579     }
   580     return music;
   581 }
   582 
   583 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
   584 {
   585     return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
   586 }
   587 
   588 Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
   589 {
   590     Mix_Music *music;
   591     Sint64 start;
   592 
   593     if (!src) {
   594         Mix_SetError("RWops pointer is NULL");
   595         return NULL;
   596     }
   597     start = SDL_RWtell(src);
   598 
   599     /* If the caller wants auto-detection, figure out what kind of file
   600      * this is. */
   601     if (type == MUS_NONE) {
   602         if ((type = detect_music_type(src)) == MUS_NONE) {
   603             /* Don't call Mix_SetError() here since detect_music_type()
   604              * does that. */
   605             if (freesrc) {
   606                 SDL_RWclose(src);
   607             }
   608             return NULL;
   609         }
   610     }
   611 
   612     /* Allocate memory for the music structure */
   613     music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
   614     if (music == NULL ) {
   615         Mix_SetError("Out of memory");
   616         if (freesrc) {
   617             SDL_RWclose(src);
   618         }
   619         return NULL;
   620     }
   621     music->error = 1;
   622 
   623     switch (type) {
   624 #ifdef WAV_MUSIC
   625     case MUS_WAV:
   626         music->type = MUS_WAV;
   627         music->data.wave = WAVStream_LoadSong_RW(src, freesrc);
   628         if (music->data.wave) {
   629             music->error = 0;
   630         }
   631         break;
   632 #endif
   633 #ifdef OGG_MUSIC
   634     case MUS_OGG:
   635         music->type = MUS_OGG;
   636         music->data.ogg = OGG_new_RW(src, freesrc);
   637         if (music->data.ogg) {
   638             music->error = 0;
   639         }
   640         break;
   641 #endif
   642 #ifdef FLAC_MUSIC
   643     case MUS_FLAC:
   644         music->type = MUS_FLAC;
   645         music->data.flac = FLAC_new_RW(src, freesrc);
   646         if (music->data.flac) {
   647             music->error = 0;
   648         }
   649         break;
   650 #endif
   651 #ifdef MP3_MUSIC
   652     case MUS_MP3:
   653         if (Mix_Init(MIX_INIT_MP3)) {
   654             SMPEG_Info info;
   655             music->type = MUS_MP3;
   656             music->data.mp3 = smpeg.SMPEG_new_rwops(src, &info, freesrc, 0);
   657             if (!info.has_audio) {
   658                 Mix_SetError("MPEG file does not have any audio stream.");
   659                 smpeg.SMPEG_delete(music->data.mp3);
   660                 /* Deleting the MP3 closed the source if desired */
   661                 freesrc = SDL_FALSE;
   662             } else {
   663                 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   664                 music->error = 0;
   665             }
   666         }
   667         break;
   668 #elif defined(MP3_MAD_MUSIC)
   669     case MUS_MP3:
   670         music->type = MUS_MP3_MAD;
   671         music->data.mp3_mad = mad_openFileRW(src, &used_mixer, freesrc);
   672         if (music->data.mp3_mad) {
   673             music->error = 0;
   674         } else {
   675             Mix_SetError("Could not initialize MPEG stream.");
   676         }
   677         break;
   678 #endif
   679 #ifdef MID_MUSIC
   680     case MUS_MID:
   681         music->type = MUS_MID;
   682 #ifdef USE_NATIVE_MIDI
   683         if (native_midi_ok) {
   684             SDL_RWseek(src, start, RW_SEEK_SET);
   685             music->data.nativemidi = native_midi_loadsong_RW(src, freesrc);
   686             if (music->data.nativemidi) {
   687                 music->error = 0;
   688             } else {
   689                 Mix_SetError("%s", native_midi_error());
   690             }
   691             break;
   692         }
   693 #endif
   694 #ifdef USE_FLUIDSYNTH_MIDI
   695         if (fluidsynth_ok) {
   696             SDL_RWseek(src, start, RW_SEEK_SET);
   697             music->data.fluidsynthmidi = fluidsynth_loadsong_RW(src, freesrc);
   698             if (music->data.fluidsynthmidi) {
   699                 music->error = 0;
   700             }
   701             break;
   702         }
   703 #endif
   704 #ifdef USE_TIMIDITY_MIDI
   705         if (timidity_ok) {
   706             SDL_RWseek(src, start, RW_SEEK_SET);
   707             music->data.midi = Timidity_LoadSong_RW(src, freesrc);
   708             if (music->data.midi) {
   709                 music->error = 0;
   710             } else {
   711                 Mix_SetError("%s", Timidity_Error());
   712             }
   713         } else {
   714             Mix_SetError("%s", Timidity_Error());
   715         }
   716 #endif
   717         break;
   718 #endif
   719 #if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
   720     case MUS_MOD:
   721 #ifdef MODPLUG_MUSIC
   722         if (music->error) {
   723             SDL_RWseek(src, start, RW_SEEK_SET);
   724             music->type = MUS_MODPLUG;
   725             music->data.modplug = modplug_new_RW(src, freesrc);
   726             if (music->data.modplug) {
   727                 music->error = 0;
   728             }
   729         }
   730 #endif
   731 #ifdef MOD_MUSIC
   732         if (music->error) {
   733             SDL_RWseek(src, start, RW_SEEK_SET);
   734             music->type = MUS_MOD;
   735             music->data.module = MOD_new_RW(src, freesrc);
   736             if (music->data.module) {
   737                 music->error = 0;
   738             }
   739         }
   740 #endif
   741         break;
   742 #endif
   743 
   744     default:
   745         Mix_SetError("Unrecognized music format");
   746         break;
   747     } /* switch (want) */
   748 
   749     if (music->error) {
   750         SDL_free(music);
   751         if (freesrc) {
   752             SDL_RWclose(src);
   753         } else {
   754             SDL_RWseek(src, start, RW_SEEK_SET);
   755         }
   756         music = NULL;
   757     }
   758     return music;
   759 }
   760 
   761 /* Free a music chunk previously loaded */
   762 void Mix_FreeMusic(Mix_Music *music)
   763 {
   764     if ( music ) {
   765         /* Stop the music if it's currently playing */
   766         SDL_LockAudio();
   767         if ( music == music_playing ) {
   768             /* Wait for any fade out to finish */
   769             while ( music->fading == MIX_FADING_OUT ) {
   770                 SDL_UnlockAudio();
   771                 SDL_Delay(100);
   772                 SDL_LockAudio();
   773             }
   774             if ( music == music_playing ) {
   775                 music_internal_halt();
   776             }
   777         }
   778         SDL_UnlockAudio();
   779         switch (music->type) {
   780 #ifdef CMD_MUSIC
   781             case MUS_CMD:
   782                 MusicCMD_FreeSong(music->data.cmd);
   783                 break;
   784 #endif
   785 #ifdef WAV_MUSIC
   786             case MUS_WAV:
   787                 WAVStream_FreeSong(music->data.wave);
   788                 break;
   789 #endif
   790 #ifdef MODPLUG_MUSIC
   791             case MUS_MODPLUG:
   792                 modplug_delete(music->data.modplug);
   793                 break;
   794 #endif
   795 #ifdef MOD_MUSIC
   796             case MUS_MOD:
   797                 MOD_delete(music->data.module);
   798                 break;
   799 #endif
   800 #ifdef MID_MUSIC
   801             case MUS_MID:
   802 #ifdef USE_NATIVE_MIDI
   803                 if ( native_midi_ok ) {
   804                     native_midi_freesong(music->data.nativemidi);
   805                     goto skip;
   806                 }
   807 #endif
   808 #ifdef USE_FLUIDSYNTH_MIDI
   809                 if ( fluidsynth_ok ) {
   810                     fluidsynth_freesong(music->data.fluidsynthmidi);
   811                     goto skip;
   812                 }
   813 #endif
   814 #ifdef USE_TIMIDITY_MIDI
   815                 if ( timidity_ok ) {
   816                     Timidity_FreeSong(music->data.midi);
   817                     goto skip;
   818                 }
   819 #endif
   820                 break;
   821 #endif
   822 #ifdef OGG_MUSIC
   823             case MUS_OGG:
   824                 OGG_delete(music->data.ogg);
   825                 break;
   826 #endif
   827 #ifdef FLAC_MUSIC
   828             case MUS_FLAC:
   829                 FLAC_delete(music->data.flac);
   830                 break;
   831 #endif
   832 #ifdef MP3_MUSIC
   833             case MUS_MP3:
   834                 smpeg.SMPEG_delete(music->data.mp3);
   835                 break;
   836 #endif
   837 #ifdef MP3_MAD_MUSIC
   838             case MUS_MP3_MAD:
   839                 mad_closeFile(music->data.mp3_mad);
   840                 break;
   841 #endif
   842             default:
   843                 /* Unknown music type?? */
   844                 break;
   845         }
   846 
   847     skip:
   848         SDL_free(music);
   849     }
   850 }
   851 
   852 /* Find out the music format of a mixer music, or the currently playing
   853    music, if 'music' is NULL.
   854 */
   855 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   856 {
   857     Mix_MusicType type = MUS_NONE;
   858 
   859     if ( music ) {
   860         type = music->type;
   861     } else {
   862         SDL_LockAudio();
   863         if ( music_playing ) {
   864             type = music_playing->type;
   865         }
   866         SDL_UnlockAudio();
   867     }
   868     return(type);
   869 }
   870 
   871 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   872  */
   873 static int music_internal_play(Mix_Music *music, double position)
   874 {
   875     int retval = 0;
   876 
   877 #if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
   878     /* This fixes a bug with native MIDI on Mac OS X, where you
   879        can't really stop and restart MIDI from the audio callback.
   880     */
   881     if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
   882         /* Just a seek suffices to restart playing */
   883         music_internal_position(position);
   884         return 0;
   885     }
   886 #endif
   887 
   888     /* Note the music we're playing */
   889     if ( music_playing ) {
   890         music_internal_halt();
   891     }
   892     music_playing = music;
   893 
   894     /* Set the initial volume */
   895     if ( music->type != MUS_MOD ) {
   896         music_internal_initialize_volume();
   897     }
   898 
   899     /* Set up for playback */
   900     switch (music->type) {
   901 #ifdef CMD_MUSIC
   902         case MUS_CMD:
   903         MusicCMD_Start(music->data.cmd);
   904         break;
   905 #endif
   906 #ifdef WAV_MUSIC
   907         case MUS_WAV:
   908         WAVStream_Start(music->data.wave);
   909         break;
   910 #endif
   911 #ifdef MODPLUG_MUSIC
   912         case MUS_MODPLUG:
   913         /* can't set volume until file is loaded, so finally set it now */
   914         music_internal_initialize_volume();
   915         modplug_play(music->data.modplug);
   916         break;
   917 #endif
   918 #ifdef MOD_MUSIC
   919         case MUS_MOD:
   920         MOD_play(music->data.module);
   921         /* Player_SetVolume() does nothing before Player_Start() */
   922         music_internal_initialize_volume();
   923         break;
   924 #endif
   925 #ifdef MID_MUSIC
   926         case MUS_MID:
   927 #ifdef USE_NATIVE_MIDI
   928         if ( native_midi_ok ) {
   929             native_midi_start(music->data.nativemidi, music_loops);
   930             goto skip;
   931         }
   932 #endif
   933 #ifdef USE_FLUIDSYNTH_MIDI
   934         if (fluidsynth_ok ) {
   935             fluidsynth_start(music->data.fluidsynthmidi);
   936             goto skip;
   937         }
   938 #endif
   939 #ifdef USE_TIMIDITY_MIDI
   940         if ( timidity_ok ) {
   941             Timidity_Start(music->data.midi);
   942             goto skip;
   943         }
   944 #endif
   945         break;
   946 #endif
   947 #ifdef OGG_MUSIC
   948         case MUS_OGG:
   949         OGG_play(music->data.ogg);
   950         break;
   951 #endif
   952 #ifdef FLAC_MUSIC
   953         case MUS_FLAC:
   954         FLAC_play(music->data.flac);
   955         break;
   956 #endif
   957 #ifdef MP3_MUSIC
   958         case MUS_MP3:
   959         smpeg.SMPEG_enableaudio(music->data.mp3,1);
   960         smpeg.SMPEG_enablevideo(music->data.mp3,0);
   961         smpeg.SMPEG_play(music_playing->data.mp3);
   962         break;
   963 #endif
   964 #ifdef MP3_MAD_MUSIC
   965         case MUS_MP3_MAD:
   966         mad_start(music->data.mp3_mad);
   967         break;
   968 #endif
   969         default:
   970         Mix_SetError("Can't play unknown music type");
   971         retval = -1;
   972         break;
   973     }
   974 
   975 skip:
   976     /* Set the playback position, note any errors if an offset is used */
   977     if ( retval == 0 ) {
   978         if ( position > 0.0 ) {
   979             if ( music_internal_position(position) < 0 ) {
   980                 Mix_SetError("Position not implemented for music type");
   981                 retval = -1;
   982             }
   983         } else {
   984             music_internal_position(0.0);
   985         }
   986     }
   987 
   988     /* If the setup failed, we're not playing any music anymore */
   989     if ( retval < 0 ) {
   990         music_playing = NULL;
   991     }
   992     return(retval);
   993 }
   994 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   995 {
   996     int retval;
   997 
   998     if ( ms_per_step == 0 ) {
   999         SDL_SetError("Audio device hasn't been opened");
  1000         return(-1);
  1001     }
  1002 
  1003     /* Don't play null pointers :-) */
  1004     if ( music == NULL ) {
  1005         Mix_SetError("music parameter was NULL");
  1006         return(-1);
  1007     }
  1008 
  1009     /* Setup the data */
  1010     if ( ms ) {
  1011         music->fading = MIX_FADING_IN;
  1012     } else {
  1013         music->fading = MIX_NO_FADING;
  1014     }
  1015     music->fade_step = 0;
  1016     music->fade_steps = ms/ms_per_step;
  1017 
  1018     /* Play the puppy */
  1019     SDL_LockAudio();
  1020     /* If the current music is fading out, wait for the fade to complete */
  1021     while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
  1022         SDL_UnlockAudio();
  1023         SDL_Delay(100);
  1024         SDL_LockAudio();
  1025     }
  1026     music_active = 1;
  1027     if (loops == 1) {
  1028         /* Loop is the number of times to play the audio */
  1029         loops = 0;
  1030     }
  1031     music_loops = loops;
  1032     retval = music_internal_play(music, position);
  1033     SDL_UnlockAudio();
  1034 
  1035     return(retval);
  1036 }
  1037 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
  1038 {
  1039     return Mix_FadeInMusicPos(music, loops, ms, 0.0);
  1040 }
  1041 int Mix_PlayMusic(Mix_Music *music, int loops)
  1042 {
  1043     return Mix_FadeInMusicPos(music, loops, 0, 0.0);
  1044 }
  1045 
  1046 /* Set the playing music position */
  1047 int music_internal_position(double position)
  1048 {
  1049     int retval = 0;
  1050 
  1051     switch (music_playing->type) {
  1052 #ifdef MODPLUG_MUSIC
  1053         case MUS_MODPLUG:
  1054         modplug_jump_to_time(music_playing->data.modplug, position);
  1055         break;
  1056 #endif
  1057 #ifdef MOD_MUSIC
  1058         case MUS_MOD:
  1059         MOD_jump_to_time(music_playing->data.module, position);
  1060         break;
  1061 #endif
  1062 #ifdef OGG_MUSIC
  1063         case MUS_OGG:
  1064         OGG_jump_to_time(music_playing->data.ogg, position);
  1065         break;
  1066 #endif
  1067 #ifdef FLAC_MUSIC
  1068         case MUS_FLAC:
  1069         FLAC_jump_to_time(music_playing->data.flac, position);
  1070         break;
  1071 #endif
  1072 #ifdef MP3_MUSIC
  1073         case MUS_MP3:
  1074         smpeg.SMPEG_rewind(music_playing->data.mp3);
  1075         smpeg.SMPEG_play(music_playing->data.mp3);
  1076         if ( position > 0.0 ) {
  1077             smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
  1078         }
  1079         break;
  1080 #endif
  1081 #ifdef MP3_MAD_MUSIC
  1082         case MUS_MP3_MAD:
  1083         mad_seek(music_playing->data.mp3_mad, position);
  1084         break;
  1085 #endif
  1086         default:
  1087         /* TODO: Implement this for other music backends */
  1088         retval = -1;
  1089         break;
  1090     }
  1091     return(retval);
  1092 }
  1093 int Mix_SetMusicPosition(double position)
  1094 {
  1095     int retval;
  1096 
  1097     SDL_LockAudio();
  1098     if ( music_playing ) {
  1099         retval = music_internal_position(position);
  1100         if ( retval < 0 ) {
  1101             Mix_SetError("Position not implemented for music type");
  1102         }
  1103     } else {
  1104         Mix_SetError("Music isn't playing");
  1105         retval = -1;
  1106     }
  1107     SDL_UnlockAudio();
  1108 
  1109     return(retval);
  1110 }
  1111 
  1112 /* Set the music's initial volume */
  1113 static void music_internal_initialize_volume(void)
  1114 {
  1115     if ( music_playing->fading == MIX_FADING_IN ) {
  1116         music_internal_volume(0);
  1117     } else {
  1118         music_internal_volume(music_volume);
  1119     }
  1120 }
  1121 
  1122 /* Set the music volume */
  1123 static void music_internal_volume(int volume)
  1124 {
  1125     switch (music_playing->type) {
  1126 #ifdef CMD_MUSIC
  1127         case MUS_CMD:
  1128         MusicCMD_SetVolume(volume);
  1129         break;
  1130 #endif
  1131 #ifdef WAV_MUSIC
  1132         case MUS_WAV:
  1133         WAVStream_SetVolume(volume);
  1134         break;
  1135 #endif
  1136 #ifdef MODPLUG_MUSIC
  1137         case MUS_MODPLUG:
  1138         modplug_setvolume(music_playing->data.modplug, volume);
  1139         break;
  1140 #endif
  1141 #ifdef MOD_MUSIC
  1142         case MUS_MOD:
  1143         MOD_setvolume(music_playing->data.module, volume);
  1144         break;
  1145 #endif
  1146 #ifdef MID_MUSIC
  1147         case MUS_MID:
  1148 #ifdef USE_NATIVE_MIDI
  1149         if ( native_midi_ok ) {
  1150             native_midi_setvolume(volume);
  1151             return;
  1152         }
  1153 #endif
  1154 #ifdef USE_FLUIDSYNTH_MIDI
  1155         if ( fluidsynth_ok ) {
  1156             fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1157             return;
  1158         }
  1159 #endif
  1160 #ifdef USE_TIMIDITY_MIDI
  1161         if ( timidity_ok ) {
  1162             Timidity_SetVolume(volume);
  1163             return;
  1164         }
  1165 #endif
  1166         break;
  1167 #endif
  1168 #ifdef OGG_MUSIC
  1169         case MUS_OGG:
  1170         OGG_setvolume(music_playing->data.ogg, volume);
  1171         break;
  1172 #endif
  1173 #ifdef FLAC_MUSIC
  1174         case MUS_FLAC:
  1175         FLAC_setvolume(music_playing->data.flac, volume);
  1176         break;
  1177 #endif
  1178 #ifdef MP3_MUSIC
  1179         case MUS_MP3:
  1180         smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1181         break;
  1182 #endif
  1183 #ifdef MP3_MAD_MUSIC
  1184         case MUS_MP3_MAD:
  1185         mad_setVolume(music_playing->data.mp3_mad, volume);
  1186         break;
  1187 #endif
  1188         default:
  1189         /* Unknown music type?? */
  1190         break;
  1191     }
  1192 }
  1193 int Mix_VolumeMusic(int volume)
  1194 {
  1195     int prev_volume;
  1196 
  1197     prev_volume = music_volume;
  1198     if ( volume < 0 ) {
  1199         return prev_volume;
  1200     }
  1201     if ( volume > SDL_MIX_MAXVOLUME ) {
  1202         volume = SDL_MIX_MAXVOLUME;
  1203     }
  1204     music_volume = volume;
  1205     SDL_LockAudio();
  1206     if ( music_playing ) {
  1207         music_internal_volume(music_volume);
  1208     }
  1209     SDL_UnlockAudio();
  1210     return(prev_volume);
  1211 }
  1212 
  1213 /* Halt playing of music */
  1214 static void music_internal_halt(void)
  1215 {
  1216     switch (music_playing->type) {
  1217 #ifdef CMD_MUSIC
  1218         case MUS_CMD:
  1219         MusicCMD_Stop(music_playing->data.cmd);
  1220         break;
  1221 #endif
  1222 #ifdef WAV_MUSIC
  1223         case MUS_WAV:
  1224         WAVStream_Stop();
  1225         break;
  1226 #endif
  1227 #ifdef MODPLUG_MUSIC
  1228         case MUS_MODPLUG:
  1229         modplug_stop(music_playing->data.modplug);
  1230         break;
  1231 #endif
  1232 #ifdef MOD_MUSIC
  1233         case MUS_MOD:
  1234         MOD_stop(music_playing->data.module);
  1235         break;
  1236 #endif
  1237 #ifdef MID_MUSIC
  1238         case MUS_MID:
  1239 #ifdef USE_NATIVE_MIDI
  1240         if ( native_midi_ok ) {
  1241             native_midi_stop();
  1242             goto skip;
  1243         }
  1244 #endif
  1245 #ifdef USE_FLUIDSYNTH_MIDI
  1246         if ( fluidsynth_ok ) {
  1247             fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1248             goto skip;
  1249         }
  1250 #endif
  1251 #ifdef USE_TIMIDITY_MIDI
  1252         if ( timidity_ok ) {
  1253             Timidity_Stop();
  1254             goto skip;
  1255         }
  1256 #endif
  1257         break;
  1258 #endif
  1259 #ifdef OGG_MUSIC
  1260         case MUS_OGG:
  1261         OGG_stop(music_playing->data.ogg);
  1262         break;
  1263 #endif
  1264 #ifdef FLAC_MUSIC
  1265         case MUS_FLAC:
  1266         FLAC_stop(music_playing->data.flac);
  1267         break;
  1268 #endif
  1269 #ifdef MP3_MUSIC
  1270         case MUS_MP3:
  1271         smpeg.SMPEG_stop(music_playing->data.mp3);
  1272         break;
  1273 #endif
  1274 #ifdef MP3_MAD_MUSIC
  1275         case MUS_MP3_MAD:
  1276         mad_stop(music_playing->data.mp3_mad);
  1277         break;
  1278 #endif
  1279         default:
  1280         /* Unknown music type?? */
  1281         return;
  1282     }
  1283 
  1284 skip:
  1285     music_playing->fading = MIX_NO_FADING;
  1286     music_playing = NULL;
  1287 }
  1288 int Mix_HaltMusic(void)
  1289 {
  1290     SDL_LockAudio();
  1291     if ( music_playing ) {
  1292         music_internal_halt();
  1293         if ( music_finished_hook ) {
  1294             music_finished_hook();
  1295         }
  1296     }
  1297     SDL_UnlockAudio();
  1298 
  1299     return(0);
  1300 }
  1301 
  1302 /* Progressively stop the music */
  1303 int Mix_FadeOutMusic(int ms)
  1304 {
  1305     int retval = 0;
  1306 
  1307     if ( ms_per_step == 0 ) {
  1308         SDL_SetError("Audio device hasn't been opened");
  1309         return 0;
  1310     }
  1311 
  1312     if (ms <= 0) {  /* just halt immediately. */
  1313         Mix_HaltMusic();
  1314         return 1;
  1315     }
  1316 
  1317     SDL_LockAudio();
  1318     if ( music_playing) {
  1319                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1320                 if ( music_playing->fading == MIX_NO_FADING ) {
  1321                 music_playing->fade_step = 0;
  1322                 } else {
  1323                         int step;
  1324                         int old_fade_steps = music_playing->fade_steps;
  1325                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1326                                 step = music_playing->fade_step;
  1327                         } else {
  1328                                 step = old_fade_steps
  1329                                         - music_playing->fade_step + 1;
  1330                         }
  1331                         music_playing->fade_step = (step * fade_steps)
  1332                                 / old_fade_steps;
  1333                 }
  1334         music_playing->fading = MIX_FADING_OUT;
  1335         music_playing->fade_steps = fade_steps;
  1336         retval = 1;
  1337     }
  1338     SDL_UnlockAudio();
  1339 
  1340     return(retval);
  1341 }
  1342 
  1343 Mix_Fading Mix_FadingMusic(void)
  1344 {
  1345     Mix_Fading fading = MIX_NO_FADING;
  1346 
  1347     SDL_LockAudio();
  1348     if ( music_playing ) {
  1349         fading = music_playing->fading;
  1350     }
  1351     SDL_UnlockAudio();
  1352 
  1353     return(fading);
  1354 }
  1355 
  1356 /* Pause/Resume the music stream */
  1357 void Mix_PauseMusic(void)
  1358 {
  1359     music_active = 0;
  1360 }
  1361 
  1362 void Mix_ResumeMusic(void)
  1363 {
  1364     music_active = 1;
  1365 }
  1366 
  1367 void Mix_RewindMusic(void)
  1368 {
  1369     Mix_SetMusicPosition(0.0);
  1370 }
  1371 
  1372 int Mix_PausedMusic(void)
  1373 {
  1374     return (music_active == 0);
  1375 }
  1376 
  1377 /* Check the status of the music */
  1378 static int music_internal_playing()
  1379 {
  1380     int playing = 1;
  1381 
  1382     if (music_playing == NULL) {
  1383         return 0;
  1384     }
  1385 
  1386     switch (music_playing->type) {
  1387 #ifdef CMD_MUSIC
  1388         case MUS_CMD:
  1389         if (!MusicCMD_Active(music_playing->data.cmd)) {
  1390             playing = 0;
  1391         }
  1392         break;
  1393 #endif
  1394 #ifdef WAV_MUSIC
  1395         case MUS_WAV:
  1396         if ( ! WAVStream_Active() ) {
  1397             playing = 0;
  1398         }
  1399         break;
  1400 #endif
  1401 #ifdef MODPLUG_MUSIC
  1402         case MUS_MODPLUG:
  1403         if ( ! modplug_playing(music_playing->data.modplug) ) {
  1404             playing = 0;
  1405         }
  1406         break;
  1407 #endif
  1408 #ifdef MOD_MUSIC
  1409         case MUS_MOD:
  1410         if ( ! MOD_playing(music_playing->data.module) ) {
  1411             playing = 0;
  1412         }
  1413         break;
  1414 #endif
  1415 #ifdef MID_MUSIC
  1416         case MUS_MID:
  1417 #ifdef USE_NATIVE_MIDI
  1418         if ( native_midi_ok ) {
  1419             if ( ! native_midi_active() )
  1420                 playing = 0;
  1421             goto skip;
  1422         }
  1423 #endif
  1424 #ifdef USE_FLUIDSYNTH_MIDI
  1425         if ( fluidsynth_ok ) {
  1426             if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1427                 playing = 0;
  1428             goto skip;
  1429         }
  1430 #endif
  1431 #ifdef USE_TIMIDITY_MIDI
  1432         if ( timidity_ok ) {
  1433             if ( ! Timidity_Active() )
  1434                 playing = 0;
  1435             goto skip;
  1436         }
  1437 #endif
  1438         break;
  1439 #endif
  1440 #ifdef OGG_MUSIC
  1441         case MUS_OGG:
  1442         if ( ! OGG_playing(music_playing->data.ogg) ) {
  1443             playing = 0;
  1444         }
  1445         break;
  1446 #endif
  1447 #ifdef FLAC_MUSIC
  1448         case MUS_FLAC:
  1449         if ( ! FLAC_playing(music_playing->data.flac) ) {
  1450             playing = 0;
  1451         }
  1452         break;
  1453 #endif
  1454 #ifdef MP3_MUSIC
  1455         case MUS_MP3:
  1456         if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1457             playing = 0;
  1458         break;
  1459 #endif
  1460 #ifdef MP3_MAD_MUSIC
  1461         case MUS_MP3_MAD:
  1462         if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1463             playing = 0;
  1464         }
  1465         break;
  1466 #endif
  1467         default:
  1468         playing = 0;
  1469         break;
  1470     }
  1471 
  1472 skip:
  1473     return(playing);
  1474 }
  1475 int Mix_PlayingMusic(void)
  1476 {
  1477     int playing = 0;
  1478 
  1479     SDL_LockAudio();
  1480     if ( music_playing ) {
  1481         playing = music_loops || music_internal_playing();
  1482     }
  1483     SDL_UnlockAudio();
  1484 
  1485     return(playing);
  1486 }
  1487 
  1488 /* Set the external music playback command */
  1489 int Mix_SetMusicCMD(const char *command)
  1490 {
  1491     Mix_HaltMusic();
  1492     if ( music_cmd ) {
  1493         SDL_free(music_cmd);
  1494         music_cmd = NULL;
  1495     }
  1496     if ( command ) {
  1497         music_cmd = (char *)SDL_malloc(strlen(command)+1);
  1498         if ( music_cmd == NULL ) {
  1499             return(-1);
  1500         }
  1501         strcpy(music_cmd, command);
  1502     }
  1503     return(0);
  1504 }
  1505 
  1506 int Mix_SetSynchroValue(int i)
  1507 {
  1508     /* Not supported by any players at this time */
  1509     return(-1);
  1510 }
  1511 
  1512 int Mix_GetSynchroValue(void)
  1513 {
  1514     /* Not supported by any players at this time */
  1515     return(-1);
  1516 }
  1517 
  1518 
  1519 /* Uninitialize the music players */
  1520 void close_music(void)
  1521 {
  1522     Mix_HaltMusic();
  1523 #ifdef CMD_MUSIC
  1524     Mix_SetMusicCMD(NULL);
  1525 #endif
  1526 #ifdef MODPLUG_MUSIC
  1527     modplug_exit();
  1528 #endif
  1529 #ifdef MOD_MUSIC
  1530     MOD_exit();
  1531 #endif
  1532 #ifdef MID_MUSIC
  1533 # ifdef USE_TIMIDITY_MIDI
  1534     Timidity_Close();
  1535 # endif
  1536 #endif
  1537 
  1538     /* rcg06042009 report available decoders at runtime. */
  1539     SDL_free((void *)music_decoders);
  1540     music_decoders = NULL;
  1541     num_decoders = 0;
  1542 
  1543     ms_per_step = 0;
  1544 }
  1545 
  1546 int Mix_SetSoundFonts(const char *paths)
  1547 {
  1548 #ifdef MID_MUSIC
  1549     if (soundfont_paths) {
  1550         SDL_free(soundfont_paths);
  1551         soundfont_paths = NULL;
  1552     }
  1553 
  1554     if (paths) {
  1555         if (!(soundfont_paths = SDL_strdup(paths))) {
  1556             Mix_SetError("Insufficient memory to set SoundFonts");
  1557             return 0;
  1558         }
  1559     }
  1560 #endif
  1561     return 1;
  1562 }
  1563 
  1564 #ifdef MID_MUSIC
  1565 const char* Mix_GetSoundFonts(void)
  1566 {
  1567     const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1568 
  1569     if (!soundfont_paths || (force && force[0] == '1')) {
  1570         return getenv("SDL_SOUNDFONTS");
  1571     } else {
  1572         return soundfont_paths;
  1573     }
  1574 }
  1575 
  1576 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1577 {
  1578     char *context, *path, *paths;
  1579     const char* cpaths = Mix_GetSoundFonts();
  1580 
  1581     if (!cpaths) {
  1582         Mix_SetError("No SoundFonts have been requested");
  1583         return 0;
  1584     }
  1585 
  1586     if (!(paths = SDL_strdup(cpaths))) {
  1587         Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1588         return 0;
  1589     }
  1590 
  1591 #if defined(__MINGW32__) || defined(__MINGW64__)
  1592     for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1593 #elif defined(_WIN32)
  1594     for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1595 #else
  1596     for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1597 #endif
  1598         if (!function(path, data)) {
  1599             SDL_free(paths);
  1600             return 0;
  1601         }
  1602     }
  1603 
  1604     SDL_free(paths);
  1605     return 1;
  1606 }
  1607 #endif