music.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 14 Oct 2017 01:49:37 -0700
changeset 766 1e215d1f9492
parent 762 6c6adcc85536
child 770 74a0ac03a448
permissions -rw-r--r--
The soundfont API functions are public and should always be available.

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