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