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