music.c
author Ozkan Sezer <sezeroz@gmail.com>
Fri, 15 Jun 2018 08:32:56 +0300
changeset 855 a7dee77dd60f
parent 848 3907db698eb5
child 861 671a669e1065
permissions -rw-r--r--
opus support using opusfile library (bug #4200)
     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     Mix_UnlockAudio();
   763 
   764     return(retval);
   765 }
   766 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   767 {
   768     return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   769 }
   770 int Mix_PlayMusic(Mix_Music *music, int loops)
   771 {
   772     return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   773 }
   774 
   775 /* Set the playing music position */
   776 int music_internal_position(double position)
   777 {
   778     if (music_playing->interface->Seek) {
   779         return music_playing->interface->Seek(music_playing->context, position);
   780     }
   781     return -1;
   782 }
   783 int Mix_SetMusicPosition(double position)
   784 {
   785     int retval;
   786 
   787     Mix_LockAudio();
   788     if (music_playing) {
   789         retval = music_internal_position(position);
   790         if (retval < 0) {
   791             Mix_SetError("Position not implemented for music type");
   792         }
   793     } else {
   794         Mix_SetError("Music isn't playing");
   795         retval = -1;
   796     }
   797     Mix_UnlockAudio();
   798 
   799     return(retval);
   800 }
   801 
   802 /* Set the music's initial volume */
   803 static void music_internal_initialize_volume(void)
   804 {
   805     if (music_playing->fading == MIX_FADING_IN) {
   806         music_internal_volume(0);
   807     } else {
   808         music_internal_volume(music_volume);
   809     }
   810 }
   811 
   812 /* Set the music volume */
   813 static void music_internal_volume(int volume)
   814 {
   815     if (music_playing->interface->SetVolume) {
   816         music_playing->interface->SetVolume(music_playing->context, volume);
   817     }
   818 }
   819 int Mix_VolumeMusic(int volume)
   820 {
   821     int prev_volume;
   822 
   823     prev_volume = music_volume;
   824     if (volume < 0) {
   825         return prev_volume;
   826     }
   827     if (volume > SDL_MIX_MAXVOLUME) {
   828         volume = SDL_MIX_MAXVOLUME;
   829     }
   830     music_volume = volume;
   831     Mix_LockAudio();
   832     if (music_playing) {
   833         music_internal_volume(music_volume);
   834     }
   835     Mix_UnlockAudio();
   836     return(prev_volume);
   837 }
   838 
   839 /* Halt playing of music */
   840 static void music_internal_halt(void)
   841 {
   842     if (music_playing->interface->Stop) {
   843         music_playing->interface->Stop(music_playing->context);
   844     }
   845 
   846     music_playing->playing = SDL_FALSE;
   847     music_playing->fading = MIX_NO_FADING;
   848     music_playing = NULL;
   849 }
   850 int Mix_HaltMusic(void)
   851 {
   852     Mix_LockAudio();
   853     if (music_playing) {
   854         music_internal_halt();
   855         if (music_finished_hook) {
   856             music_finished_hook();
   857         }
   858     }
   859     Mix_UnlockAudio();
   860 
   861     return(0);
   862 }
   863 
   864 /* Progressively stop the music */
   865 int Mix_FadeOutMusic(int ms)
   866 {
   867     int retval = 0;
   868 
   869     if (ms_per_step == 0) {
   870         SDL_SetError("Audio device hasn't been opened");
   871         return 0;
   872     }
   873 
   874     if (ms <= 0) {  /* just halt immediately. */
   875         Mix_HaltMusic();
   876         return 1;
   877     }
   878 
   879     Mix_LockAudio();
   880     if (music_playing) {
   881         int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
   882         if (music_playing->fading == MIX_NO_FADING) {
   883             music_playing->fade_step = 0;
   884         } else {
   885             int step;
   886             int old_fade_steps = music_playing->fade_steps;
   887             if (music_playing->fading == MIX_FADING_OUT) {
   888                 step = music_playing->fade_step;
   889             } else {
   890                 step = old_fade_steps - music_playing->fade_step + 1;
   891             }
   892             music_playing->fade_step = (step * fade_steps) / old_fade_steps;
   893         }
   894         music_playing->fading = MIX_FADING_OUT;
   895         music_playing->fade_steps = fade_steps;
   896         retval = 1;
   897     }
   898     Mix_UnlockAudio();
   899 
   900     return(retval);
   901 }
   902 
   903 Mix_Fading Mix_FadingMusic(void)
   904 {
   905     Mix_Fading fading = MIX_NO_FADING;
   906 
   907     Mix_LockAudio();
   908     if (music_playing) {
   909         fading = music_playing->fading;
   910     }
   911     Mix_UnlockAudio();
   912 
   913     return(fading);
   914 }
   915 
   916 /* Pause/Resume the music stream */
   917 void Mix_PauseMusic(void)
   918 {
   919     Mix_LockAudio();
   920     if (music_playing) {
   921         if (music_playing->interface->Pause) {
   922             music_playing->interface->Pause(music_playing->context);
   923         }
   924     }
   925     music_active = SDL_FALSE;
   926     Mix_UnlockAudio();
   927 }
   928 
   929 void Mix_ResumeMusic(void)
   930 {
   931     Mix_LockAudio();
   932     if (music_playing) {
   933         if (music_playing->interface->Resume) {
   934             music_playing->interface->Resume(music_playing->context);
   935         }
   936     }
   937     music_active = SDL_TRUE;
   938     Mix_UnlockAudio();
   939 }
   940 
   941 void Mix_RewindMusic(void)
   942 {
   943     Mix_SetMusicPosition(0.0);
   944 }
   945 
   946 int Mix_PausedMusic(void)
   947 {
   948     return (music_active == SDL_FALSE);
   949 }
   950 
   951 /* Check the status of the music */
   952 static SDL_bool music_internal_playing(void)
   953 {
   954     if (!music_playing) {
   955         return SDL_FALSE;
   956     }
   957 
   958     if (music_playing->interface->IsPlaying) {
   959         music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
   960     }
   961     return music_playing->playing;
   962 }
   963 int Mix_PlayingMusic(void)
   964 {
   965     SDL_bool playing;
   966 
   967     Mix_LockAudio();
   968     playing = music_internal_playing();
   969     Mix_UnlockAudio();
   970 
   971     return playing ? 1 : 0;
   972 }
   973 
   974 /* Set the external music playback command */
   975 int Mix_SetMusicCMD(const char *command)
   976 {
   977     Mix_HaltMusic();
   978     if (music_cmd) {
   979         SDL_free(music_cmd);
   980         music_cmd = NULL;
   981     }
   982     if (command) {
   983         size_t length = SDL_strlen(command) + 1;
   984         music_cmd = (char *)SDL_malloc(length);
   985         if (music_cmd == NULL) {
   986             return SDL_OutOfMemory();
   987         }
   988         SDL_memcpy(music_cmd, command, length);
   989     }
   990     return 0;
   991 }
   992 
   993 int Mix_SetSynchroValue(int i)
   994 {
   995     /* Not supported by any players at this time */
   996     return(-1);
   997 }
   998 
   999 int Mix_GetSynchroValue(void)
  1000 {
  1001     /* Not supported by any players at this time */
  1002     return(-1);
  1003 }
  1004 
  1005 
  1006 /* Uninitialize the music interfaces */
  1007 void close_music(void)
  1008 {
  1009     int i;
  1010 
  1011     Mix_HaltMusic();
  1012 
  1013     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1014         Mix_MusicInterface *interface = s_music_interfaces[i];
  1015         if (!interface || !interface->opened) {
  1016             continue;
  1017         }
  1018 
  1019         if (interface->Close) {
  1020             interface->Close();
  1021         }
  1022         interface->opened = SDL_FALSE;
  1023     }
  1024 
  1025     if (soundfont_paths) {
  1026         SDL_free(soundfont_paths);
  1027         soundfont_paths = NULL;
  1028     }
  1029 
  1030     /* rcg06042009 report available decoders at runtime. */
  1031     if (music_decoders) {
  1032         SDL_free((void *)music_decoders);
  1033         music_decoders = NULL;
  1034     }
  1035     num_decoders = 0;
  1036 
  1037     ms_per_step = 0;
  1038 }
  1039 
  1040 /* Unload the music interface libraries */
  1041 void unload_music(void)
  1042 {
  1043     int i;
  1044     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1045         Mix_MusicInterface *interface = s_music_interfaces[i];
  1046         if (!interface || !interface->loaded) {
  1047             continue;
  1048         }
  1049 
  1050         if (interface->Unload) {
  1051             interface->Unload();
  1052         }
  1053         interface->loaded = SDL_FALSE;
  1054     }
  1055 }
  1056 
  1057 int Mix_SetSoundFonts(const char *paths)
  1058 {
  1059     if (soundfont_paths) {
  1060         SDL_free(soundfont_paths);
  1061         soundfont_paths = NULL;
  1062     }
  1063 
  1064     if (paths) {
  1065         if (!(soundfont_paths = SDL_strdup(paths))) {
  1066             Mix_SetError("Insufficient memory to set SoundFonts");
  1067             return 0;
  1068         }
  1069     }
  1070     return 1;
  1071 }
  1072 
  1073 const char* Mix_GetSoundFonts(void)
  1074 {
  1075     const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
  1076     SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
  1077     if (force_env_paths && (!env_paths || !*env_paths)) {
  1078         force_env_paths = SDL_FALSE;
  1079     }
  1080     if (soundfont_paths && *soundfont_paths && !force_env_paths) {
  1081         return soundfont_paths;
  1082     }
  1083     if (env_paths) {
  1084         return env_paths;
  1085     }
  1086 
  1087     /* We don't have any sound fonts set programmatically or in the environment
  1088        Time to start guessing where they might be...
  1089      */
  1090     {
  1091         static char *s_soundfont_paths[] = {
  1092             "/usr/share/sounds/sf2/FluidR3_GM.sf2"  /* Remember to add ',' here */
  1093         };
  1094         unsigned i;
  1095 
  1096         for (i = 0; i < SDL_arraysize(s_soundfont_paths); ++i) {
  1097             SDL_RWops *rwops = SDL_RWFromFile(s_soundfont_paths[i], "rb");
  1098             if (rwops) {
  1099                 SDL_RWclose(rwops);
  1100                 return s_soundfont_paths[i];
  1101             }
  1102         }
  1103     }
  1104     return NULL;
  1105 }
  1106 
  1107 int Mix_EachSoundFont(int (SDLCALL *function)(const char*, void*), void *data)
  1108 {
  1109     char *context, *path, *paths;
  1110     const char* cpaths = Mix_GetSoundFonts();
  1111     int soundfonts_found = 0;
  1112 
  1113     if (!cpaths) {
  1114         Mix_SetError("No SoundFonts have been requested");
  1115         return 0;
  1116     }
  1117 
  1118     if (!(paths = SDL_strdup(cpaths))) {
  1119         Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1120         return 0;
  1121     }
  1122 
  1123 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__)
  1124     for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1125 #elif defined(_WIN32)
  1126     for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1127 #else
  1128     for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1129 #endif
  1130         if (!function(path, data)) {
  1131             continue;
  1132         } else {
  1133             soundfonts_found++;
  1134         }
  1135     }
  1136 
  1137     SDL_free(paths);
  1138     if (soundfonts_found > 0)
  1139         return 1;
  1140     else
  1141         return 0;
  1142 }
  1143 
  1144 /* vi: set ts=4 sw=4 expandtab: */