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