music.c
author Ozkan Sezer <sezeroz@gmail.com>
Wed, 10 Oct 2018 17:56:10 +0300
changeset 901 253f50984a9a
parent 861 671a669e1065
child 926 d6c9518fb5ee
permissions -rw-r--r--
removed smpeg support completely.
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2018 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 #include <string.h> /* for strtok() and strtok_s() */
    22 
    23 #include "SDL_hints.h"
    24 #include "SDL_log.h"
    25 #include "SDL_timer.h"
    26 
    27 #include "SDL_mixer.h"
    28 #include "mixer.h"
    29 #include "music.h"
    30 
    31 #include "music_cmd.h"
    32 #include "music_wav.h"
    33 #include "music_mikmod.h"
    34 #include "music_modplug.h"
    35 #include "music_nativemidi.h"
    36 #include "music_fluidsynth.h"
    37 #include "music_timidity.h"
    38 #include "music_ogg.h"
    39 #include "music_opus.h"
    40 #include "music_mpg123.h"
    41 #include "music_mad.h"
    42 #include "music_flac.h"
    43 #include "native_midi/native_midi.h"
    44 
    45 /* Check to make sure we are building with a new enough SDL */
    46 #if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 7)
    47 #error You need SDL 2.0.7 or newer from http://www.libsdl.org
    48 #endif
    49 
    50 /* Set this hint to true if you want verbose logging of music interfaces */
    51 #define SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES \
    52     "SDL_MIXER_DEBUG_MUSIC_INTERFACES"
    53 
    54 char *music_cmd = NULL;
    55 static SDL_bool music_active = SDL_TRUE;
    56 static int music_volume = MIX_MAX_VOLUME;
    57 static Mix_Music * volatile music_playing = NULL;
    58 SDL_AudioSpec music_spec;
    59 
    60 struct _Mix_Music {
    61     Mix_MusicInterface *interface;
    62     void *context;
    63 
    64     SDL_bool playing;
    65     Mix_Fading fading;
    66     int fade_step;
    67     int fade_steps;
    68 };
    69 
    70 /* Used to calculate fading steps */
    71 static int ms_per_step;
    72 
    73 /* rcg06042009 report available decoders at runtime. */
    74 static const char **music_decoders = NULL;
    75 static int num_decoders = 0;
    76 
    77 /* Semicolon-separated SoundFont paths */
    78 static char* soundfont_paths = NULL;
    79 
    80 /* Interfaces for the various music interfaces, ordered by priority */
    81 static Mix_MusicInterface *s_music_interfaces[] =
    82 {
    83 #ifdef MUSIC_CMD
    84     &Mix_MusicInterface_CMD,
    85 #endif
    86 #ifdef MUSIC_WAV
    87     &Mix_MusicInterface_WAV,
    88 #endif
    89 #ifdef MUSIC_FLAC
    90     &Mix_MusicInterface_FLAC,
    91 #endif
    92 #ifdef MUSIC_OGG
    93     &Mix_MusicInterface_OGG,
    94 #endif
    95 #ifdef MUSIC_OPUS
    96     &Mix_MusicInterface_Opus,
    97 #endif
    98 #ifdef MUSIC_MP3_MPG123
    99     &Mix_MusicInterface_MPG123,
   100 #endif
   101 #ifdef MUSIC_MP3_MAD
   102     &Mix_MusicInterface_MAD,
   103 #endif
   104 #ifdef MUSIC_MOD_MODPLUG
   105     &Mix_MusicInterface_MODPLUG,
   106 #endif
   107 #ifdef MUSIC_MOD_MIKMOD
   108     &Mix_MusicInterface_MIKMOD,
   109 #endif
   110 #ifdef MUSIC_MID_FLUIDSYNTH
   111     &Mix_MusicInterface_FLUIDSYNTH,
   112 #endif
   113 #ifdef MUSIC_MID_TIMIDITY
   114     &Mix_MusicInterface_TIMIDITY,
   115 #endif
   116 #ifdef MUSIC_MID_NATIVE
   117     &Mix_MusicInterface_NATIVEMIDI,
   118 #endif
   119 };
   120 
   121 int get_num_music_interfaces(void)
   122 {
   123     return SDL_arraysize(s_music_interfaces);
   124 }
   125 
   126 Mix_MusicInterface *get_music_interface(int index)
   127 {
   128     return s_music_interfaces[index];
   129 }
   130 
   131 int Mix_GetNumMusicDecoders(void)
   132 {
   133     return(num_decoders);
   134 }
   135 
   136 const char *Mix_GetMusicDecoder(int index)
   137 {
   138     if ((index < 0) || (index >= num_decoders)) {
   139         return NULL;
   140     }
   141     return(music_decoders[index]);
   142 }
   143 
   144 static void add_music_decoder(const char *decoder)
   145 {
   146     void *ptr;
   147     int i;
   148 
   149     /* Check to see if we already have this decoder */
   150     for (i = 0; i < num_decoders; ++i) {
   151         if (SDL_strcmp(music_decoders[i], decoder) == 0) {
   152             return;
   153         }
   154     }
   155 
   156     ptr = SDL_realloc((void *)music_decoders, (num_decoders + 1) * sizeof (const char *));
   157     if (ptr == NULL) {
   158         return;  /* oh well, go on without it. */
   159     }
   160     music_decoders = (const char **) ptr;
   161     music_decoders[num_decoders++] = decoder;
   162 }
   163 
   164 /* Local low-level functions prototypes */
   165 static void music_internal_initialize_volume(void);
   166 static void music_internal_volume(int volume);
   167 static int  music_internal_play(Mix_Music *music, int play_count, double position);
   168 static int  music_internal_position(double position);
   169 static SDL_bool music_internal_playing(void);
   170 static void music_internal_halt(void);
   171 
   172 
   173 /* Support for hooking when the music has finished */
   174 static void (SDLCALL *music_finished_hook)(void) = NULL;
   175 
   176 void Mix_HookMusicFinished(void (SDLCALL *music_finished)(void))
   177 {
   178     Mix_LockAudio();
   179     music_finished_hook = music_finished;
   180     Mix_UnlockAudio();
   181 }
   182 
   183 /* Convenience function to fill audio and mix at the specified volume
   184    This is called from many music player's GetAudio callback.
   185  */
   186 int music_pcm_getaudio(void *context, void *data, int bytes, int volume,
   187                        int (*GetSome)(void *context, void *data, int bytes, SDL_bool *done))
   188 {
   189     Uint8 *snd = (Uint8 *)data;
   190     Uint8 *dst;
   191     int len = bytes;
   192     SDL_bool done = SDL_FALSE;
   193 
   194     if (volume == MIX_MAX_VOLUME) {
   195         dst = snd;
   196     } else {
   197         dst = SDL_stack_alloc(Uint8, bytes);
   198     }
   199     while (len > 0 && !done) {
   200         int consumed = GetSome(context, dst, len, &done);
   201         if (consumed < 0) {
   202             break;
   203         }
   204 
   205         if (volume == MIX_MAX_VOLUME) {
   206             dst += consumed;
   207         } else {
   208             SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
   209             snd += consumed;
   210         }
   211         len -= consumed;
   212     }
   213     if (volume != MIX_MAX_VOLUME) {
   214         SDL_stack_free(dst);
   215     }
   216     return len;
   217 }
   218 
   219 /* Mixing function */
   220 void SDLCALL music_mixer(void *udata, Uint8 *stream, int len)
   221 {
   222     while (music_playing && music_active && len > 0) {
   223         /* Handle fading */
   224         if (music_playing->fading != MIX_NO_FADING) {
   225             if (music_playing->fade_step++ < music_playing->fade_steps) {
   226                 int volume;
   227                 int fade_step = music_playing->fade_step;
   228                 int fade_steps = music_playing->fade_steps;
   229 
   230                 if (music_playing->fading == MIX_FADING_OUT) {
   231                     volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
   232                 } else { /* Fading in */
   233                     volume = (music_volume * fade_step) / fade_steps;
   234                 }
   235                 music_internal_volume(volume);
   236             } else {
   237                 if (music_playing->fading == MIX_FADING_OUT) {
   238                     music_internal_halt();
   239                     if (music_finished_hook) {
   240                         music_finished_hook();
   241                     }
   242                     return;
   243                 }
   244                 music_playing->fading = MIX_NO_FADING;
   245             }
   246         }
   247 
   248         if (music_playing->interface->GetAudio) {
   249             int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
   250             if (left != 0) {
   251                 /* Either an error or finished playing with data left */
   252                 music_playing->playing = SDL_FALSE;
   253             }
   254             if (left > 0) {
   255                 stream += (len - left);
   256                 len = left;
   257             } else {
   258                 len = 0;
   259             }
   260         } else {
   261             len = 0;
   262         }
   263 
   264         if (!music_internal_playing()) {
   265             music_internal_halt();
   266             if (music_finished_hook) {
   267                 music_finished_hook();
   268             }
   269         }
   270     }
   271 }
   272 
   273 /* Load the music interface libraries for a given music type */
   274 SDL_bool load_music_type(Mix_MusicType type)
   275 {
   276     int i, loaded = 0;
   277     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   278         Mix_MusicInterface *interface = s_music_interfaces[i];
   279         if (interface->type != type) {
   280             continue;
   281         }
   282         if (!interface->loaded) {
   283             char hint[64];
   284             SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
   285             if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
   286                 continue;
   287             }
   288 
   289             if (interface->Load && interface->Load() < 0) {
   290                 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
   291                     SDL_Log("Couldn't load %s: %s\n", interface->tag, Mix_GetError());
   292                 }
   293                 continue;
   294             }
   295             interface->loaded = SDL_TRUE;
   296         }
   297         ++loaded;
   298     }
   299     return (loaded > 0) ? SDL_TRUE : SDL_FALSE;
   300 }
   301 
   302 /* Open the music interfaces for a given music type */
   303 SDL_bool open_music_type(Mix_MusicType type)
   304 {
   305     int i, opened = 0;
   306     SDL_bool use_native_midi = SDL_FALSE;
   307 
   308     if (!music_spec.format) {
   309         /* Music isn't opened yet */
   310         return SDL_FALSE;
   311     }
   312 
   313 #ifdef MUSIC_MID_NATIVE
   314     if (type == MUS_MID && SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
   315         use_native_midi = SDL_TRUE;
   316     }
   317 #endif
   318 
   319     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   320         Mix_MusicInterface *interface = s_music_interfaces[i];
   321         if (!interface->loaded) {
   322             continue;
   323         }
   324         if (type != MUS_NONE && interface->type != type) {
   325             continue;
   326         }
   327 
   328         if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
   329             continue;
   330         }
   331 
   332         if (!interface->opened) {
   333             if (interface->Open && interface->Open(&music_spec) < 0) {
   334                 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
   335                     SDL_Log("Couldn't open %s: %s\n", interface->tag, Mix_GetError());
   336                 }
   337                 continue;
   338             }
   339             interface->opened = SDL_TRUE;
   340             add_music_decoder(interface->tag);
   341         }
   342         ++opened;
   343     }
   344 
   345     if (has_music(MUS_MOD)) {
   346         add_music_decoder("MOD");
   347         add_chunk_decoder("MOD");
   348     }
   349     if (has_music(MUS_MID)) {
   350         add_music_decoder("MIDI");
   351         add_chunk_decoder("MID");
   352     }
   353     if (has_music(MUS_OGG)) {
   354         add_music_decoder("OGG");
   355         add_chunk_decoder("OGG");
   356     }
   357     if (has_music(MUS_OPUS)) {
   358         add_music_decoder("OPUS");
   359         add_chunk_decoder("OPUS");
   360     }
   361     if (has_music(MUS_MP3)) {
   362         add_music_decoder("MP3");
   363         add_chunk_decoder("MP3");
   364     }
   365     if (has_music(MUS_FLAC)) {
   366         add_music_decoder("FLAC");
   367         add_chunk_decoder("FLAC");
   368     }
   369 
   370     return (opened > 0) ? SDL_TRUE : SDL_FALSE;
   371 }
   372 
   373 /* Initialize the music interfaces with a certain desired audio format */
   374 void open_music(const SDL_AudioSpec *spec)
   375 {
   376 #ifdef MIX_INIT_SOUNDFONT_PATHS
   377     if (!soundfont_paths) {
   378         soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
   379     }
   380 #endif
   381 
   382     /* Load the music interfaces that don't have explicit initialization */
   383     load_music_type(MUS_CMD);
   384     load_music_type(MUS_WAV);
   385 
   386     /* Open all the interfaces that are loaded */
   387     music_spec = *spec;
   388     open_music_type(MUS_NONE);
   389 
   390     Mix_VolumeMusic(MIX_MAX_VOLUME);
   391 
   392     /* Calculate the number of ms for each callback */
   393     ms_per_step = (int) (((float)spec->samples * 1000.0) / spec->freq);
   394 }
   395 
   396 /* Return SDL_TRUE if the music type is available */
   397 SDL_bool has_music(Mix_MusicType type)
   398 {
   399     int i;
   400     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   401         Mix_MusicInterface *interface = s_music_interfaces[i];
   402         if (interface->type != type) {
   403             continue;
   404         }
   405         if (interface->opened) {
   406             return SDL_TRUE;
   407         }
   408     }
   409     return SDL_FALSE;
   410 }
   411 
   412 Mix_MusicType detect_music_type_from_magic(const Uint8 *magic)
   413 {
   414     /* Ogg Vorbis files have the magic four bytes "OggS" */
   415     if (SDL_memcmp(magic, "OggS", 4) == 0) {
   416         return MUS_OGG;
   417     }
   418 
   419     /* FLAC files have the magic four bytes "fLaC" */
   420     if (SDL_memcmp(magic, "fLaC", 4) == 0) {
   421         return MUS_FLAC;
   422     }
   423 
   424     /* MIDI files have the magic four bytes "MThd" */
   425     if (SDL_memcmp(magic, "MThd", 4) == 0) {
   426         return MUS_MID;
   427     }
   428 
   429     if (SDL_memcmp(magic, "ID3", 3) == 0 ||
   430         (magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
   431         return MUS_MP3;
   432     }
   433 
   434     /* Assume MOD format.
   435      *
   436      * Apparently there is no way to check if the file is really a MOD,
   437      * or there are too many formats supported by MikMod/ModPlug, or
   438      * MikMod/ModPlug does this check by itself. */
   439     return MUS_MOD;
   440 }
   441 
   442 static Mix_MusicType detect_music_type(SDL_RWops *src)
   443 {
   444     Uint8 magic[12];
   445     Mix_MusicType t;
   446 
   447     if (SDL_RWread(src, magic, 1, 12) != 12) {
   448         Mix_SetError("Couldn't read first 12 bytes of audio data");
   449         return MUS_NONE;
   450     }
   451     SDL_RWseek(src, -12, RW_SEEK_CUR);
   452 
   453     /* WAVE files have the magic four bytes "RIFF"
   454        AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
   455     if (((SDL_memcmp(magic, "RIFF", 4) == 0) && (SDL_memcmp((magic+8), "WAVE", 4) == 0)) ||
   456         (SDL_memcmp(magic, "FORM", 4) == 0)) {
   457         return MUS_WAV;
   458     }
   459     t = detect_music_type_from_magic(magic);
   460     if (t == MUS_OGG) {
   461         Sint64 pos = SDL_RWtell(src);
   462         SDL_RWseek(src, 28, RW_SEEK_CUR);
   463         SDL_RWread(src, magic, 1, 8);
   464         SDL_RWseek(src, pos, RW_SEEK_SET);
   465         if (SDL_memcmp(magic, "OpusHead", 8) == 0) {
   466             return MUS_OPUS;
   467         }
   468     }
   469     return t;
   470 }
   471 
   472 /* Load a music file */
   473 Mix_Music *Mix_LoadMUS(const char *file)
   474 {
   475     int i;
   476     void *context;
   477     char *ext;
   478     Mix_MusicType type;
   479     SDL_RWops *src;
   480 
   481     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   482         Mix_MusicInterface *interface = s_music_interfaces[i];
   483         if (!interface->opened || !interface->CreateFromFile) {
   484             continue;
   485         }
   486 
   487         context = interface->CreateFromFile(file);
   488         if (context) {
   489             /* Allocate memory for the music structure */
   490             Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
   491             if (music == NULL) {
   492                 Mix_SetError("Out of memory");
   493                 return NULL;
   494             }
   495             music->interface = interface;
   496             music->context = context;
   497             return music;
   498         }
   499     }
   500 
   501     src = SDL_RWFromFile(file, "rb");
   502     if (src == NULL) {
   503         Mix_SetError("Couldn't open '%s'", file);
   504         return NULL;
   505     }
   506 
   507     /* Use the extension as a first guess on the file type */
   508     type = MUS_NONE;
   509     ext = strrchr(file, '.');
   510     if (ext) {
   511         ++ext; /* skip the dot in the extension */
   512         if (SDL_strcasecmp(ext, "WAV") == 0) {
   513             type = MUS_WAV;
   514         } else if (SDL_strcasecmp(ext, "MID") == 0 ||
   515                     SDL_strcasecmp(ext, "MIDI") == 0 ||
   516                     SDL_strcasecmp(ext, "KAR") == 0) {
   517             type = MUS_MID;
   518         } else if (SDL_strcasecmp(ext, "OGG") == 0) {
   519             type = MUS_OGG;
   520         } else if (SDL_strcasecmp(ext, "OPUS") == 0) {
   521             type = MUS_OPUS;
   522         } else if (SDL_strcasecmp(ext, "FLAC") == 0) {
   523             type = MUS_FLAC;
   524         } else  if (SDL_strcasecmp(ext, "MPG") == 0 ||
   525                      SDL_strcasecmp(ext, "MPEG") == 0 ||
   526                      SDL_strcasecmp(ext, "MP3") == 0 ||
   527                      SDL_strcasecmp(ext, "MAD") == 0) {
   528             type = MUS_MP3;
   529         } else if (SDL_strcasecmp(ext, "669") == 0 ||
   530                     SDL_strcasecmp(ext, "AMF") == 0 ||
   531                     SDL_strcasecmp(ext, "AMS") == 0 ||
   532                     SDL_strcasecmp(ext, "DBM") == 0 ||
   533                     SDL_strcasecmp(ext, "DSM") == 0 ||
   534                     SDL_strcasecmp(ext, "FAR") == 0 ||
   535                     SDL_strcasecmp(ext, "IT") == 0 ||
   536                     SDL_strcasecmp(ext, "MED") == 0 ||
   537                     SDL_strcasecmp(ext, "MDL") == 0 ||
   538                     SDL_strcasecmp(ext, "MOD") == 0 ||
   539                     SDL_strcasecmp(ext, "MOL") == 0 ||
   540                     SDL_strcasecmp(ext, "MTM") == 0 ||
   541                     SDL_strcasecmp(ext, "NST") == 0 ||
   542                     SDL_strcasecmp(ext, "OKT") == 0 ||
   543                     SDL_strcasecmp(ext, "PTM") == 0 ||
   544                     SDL_strcasecmp(ext, "S3M") == 0 ||
   545                     SDL_strcasecmp(ext, "STM") == 0 ||
   546                     SDL_strcasecmp(ext, "ULT") == 0 ||
   547                     SDL_strcasecmp(ext, "UMX") == 0 ||
   548                     SDL_strcasecmp(ext, "WOW") == 0 ||
   549                     SDL_strcasecmp(ext, "XM") == 0) {
   550             type = MUS_MOD;
   551         }
   552     }
   553     return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
   554 }
   555 
   556 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
   557 {
   558     return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
   559 }
   560 
   561 Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
   562 {
   563     int i;
   564     void *context;
   565     Sint64 start;
   566 
   567     if (!src) {
   568         Mix_SetError("RWops pointer is NULL");
   569         return NULL;
   570     }
   571     start = SDL_RWtell(src);
   572 
   573     /* If the caller wants auto-detection, figure out what kind of file
   574      * this is. */
   575     if (type == MUS_NONE) {
   576         if ((type = detect_music_type(src)) == MUS_NONE) {
   577             /* Don't call Mix_SetError() since detect_music_type() does that. */
   578             if (freesrc) {
   579                 SDL_RWclose(src);
   580             }
   581             return NULL;
   582         }
   583     }
   584 
   585     Mix_ClearError();
   586 
   587     if (load_music_type(type) && open_music_type(type)) {
   588         for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   589             Mix_MusicInterface *interface = s_music_interfaces[i];
   590             if (!interface->opened || type != interface->type || !interface->CreateFromRW) {
   591                 continue;
   592             }
   593 
   594             context = interface->CreateFromRW(src, freesrc);
   595             if (context) {
   596                 /* Allocate memory for the music structure */
   597                 Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
   598                 if (music == NULL) {
   599                     interface->Delete(context);
   600                     Mix_SetError("Out of memory");
   601                     return NULL;
   602                 }
   603                 music->interface = interface;
   604                 music->context = context;
   605 
   606                 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
   607                     SDL_Log("Loaded music with %s\n", interface->tag);
   608                 }
   609                 return music;
   610             }
   611 
   612             /* Reset the stream for the next decoder */
   613             SDL_RWseek(src, start, RW_SEEK_SET);
   614         }
   615     }
   616 
   617     if (!*Mix_GetError()) {
   618         Mix_SetError("Unrecognized audio format");
   619     }
   620     if (freesrc) {
   621         SDL_RWclose(src);
   622     } else {
   623         SDL_RWseek(src, start, RW_SEEK_SET);
   624     }
   625     return NULL;
   626 }
   627 
   628 /* Free a music chunk previously loaded */
   629 void Mix_FreeMusic(Mix_Music *music)
   630 {
   631     if (music) {
   632         /* Stop the music if it's currently playing */
   633         Mix_LockAudio();
   634         if (music == music_playing) {
   635             /* Wait for any fade out to finish */
   636             while (music->fading == MIX_FADING_OUT) {
   637                 Mix_UnlockAudio();
   638                 SDL_Delay(100);
   639                 Mix_LockAudio();
   640             }
   641             if (music == music_playing) {
   642                 music_internal_halt();
   643             }
   644         }
   645         Mix_UnlockAudio();
   646 
   647         music->interface->Delete(music->context);
   648         SDL_free(music);
   649     }
   650 }
   651 
   652 /* Find out the music format of a mixer music, or the currently playing
   653    music, if 'music' is NULL.
   654 */
   655 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   656 {
   657     Mix_MusicType type = MUS_NONE;
   658 
   659     if (music) {
   660         type = music->interface->type;
   661     } else {
   662         Mix_LockAudio();
   663         if (music_playing) {
   664             type = music_playing->interface->type;
   665         }
   666         Mix_UnlockAudio();
   667     }
   668     return(type);
   669 }
   670 
   671 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   672  */
   673 static int music_internal_play(Mix_Music *music, int play_count, double position)
   674 {
   675     int retval = 0;
   676 
   677 #if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
   678     /* This fixes a bug with native MIDI on Mac OS X, where you
   679        can't really stop and restart MIDI from the audio callback.
   680     */
   681     if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
   682         /* Just a seek suffices to restart playing */
   683         music_internal_position(position);
   684         return 0;
   685     }
   686 #endif
   687 
   688     /* Note the music we're playing */
   689     if (music_playing) {
   690         music_internal_halt();
   691     }
   692     music_playing = music;
   693     music_playing->playing = SDL_TRUE;
   694 
   695     /* Set the initial volume */
   696     music_internal_initialize_volume();
   697 
   698     /* Set up for playback */
   699     retval = music->interface->Play(music->context, play_count);
   700 
   701     /* Set the playback position, note any errors if an offset is used */
   702     if (retval == 0) {
   703         if (position > 0.0) {
   704             if (music_internal_position(position) < 0) {
   705                 Mix_SetError("Position not implemented for music type");
   706                 retval = -1;
   707             }
   708         } else {
   709             music_internal_position(0.0);
   710         }
   711     }
   712 
   713     /* If the setup failed, we're not playing any music anymore */
   714     if (retval < 0) {
   715         music->playing = SDL_FALSE;
   716         music_playing = NULL;
   717     }
   718     return(retval);
   719 }
   720 
   721 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   722 {
   723     int retval;
   724 
   725     if (ms_per_step == 0) {
   726         SDL_SetError("Audio device hasn't been opened");
   727         return(-1);
   728     }
   729 
   730     /* Don't play null pointers :-) */
   731     if (music == NULL) {
   732         Mix_SetError("music parameter was NULL");
   733         return(-1);
   734     }
   735 
   736     /* Setup the data */
   737     if (ms) {
   738         music->fading = MIX_FADING_IN;
   739     } else {
   740         music->fading = MIX_NO_FADING;
   741     }
   742     music->fade_step = 0;
   743     music->fade_steps = ms/ms_per_step;
   744 
   745     /* Play the puppy */
   746     Mix_LockAudio();
   747     /* If the current music is fading out, wait for the fade to complete */
   748     while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
   749         Mix_UnlockAudio();
   750         SDL_Delay(100);
   751         Mix_LockAudio();
   752     }
   753     if (loops == 0) {
   754         /* Loop is the number of times to play the audio */
   755         loops = 1;
   756     }
   757     retval = music_internal_play(music, loops, position);
   758     music_active = (retval == 0);
   759     Mix_UnlockAudio();
   760 
   761     return(retval);
   762 }
   763 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   764 {
   765     return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   766 }
   767 int Mix_PlayMusic(Mix_Music *music, int loops)
   768 {
   769     return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   770 }
   771 
   772 /* Set the playing music position */
   773 int music_internal_position(double position)
   774 {
   775     if (music_playing->interface->Seek) {
   776         return music_playing->interface->Seek(music_playing->context, position);
   777     }
   778     return -1;
   779 }
   780 int Mix_SetMusicPosition(double position)
   781 {
   782     int retval;
   783 
   784     Mix_LockAudio();
   785     if (music_playing) {
   786         retval = music_internal_position(position);
   787         if (retval < 0) {
   788             Mix_SetError("Position not implemented for music type");
   789         }
   790     } else {
   791         Mix_SetError("Music isn't playing");
   792         retval = -1;
   793     }
   794     Mix_UnlockAudio();
   795 
   796     return(retval);
   797 }
   798 
   799 /* Set the music's initial volume */
   800 static void music_internal_initialize_volume(void)
   801 {
   802     if (music_playing->fading == MIX_FADING_IN) {
   803         music_internal_volume(0);
   804     } else {
   805         music_internal_volume(music_volume);
   806     }
   807 }
   808 
   809 /* Set the music volume */
   810 static void music_internal_volume(int volume)
   811 {
   812     if (music_playing->interface->SetVolume) {
   813         music_playing->interface->SetVolume(music_playing->context, volume);
   814     }
   815 }
   816 int Mix_VolumeMusic(int volume)
   817 {
   818     int prev_volume;
   819 
   820     prev_volume = music_volume;
   821     if (volume < 0) {
   822         return prev_volume;
   823     }
   824     if (volume > SDL_MIX_MAXVOLUME) {
   825         volume = SDL_MIX_MAXVOLUME;
   826     }
   827     music_volume = volume;
   828     Mix_LockAudio();
   829     if (music_playing) {
   830         music_internal_volume(music_volume);
   831     }
   832     Mix_UnlockAudio();
   833     return(prev_volume);
   834 }
   835 
   836 /* Halt playing of music */
   837 static void music_internal_halt(void)
   838 {
   839     if (music_playing->interface->Stop) {
   840         music_playing->interface->Stop(music_playing->context);
   841     }
   842 
   843     music_playing->playing = SDL_FALSE;
   844     music_playing->fading = MIX_NO_FADING;
   845     music_playing = NULL;
   846 }
   847 int Mix_HaltMusic(void)
   848 {
   849     Mix_LockAudio();
   850     if (music_playing) {
   851         music_internal_halt();
   852         if (music_finished_hook) {
   853             music_finished_hook();
   854         }
   855     }
   856     Mix_UnlockAudio();
   857 
   858     return(0);
   859 }
   860 
   861 /* Progressively stop the music */
   862 int Mix_FadeOutMusic(int ms)
   863 {
   864     int retval = 0;
   865 
   866     if (ms_per_step == 0) {
   867         SDL_SetError("Audio device hasn't been opened");
   868         return 0;
   869     }
   870 
   871     if (ms <= 0) {  /* just halt immediately. */
   872         Mix_HaltMusic();
   873         return 1;
   874     }
   875 
   876     Mix_LockAudio();
   877     if (music_playing) {
   878         int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
   879         if (music_playing->fading == MIX_NO_FADING) {
   880             music_playing->fade_step = 0;
   881         } else {
   882             int step;
   883             int old_fade_steps = music_playing->fade_steps;
   884             if (music_playing->fading == MIX_FADING_OUT) {
   885                 step = music_playing->fade_step;
   886             } else {
   887                 step = old_fade_steps - music_playing->fade_step + 1;
   888             }
   889             music_playing->fade_step = (step * fade_steps) / old_fade_steps;
   890         }
   891         music_playing->fading = MIX_FADING_OUT;
   892         music_playing->fade_steps = fade_steps;
   893         retval = 1;
   894     }
   895     Mix_UnlockAudio();
   896 
   897     return(retval);
   898 }
   899 
   900 Mix_Fading Mix_FadingMusic(void)
   901 {
   902     Mix_Fading fading = MIX_NO_FADING;
   903 
   904     Mix_LockAudio();
   905     if (music_playing) {
   906         fading = music_playing->fading;
   907     }
   908     Mix_UnlockAudio();
   909 
   910     return(fading);
   911 }
   912 
   913 /* Pause/Resume the music stream */
   914 void Mix_PauseMusic(void)
   915 {
   916     Mix_LockAudio();
   917     if (music_playing) {
   918         if (music_playing->interface->Pause) {
   919             music_playing->interface->Pause(music_playing->context);
   920         }
   921     }
   922     music_active = SDL_FALSE;
   923     Mix_UnlockAudio();
   924 }
   925 
   926 void Mix_ResumeMusic(void)
   927 {
   928     Mix_LockAudio();
   929     if (music_playing) {
   930         if (music_playing->interface->Resume) {
   931             music_playing->interface->Resume(music_playing->context);
   932         }
   933     }
   934     music_active = SDL_TRUE;
   935     Mix_UnlockAudio();
   936 }
   937 
   938 void Mix_RewindMusic(void)
   939 {
   940     Mix_SetMusicPosition(0.0);
   941 }
   942 
   943 int Mix_PausedMusic(void)
   944 {
   945     return (music_active == SDL_FALSE);
   946 }
   947 
   948 /* Check the status of the music */
   949 static SDL_bool music_internal_playing(void)
   950 {
   951     if (!music_playing) {
   952         return SDL_FALSE;
   953     }
   954 
   955     if (music_playing->interface->IsPlaying) {
   956         music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
   957     }
   958     return music_playing->playing;
   959 }
   960 int Mix_PlayingMusic(void)
   961 {
   962     SDL_bool playing;
   963 
   964     Mix_LockAudio();
   965     playing = music_internal_playing();
   966     Mix_UnlockAudio();
   967 
   968     return playing ? 1 : 0;
   969 }
   970 
   971 /* Set the external music playback command */
   972 int Mix_SetMusicCMD(const char *command)
   973 {
   974     Mix_HaltMusic();
   975     if (music_cmd) {
   976         SDL_free(music_cmd);
   977         music_cmd = NULL;
   978     }
   979     if (command) {
   980         size_t length = SDL_strlen(command) + 1;
   981         music_cmd = (char *)SDL_malloc(length);
   982         if (music_cmd == NULL) {
   983             return SDL_OutOfMemory();
   984         }
   985         SDL_memcpy(music_cmd, command, length);
   986     }
   987     return 0;
   988 }
   989 
   990 int Mix_SetSynchroValue(int i)
   991 {
   992     /* Not supported by any players at this time */
   993     return(-1);
   994 }
   995 
   996 int Mix_GetSynchroValue(void)
   997 {
   998     /* Not supported by any players at this time */
   999     return(-1);
  1000 }
  1001 
  1002 
  1003 /* Uninitialize the music interfaces */
  1004 void close_music(void)
  1005 {
  1006     int i;
  1007 
  1008     Mix_HaltMusic();
  1009 
  1010     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1011         Mix_MusicInterface *interface = s_music_interfaces[i];
  1012         if (!interface || !interface->opened) {
  1013             continue;
  1014         }
  1015 
  1016         if (interface->Close) {
  1017             interface->Close();
  1018         }
  1019         interface->opened = SDL_FALSE;
  1020     }
  1021 
  1022     if (soundfont_paths) {
  1023         SDL_free(soundfont_paths);
  1024         soundfont_paths = NULL;
  1025     }
  1026 
  1027     /* rcg06042009 report available decoders at runtime. */
  1028     if (music_decoders) {
  1029         SDL_free((void *)music_decoders);
  1030         music_decoders = NULL;
  1031     }
  1032     num_decoders = 0;
  1033 
  1034     ms_per_step = 0;
  1035 }
  1036 
  1037 /* Unload the music interface libraries */
  1038 void unload_music(void)
  1039 {
  1040     int i;
  1041     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1042         Mix_MusicInterface *interface = s_music_interfaces[i];
  1043         if (!interface || !interface->loaded) {
  1044             continue;
  1045         }
  1046 
  1047         if (interface->Unload) {
  1048             interface->Unload();
  1049         }
  1050         interface->loaded = SDL_FALSE;
  1051     }
  1052 }
  1053 
  1054 int Mix_SetSoundFonts(const char *paths)
  1055 {
  1056     if (soundfont_paths) {
  1057         SDL_free(soundfont_paths);
  1058         soundfont_paths = NULL;
  1059     }
  1060 
  1061     if (paths) {
  1062         if (!(soundfont_paths = SDL_strdup(paths))) {
  1063             Mix_SetError("Insufficient memory to set SoundFonts");
  1064             return 0;
  1065         }
  1066     }
  1067     return 1;
  1068 }
  1069 
  1070 const char* Mix_GetSoundFonts(void)
  1071 {
  1072     const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
  1073     SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
  1074     if (force_env_paths && (!env_paths || !*env_paths)) {
  1075         force_env_paths = SDL_FALSE;
  1076     }
  1077     if (soundfont_paths && *soundfont_paths && !force_env_paths) {
  1078         return soundfont_paths;
  1079     }
  1080     if (env_paths) {
  1081         return env_paths;
  1082     }
  1083 
  1084     /* We don't have any sound fonts set programmatically or in the environment
  1085        Time to start guessing where they might be...
  1086      */
  1087     {
  1088         static char *s_soundfont_paths[] = {
  1089             "/usr/share/sounds/sf2/FluidR3_GM.sf2"  /* Remember to add ',' here */
  1090         };
  1091         unsigned i;
  1092 
  1093         for (i = 0; i < SDL_arraysize(s_soundfont_paths); ++i) {
  1094             SDL_RWops *rwops = SDL_RWFromFile(s_soundfont_paths[i], "rb");
  1095             if (rwops) {
  1096                 SDL_RWclose(rwops);
  1097                 return s_soundfont_paths[i];
  1098             }
  1099         }
  1100     }
  1101     return NULL;
  1102 }
  1103 
  1104 int Mix_EachSoundFont(int (SDLCALL *function)(const char*, void*), void *data)
  1105 {
  1106     char *context, *path, *paths;
  1107     const char* cpaths = Mix_GetSoundFonts();
  1108     int soundfonts_found = 0;
  1109 
  1110     if (!cpaths) {
  1111         Mix_SetError("No SoundFonts have been requested");
  1112         return 0;
  1113     }
  1114 
  1115     if (!(paths = SDL_strdup(cpaths))) {
  1116         Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1117         return 0;
  1118     }
  1119 
  1120 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__)
  1121     for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1122 #elif defined(_WIN32)
  1123     for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1124 #else
  1125     for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1126 #endif
  1127         if (!function(path, data)) {
  1128             continue;
  1129         } else {
  1130             soundfonts_found++;
  1131         }
  1132     }
  1133 
  1134     SDL_free(paths);
  1135     if (soundfonts_found > 0)
  1136         return 1;
  1137     else
  1138         return 0;
  1139 }
  1140 
  1141 /* vi: set ts=4 sw=4 expandtab: */