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