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