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