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