music.c
author Ozkan Sezer <sezeroz@gmail.com>
Tue, 07 Aug 2018 10:30:55 +0300
changeset 861 671a669e1065
parent 855 a7dee77dd60f
child 901 253f50984a9a
permissions -rw-r--r--
Mix_FadeInMusicPos(): fix bug #4216:

set music_active according to error returned by music_internal_play().

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