music.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Oct 2017 02:35:44 -0700
changeset 802 98ee7bc3833a
parent 801 46acd70caa6a
child 813 e52b611d3a6f
permissions -rw-r--r--
Added some debugging to test float audio with playmus and show the music interfaces being used.
     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 #ifdef DEBUG_MUSIC
   529             /* This would be useful to expose via an API */
   530             SDL_Log("Music playing with %s\n", interface->tag);
   531 #endif
   532             return music;
   533         }
   534 
   535         /* Reset the stream for the next decoder */
   536         SDL_RWseek(src, start, RW_SEEK_SET);
   537     }
   538 
   539     if (!*Mix_GetError()) {
   540         Mix_SetError("Unrecognized audio format");
   541     }
   542     if (freesrc) {
   543         SDL_RWclose(src);
   544     } else {
   545         SDL_RWseek(src, start, RW_SEEK_SET);
   546     }
   547     return NULL;
   548 }
   549 
   550 /* Free a music chunk previously loaded */
   551 void Mix_FreeMusic(Mix_Music *music)
   552 {
   553     if (music) {
   554         /* Stop the music if it's currently playing */
   555         Mix_LockAudio();
   556         if (music == music_playing) {
   557             /* Wait for any fade out to finish */
   558             while (music->fading == MIX_FADING_OUT) {
   559                 Mix_UnlockAudio();
   560                 SDL_Delay(100);
   561                 Mix_LockAudio();
   562             }
   563             if (music == music_playing) {
   564                 music_internal_halt();
   565             }
   566         }
   567         Mix_UnlockAudio();
   568 
   569         music->interface->Delete(music->context);
   570         SDL_free(music);
   571     }
   572 }
   573 
   574 /* Find out the music format of a mixer music, or the currently playing
   575    music, if 'music' is NULL.
   576 */
   577 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   578 {
   579     Mix_MusicType type = MUS_NONE;
   580 
   581     if (music) {
   582         type = music->interface->type;
   583     } else {
   584         Mix_LockAudio();
   585         if (music_playing) {
   586             type = music_playing->interface->type;
   587         }
   588         Mix_UnlockAudio();
   589     }
   590     return(type);
   591 }
   592 
   593 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   594  */
   595 static int music_internal_play(Mix_Music *music, int play_count, double position)
   596 {
   597     int retval = 0;
   598 
   599 #if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
   600     /* This fixes a bug with native MIDI on Mac OS X, where you
   601        can't really stop and restart MIDI from the audio callback.
   602     */
   603     if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
   604         /* Just a seek suffices to restart playing */
   605         music_internal_position(position);
   606         return 0;
   607     }
   608 #endif
   609 
   610     /* Note the music we're playing */
   611     if (music_playing) {
   612         music_internal_halt();
   613     }
   614     music_playing = music;
   615     music_playing->playing = SDL_TRUE;
   616 
   617     /* Set the initial volume */
   618     music_internal_initialize_volume();
   619 
   620     /* Set up for playback */
   621     retval = music->interface->Play(music->context, play_count);
   622 
   623     /* Set the playback position, note any errors if an offset is used */
   624     if (retval == 0) {
   625         if (position > 0.0) {
   626             if (music_internal_position(position) < 0) {
   627                 Mix_SetError("Position not implemented for music type");
   628                 retval = -1;
   629             }
   630         } else {
   631             music_internal_position(0.0);
   632         }
   633     }
   634 
   635     /* If the setup failed, we're not playing any music anymore */
   636     if (retval < 0) {
   637         music->playing = SDL_FALSE;
   638         music_playing = NULL;
   639     }
   640     return(retval);
   641 }
   642 
   643 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   644 {
   645     int retval;
   646 
   647     if (ms_per_step == 0) {
   648         SDL_SetError("Audio device hasn't been opened");
   649         return(-1);
   650     }
   651 
   652     /* Don't play null pointers :-) */
   653     if (music == NULL) {
   654         Mix_SetError("music parameter was NULL");
   655         return(-1);
   656     }
   657 
   658     /* Setup the data */
   659     if (ms) {
   660         music->fading = MIX_FADING_IN;
   661     } else {
   662         music->fading = MIX_NO_FADING;
   663     }
   664     music->fade_step = 0;
   665     music->fade_steps = ms/ms_per_step;
   666 
   667     /* Play the puppy */
   668     Mix_LockAudio();
   669     /* If the current music is fading out, wait for the fade to complete */
   670     while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
   671         Mix_UnlockAudio();
   672         SDL_Delay(100);
   673         Mix_LockAudio();
   674     }
   675     if (loops == 0) {
   676         /* Loop is the number of times to play the audio */
   677         loops = 1;
   678     }
   679     retval = music_internal_play(music, loops, position);
   680     Mix_UnlockAudio();
   681 
   682     return(retval);
   683 }
   684 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   685 {
   686     return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   687 }
   688 int Mix_PlayMusic(Mix_Music *music, int loops)
   689 {
   690     return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   691 }
   692 
   693 /* Set the playing music position */
   694 int music_internal_position(double position)
   695 {
   696     if (music_playing->interface->Seek) {
   697         return music_playing->interface->Seek(music_playing->context, position);
   698     }
   699     return -1;
   700 }
   701 int Mix_SetMusicPosition(double position)
   702 {
   703     int retval;
   704 
   705     Mix_LockAudio();
   706     if (music_playing) {
   707         retval = music_internal_position(position);
   708         if (retval < 0) {
   709             Mix_SetError("Position not implemented for music type");
   710         }
   711     } else {
   712         Mix_SetError("Music isn't playing");
   713         retval = -1;
   714     }
   715     Mix_UnlockAudio();
   716 
   717     return(retval);
   718 }
   719 
   720 /* Set the music's initial volume */
   721 static void music_internal_initialize_volume(void)
   722 {
   723     if (music_playing->fading == MIX_FADING_IN) {
   724         music_internal_volume(0);
   725     } else {
   726         music_internal_volume(music_volume);
   727     }
   728 }
   729 
   730 /* Set the music volume */
   731 static void music_internal_volume(int volume)
   732 {
   733     if (music_playing->interface->SetVolume) {
   734         music_playing->interface->SetVolume(music_playing->context, volume);
   735     }
   736 }
   737 int Mix_VolumeMusic(int volume)
   738 {
   739     int prev_volume;
   740 
   741     prev_volume = music_volume;
   742     if (volume < 0) {
   743         return prev_volume;
   744     }
   745     if (volume > SDL_MIX_MAXVOLUME) {
   746         volume = SDL_MIX_MAXVOLUME;
   747     }
   748     music_volume = volume;
   749     Mix_LockAudio();
   750     if (music_playing) {
   751         music_internal_volume(music_volume);
   752     }
   753     Mix_UnlockAudio();
   754     return(prev_volume);
   755 }
   756 
   757 /* Halt playing of music */
   758 static void music_internal_halt(void)
   759 {
   760     if (music_playing->interface->Stop) {
   761         music_playing->interface->Stop(music_playing->context);
   762     }
   763 
   764     music_playing->playing = SDL_FALSE;
   765     music_playing->fading = MIX_NO_FADING;
   766     music_playing = NULL;
   767 }
   768 int Mix_HaltMusic(void)
   769 {
   770     Mix_LockAudio();
   771     if (music_playing) {
   772         music_internal_halt();
   773         if (music_finished_hook) {
   774             music_finished_hook();
   775         }
   776     }
   777     Mix_UnlockAudio();
   778 
   779     return(0);
   780 }
   781 
   782 /* Progressively stop the music */
   783 int Mix_FadeOutMusic(int ms)
   784 {
   785     int retval = 0;
   786 
   787     if (ms_per_step == 0) {
   788         SDL_SetError("Audio device hasn't been opened");
   789         return 0;
   790     }
   791 
   792     if (ms <= 0) {  /* just halt immediately. */
   793         Mix_HaltMusic();
   794         return 1;
   795     }
   796 
   797     Mix_LockAudio();
   798     if (music_playing) {
   799         int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
   800         if (music_playing->fading == MIX_NO_FADING) {
   801             music_playing->fade_step = 0;
   802         } else {
   803             int step;
   804             int old_fade_steps = music_playing->fade_steps;
   805             if (music_playing->fading == MIX_FADING_OUT) {
   806                 step = music_playing->fade_step;
   807             } else {
   808                 step = old_fade_steps - music_playing->fade_step + 1;
   809             }
   810             music_playing->fade_step = (step * fade_steps) / old_fade_steps;
   811         }
   812         music_playing->fading = MIX_FADING_OUT;
   813         music_playing->fade_steps = fade_steps;
   814         retval = 1;
   815     }
   816     Mix_UnlockAudio();
   817 
   818     return(retval);
   819 }
   820 
   821 Mix_Fading Mix_FadingMusic(void)
   822 {
   823     Mix_Fading fading = MIX_NO_FADING;
   824 
   825     Mix_LockAudio();
   826     if (music_playing) {
   827         fading = music_playing->fading;
   828     }
   829     Mix_UnlockAudio();
   830 
   831     return(fading);
   832 }
   833 
   834 /* Pause/Resume the music stream */
   835 void Mix_PauseMusic(void)
   836 {
   837     Mix_LockAudio();
   838     if (music_playing) {
   839         if (music_playing->interface->Pause) {
   840             music_playing->interface->Pause(music_playing->context);
   841         }
   842     }
   843     music_active = SDL_FALSE;
   844     Mix_UnlockAudio();
   845 }
   846 
   847 void Mix_ResumeMusic(void)
   848 {
   849     Mix_LockAudio();
   850     if (music_playing) {
   851         if (music_playing->interface->Resume) {
   852             music_playing->interface->Resume(music_playing->context);
   853         }
   854     }
   855     music_active = SDL_TRUE;
   856     Mix_UnlockAudio();
   857 }
   858 
   859 void Mix_RewindMusic(void)
   860 {
   861     Mix_SetMusicPosition(0.0);
   862 }
   863 
   864 int Mix_PausedMusic(void)
   865 {
   866     return (music_active == SDL_FALSE);
   867 }
   868 
   869 /* Check the status of the music */
   870 static SDL_bool music_internal_playing(void)
   871 {
   872     if (!music_playing) {
   873         return SDL_FALSE;
   874     }
   875 
   876     if (music_playing->interface->IsPlaying) {
   877         music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
   878     }
   879     return music_playing->playing;
   880 }
   881 int Mix_PlayingMusic(void)
   882 {
   883     SDL_bool playing;
   884 
   885     Mix_LockAudio();
   886     playing = music_internal_playing();
   887     Mix_UnlockAudio();
   888 
   889     return playing ? 1 : 0;
   890 }
   891 
   892 /* Set the external music playback command */
   893 int Mix_SetMusicCMD(const char *command)
   894 {
   895     Mix_HaltMusic();
   896     if (music_cmd) {
   897         SDL_free(music_cmd);
   898         music_cmd = NULL;
   899     }
   900     if (command) {
   901         size_t length = SDL_strlen(command) + 1;
   902         music_cmd = (char *)SDL_malloc(length);
   903         if (music_cmd == NULL) {
   904             return SDL_OutOfMemory();
   905         }
   906         SDL_memcpy(music_cmd, command, length);
   907     }
   908     return 0;
   909 }
   910 
   911 int Mix_SetSynchroValue(int i)
   912 {
   913     /* Not supported by any players at this time */
   914     return(-1);
   915 }
   916 
   917 int Mix_GetSynchroValue(void)
   918 {
   919     /* Not supported by any players at this time */
   920     return(-1);
   921 }
   922 
   923 
   924 /* Uninitialize the music interfaces */
   925 void close_music(void)
   926 {
   927     int i;
   928 
   929     Mix_HaltMusic();
   930 
   931     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   932         Mix_MusicInterface *interface = s_music_interfaces[i];
   933         if (!interface || !interface->opened) {
   934             continue;
   935         }
   936 
   937         if (interface->Close) {
   938             interface->Close();
   939         }
   940         interface->opened = SDL_FALSE;
   941     }
   942 
   943     if (soundfont_paths) {
   944         SDL_free(soundfont_paths);
   945         soundfont_paths = NULL;
   946     }
   947 
   948     /* rcg06042009 report available decoders at runtime. */
   949     if (music_decoders) {
   950         SDL_free((void *)music_decoders);
   951         music_decoders = NULL;
   952     }
   953     num_decoders = 0;
   954 
   955     ms_per_step = 0;
   956 }
   957 
   958 /* Unload the music interface libraries */
   959 void unload_music(void)
   960 {
   961     int i;
   962     for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   963         Mix_MusicInterface *interface = s_music_interfaces[i];
   964         if (!interface || !interface->loaded) {
   965             continue;
   966         }
   967 
   968         if (interface->Unload) {
   969             interface->Unload();
   970         }
   971         interface->loaded = SDL_FALSE;
   972     }
   973 }
   974 
   975 int Mix_SetSoundFonts(const char *paths)
   976 {
   977     if (soundfont_paths) {
   978         SDL_free(soundfont_paths);
   979         soundfont_paths = NULL;
   980     }
   981 
   982     if (paths) {
   983         if (!(soundfont_paths = SDL_strdup(paths))) {
   984             Mix_SetError("Insufficient memory to set SoundFonts");
   985             return 0;
   986         }
   987     }
   988     return 1;
   989 }
   990 
   991 const char* Mix_GetSoundFonts(void)
   992 {
   993     const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
   994     SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
   995     if (force_env_paths && (!env_paths || !*env_paths)) {
   996         force_env_paths = SDL_FALSE;
   997     }
   998     if (soundfont_paths && *soundfont_paths && !force_env_paths) {
   999         return soundfont_paths;
  1000     }
  1001     if (env_paths) {
  1002         return env_paths;
  1003     }
  1004 
  1005     /* We don't have any sound fonts set programmatically or in the environment
  1006        Time to start guessing where they might be...
  1007      */
  1008     {
  1009         static char *s_soundfont_paths[] = {
  1010             "/usr/share/sounds/sf2/FluidR3_GM.sf2"  /* Remember to add ',' here */
  1011         };
  1012         unsigned i;
  1013 
  1014         for (i = 0; i < SDL_arraysize(s_soundfont_paths); ++i) {
  1015             SDL_RWops *rwops = SDL_RWFromFile(s_soundfont_paths[i], "rb");
  1016             if (rwops) {
  1017                 SDL_RWclose(rwops);
  1018                 return s_soundfont_paths[i];
  1019             }
  1020         }
  1021     }
  1022     return NULL;
  1023 }
  1024 
  1025 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1026 {
  1027     char *context, *path, *paths;
  1028     const char* cpaths = Mix_GetSoundFonts();
  1029     int soundfonts_found = 0;
  1030 
  1031     if (!cpaths) {
  1032         Mix_SetError("No SoundFonts have been requested");
  1033         return 0;
  1034     }
  1035 
  1036     if (!(paths = SDL_strdup(cpaths))) {
  1037         Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1038         return 0;
  1039     }
  1040 
  1041 #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__)
  1042     for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1043 #elif defined(_WIN32)
  1044     for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1045 #else
  1046     for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1047 #endif
  1048         if (!function(path, data)) {
  1049             continue;
  1050         } else {
  1051             soundfonts_found++;
  1052         }
  1053     }
  1054 
  1055     SDL_free(paths);
  1056     if (soundfonts_found > 0)
  1057         return 1;
  1058     else
  1059         return 0;
  1060 }
  1061 
  1062 /* vi: set ts=4 sw=4 expandtab: */