blob: dce16a9de3f3e93b030e24e4e9b7c61ec4f78f75 [file] [log] [blame]
Franklin Weia855d622017-01-21 15:18:31 -05001/*
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2012 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
22/* $Id$ */
23
24#include <ctype.h>
25#include "SDL_endian.h"
26#include "SDL_audio.h"
27#include "SDL_timer.h"
28
29#include "SDL_mixer.h"
30
31#ifdef CMD_MUSIC
32#include "music_cmd.h"
33#endif
34#ifdef WAV_MUSIC
35#include "wavestream.h"
36#endif
37#ifdef MODPLUG_MUSIC
38#include "music_modplug.h"
39#endif
40#ifdef MOD_MUSIC
41#include "music_mod.h"
42#endif
43#ifdef MID_MUSIC
44# ifdef USE_TIMIDITY_MIDI
45# include "timidity/timidity.h"
46# endif
47# ifdef USE_FLUIDSYNTH_MIDI
48# include "fluidsynth.h"
49# endif
50# ifdef USE_NATIVE_MIDI
51# include "native_midi.h"
52# endif
53#endif
54#ifdef OGG_MUSIC
55#include "music_ogg.h"
56#endif
57#ifdef MP3_MUSIC
58#include "dynamic_mp3.h"
59#endif
60#ifdef MP3_MAD_MUSIC
61#include "music_mad.h"
62#endif
63#ifdef FLAC_MUSIC
64#include "music_flac.h"
65#endif
66
67#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
68static SDL_AudioSpec used_mixer;
69#endif
70
71
72int volatile music_active = 1;
73static int volatile music_stopped = 0;
74static int music_loops = 0;
75static char *music_cmd = NULL;
76static Mix_Music * volatile music_playing = NULL;
77static int music_volume = MIX_MAX_VOLUME;
78
79struct _Mix_Music {
80 Mix_MusicType type;
81 union {
82#ifdef CMD_MUSIC
83 MusicCMD *cmd;
84#endif
85#ifdef WAV_MUSIC
86 WAVStream *wave;
87#endif
88#ifdef MODPLUG_MUSIC
89 modplug_data *modplug;
90#endif
91#ifdef MOD_MUSIC
92 struct MODULE *module;
93#endif
94#ifdef MID_MUSIC
95#ifdef USE_TIMIDITY_MIDI
96 MidiSong *midi;
97#endif
98#ifdef USE_FLUIDSYNTH_MIDI
99 FluidSynthMidiSong *fluidsynthmidi;
100#endif
101#ifdef USE_NATIVE_MIDI
102 NativeMidiSong *nativemidi;
103#endif
104#endif
105#ifdef OGG_MUSIC
106 OGG_music *ogg;
107#endif
108#ifdef MP3_MUSIC
109 SMPEG *mp3;
110#endif
111#ifdef MP3_MAD_MUSIC
112 mad_data *mp3_mad;
113#endif
114#ifdef FLAC_MUSIC
115 FLAC_music *flac;
116#endif
117 } data;
118 Mix_Fading fading;
119 int fade_step;
120 int fade_steps;
121 int error;
122};
123#ifdef MID_MUSIC
124#ifdef USE_TIMIDITY_MIDI
125static int timidity_ok;
126static int samplesize;
127#endif
128#ifdef USE_FLUIDSYNTH_MIDI
129static int fluidsynth_ok;
130#endif
131#ifdef USE_NATIVE_MIDI
132static int native_midi_ok;
133#endif
134#endif
135
136/* Used to calculate fading steps */
137static int ms_per_step;
138
139/* rcg06042009 report available decoders at runtime. */
140static const char **music_decoders = NULL;
141static int num_decoders = 0;
142
143/* Semicolon-separated SoundFont paths */
144#ifdef MID_MUSIC
145char* soundfont_paths = NULL;
146#endif
147
148int Mix_GetNumMusicDecoders(void)
149{
150 return(num_decoders);
151}
152
153const char *Mix_GetMusicDecoder(int index)
154{
155 if ((index < 0) || (index >= num_decoders)) {
156 return NULL;
157 }
158 return(music_decoders[index]);
159}
160
161static void add_music_decoder(const char *decoder)
162{
163 void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
164 if (ptr == NULL) {
165 return; /* oh well, go on without it. */
166 }
167 music_decoders = (const char **) ptr;
168 music_decoders[num_decoders++] = decoder;
169}
170
171/* Local low-level functions prototypes */
172static void music_internal_initialize_volume(void);
173static void music_internal_volume(int volume);
174static int music_internal_play(Mix_Music *music, double position);
175static int music_internal_position(double position);
176static int music_internal_playing();
177static void music_internal_halt(void);
178
179
180/* Support for hooking when the music has finished */
181static void (*music_finished_hook)(void) = NULL;
182
183void Mix_HookMusicFinished(void (*music_finished)(void))
184{
185 SDL_LockAudio();
186 music_finished_hook = music_finished;
187 SDL_UnlockAudio();
188}
189
190
191/* If music isn't playing, halt it if no looping is required, restart it */
192/* otherwhise. NOP if the music is playing */
193static int music_halt_or_loop (void)
194{
195 /* Restart music if it has to loop */
196
197 if (!music_internal_playing())
198 {
199#ifdef USE_NATIVE_MIDI
200 /* Native MIDI handles looping internally */
201 if (music_playing->type == MUS_MID && native_midi_ok) {
202 music_loops = 0;
203 }
204#endif
205
206 /* Restart music if it has to loop at a high level */
207 if (music_loops)
208 {
209 Mix_Fading current_fade;
210 --music_loops;
211 current_fade = music_playing->fading;
212 music_internal_play(music_playing, 0.0);
213 music_playing->fading = current_fade;
214 }
215 else
216 {
217 music_internal_halt();
218 if (music_finished_hook)
219 music_finished_hook();
220
221 return 0;
222 }
223 }
224
225 return 1;
226}
227
228
229
230/* Mixing function */
231void music_mixer(void *udata, Uint8 *stream, int len)
232{
233 //printf("music_mixer() called!\n");
234 int left = 0;
235
236 if ( music_playing && music_active ) {
237 /* Handle fading */
238 if ( music_playing->fading != MIX_NO_FADING ) {
239 if ( music_playing->fade_step++ < music_playing->fade_steps ) {
240 int volume;
241 int fade_step = music_playing->fade_step;
242 int fade_steps = music_playing->fade_steps;
243
244 if ( music_playing->fading == MIX_FADING_OUT ) {
245 volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
246 } else { /* Fading in */
247 volume = (music_volume * fade_step) / fade_steps;
248 }
249 music_internal_volume(volume);
250 } else {
251 if ( music_playing->fading == MIX_FADING_OUT ) {
252 music_internal_halt();
253 if ( music_finished_hook ) {
254 music_finished_hook();
255 }
256 return;
257 }
258 music_playing->fading = MIX_NO_FADING;
259 }
260 }
261
262 music_halt_or_loop();
263 if (!music_internal_playing())
264 return;
265
266 switch (music_playing->type) {
267#ifdef CMD_MUSIC
268 case MUS_CMD:
269 /* The playing is done externally */
270 break;
271#endif
272#ifdef WAV_MUSIC
273 case MUS_WAV:
274 left = WAVStream_PlaySome(stream, len);
275 break;
276#endif
277#ifdef MODPLUG_MUSIC
278 case MUS_MODPLUG:
279 left = modplug_playAudio(music_playing->data.modplug, stream, len);
280 break;
281#endif
282#ifdef MOD_MUSIC
283 case MUS_MOD:
284 left = MOD_playAudio(music_playing->data.module, stream, len);
285 break;
286#endif
287#ifdef MID_MUSIC
288 case MUS_MID:
289#ifdef USE_NATIVE_MIDI
290 if ( native_midi_ok ) {
291 /* Native midi is handled asynchronously */
292 goto skip;
293 }
294#endif
295#ifdef USE_FLUIDSYNTH_MIDI
296 if ( fluidsynth_ok ) {
297 fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
298 goto skip;
299 }
300#endif
301#ifdef USE_TIMIDITY_MIDI
302 if ( timidity_ok ) {
303 int samples = len / samplesize;
304 Timidity_PlaySome(stream, samples);
305 goto skip;
306 }
307#endif
308 break;
309#endif
310#ifdef OGG_MUSIC
311 case MUS_OGG:
312
313 left = OGG_playAudio(music_playing->data.ogg, stream, len);
314 break;
315#endif
316#ifdef FLAC_MUSIC
317 case MUS_FLAC:
318 left = FLAC_playAudio(music_playing->data.flac, stream, len);
319 break;
320#endif
321#ifdef MP3_MUSIC
322 case MUS_MP3:
323 left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
324 break;
325#endif
326#ifdef MP3_MAD_MUSIC
327 case MUS_MP3_MAD:
328 left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
329 break;
330#endif
331 default:
332 /* Unknown music type?? */
333 break;
334 }
335 }
336
337
338skip:
339 /* Handle seamless music looping */
340 if (left > 0 && left < len) {
341 music_halt_or_loop();
342 if (music_internal_playing())
343 music_mixer(udata, stream+(len-left), left);
344 }
345 //printf("sample 0: %d %d", stream[0], stream[1]);
346}
347
348/* Initialize the music players with a certain desired audio format */
349int open_music(SDL_AudioSpec *mixer)
350{
351#ifdef WAV_MUSIC
352 if ( WAVStream_Init(mixer) == 0 ) {
353 add_music_decoder("WAVE");
354 }
355#endif
356#ifdef MODPLUG_MUSIC
357 if ( modplug_init(mixer) == 0 ) {
358 add_music_decoder("MODPLUG");
359 }
360#endif
361#ifdef MOD_MUSIC
362 if ( MOD_init(mixer) == 0 ) {
363 add_music_decoder("MIKMOD");
364 }
365#endif
366#ifdef MID_MUSIC
367#ifdef USE_TIMIDITY_MIDI
368 samplesize = mixer->size / mixer->samples;
369 if ( Timidity_Init(mixer->freq, mixer->format,
370 mixer->channels, mixer->samples) == 0 ) {
371 timidity_ok = 1;
372 add_music_decoder("TIMIDITY");
373 } else {
374 timidity_ok = 0;
375 }
376#endif
377#ifdef USE_FLUIDSYNTH_MIDI
378 if ( fluidsynth_init(mixer) == 0 ) {
379 fluidsynth_ok = 1;
380 add_music_decoder("FLUIDSYNTH");
381 } else {
382 fluidsynth_ok = 0;
383 }
384#endif
385#ifdef USE_NATIVE_MIDI
386#ifdef USE_FLUIDSYNTH_MIDI
387 native_midi_ok = !fluidsynth_ok;
388 if ( native_midi_ok )
389#endif
390#ifdef USE_TIMIDITY_MIDI
391 native_midi_ok = !timidity_ok;
392 if ( !native_midi_ok ) {
393 native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
394 }
395 if ( native_midi_ok )
396#endif
397 native_midi_ok = native_midi_detect();
398 if ( native_midi_ok )
399 add_music_decoder("NATIVEMIDI");
400#endif
401#endif
402#ifdef OGG_MUSIC
403 if ( OGG_init(mixer) == 0 ) {
404 add_music_decoder("OGG");
405 }
406#endif
407#ifdef FLAC_MUSIC
408 if ( FLAC_init(mixer) == 0 ) {
409 add_music_decoder("FLAC");
410 }
411#endif
412#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
413 /* Keep a copy of the mixer */
414 used_mixer = *mixer;
415 add_music_decoder("MP3");
416#endif
417
418 music_playing = NULL;
419 music_stopped = 0;
420 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
421
422 /* Calculate the number of ms for each callback */
423 ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
424
425 return(0);
426}
427
428/* Portable case-insensitive string compare function */
429int MIX_string_equals(const char *str1, const char *str2)
430{
431 while ( *str1 && *str2 ) {
432 if ( toupper((unsigned char)*str1) !=
433 toupper((unsigned char)*str2) )
434 break;
435 ++str1;
436 ++str2;
437 }
438 return (!*str1 && !*str2);
439}
440
441static int detect_mp3(Uint8 *magic)
442{
443 if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
444 return 1;
445 }
446
447 /* Detection code lifted from SMPEG */
448 if(((magic[0] & 0xff) != 0xff) || // No sync bits
449 ((magic[1] & 0xf0) != 0xf0) || //
450 ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
451 ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
452 ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
453 ((magic[1] & 0x06) == 0x00)) { // Layer is 4
454 return(0);
455 }
456 return 1;
457}
458
459/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
460 * assumed and MUS_MOD will be returned, meaning that the format might not
461 * actually be MOD-based.
462 *
463 * Returns MUS_NONE in case of errors. */
464static Mix_MusicType detect_music_type(SDL_RWops *rw)
465{
466 Uint8 magic[5];
467 Uint8 moremagic[9];
468
469 int start = SDL_RWtell(rw);
470 if (SDL_RWread(rw, magic, 1, 4) != 4 || SDL_RWread(rw, moremagic, 1, 8) != 8 ) {
471 Mix_SetError("Couldn't read from RWops");
472 return MUS_NONE;
473 }
474 SDL_RWseek(rw, start, RW_SEEK_SET);
475 magic[4]='\0';
476 moremagic[8] = '\0';
477
478 /* WAVE files have the magic four bytes "RIFF"
479 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
480 if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
481 (strcmp((char *)magic, "FORM") == 0)) {
482 return MUS_WAV;
483 }
484
485 /* Ogg Vorbis files have the magic four bytes "OggS" */
486 if (strcmp((char *)magic, "OggS") == 0) {
487 return MUS_OGG;
488 }
489
490 /* FLAC files have the magic four bytes "fLaC" */
491 if (strcmp((char *)magic, "fLaC") == 0) {
492 return MUS_FLAC;
493 }
494
495 /* MIDI files have the magic four bytes "MThd" */
496 if (strcmp((char *)magic, "MThd") == 0) {
497 return MUS_MID;
498 }
499
500 if (detect_mp3(magic)) {
501 return MUS_MP3;
502 }
503
504 /* Assume MOD format.
505 *
506 * Apparently there is no way to check if the file is really a MOD,
507 * or there are too many formats supported by MikMod/ModPlug, or
508 * MikMod/ModPlug does this check by itself. */
509 return MUS_MOD;
510}
511
512/* Load a music file */
513Mix_Music *Mix_LoadMUS(const char *file)
514{
515 SDL_RWops *rw;
516 Mix_Music *music;
517 Mix_MusicType type;
518 char *ext = strrchr(file, '.');
519
520#ifdef CMD_MUSIC
521 if ( music_cmd ) {
522 /* Allocate memory for the music structure */
523 music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
524 if ( music == NULL ) {
525 Mix_SetError("Out of memory");
526 return(NULL);
527 }
528 music->error = 0;
529 music->type = MUS_CMD;
530 music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
531 if ( music->data.cmd == NULL ) {
532 SDL_free(music);
533 music == NULL;
534 }
535 return music;
536 }
537#endif
538
539 rw = SDL_RWFromFile(file, "rb");
540 if ( rw == NULL ) {
541 Mix_SetError("Couldn't open '%s'", file);
542 return NULL;
543 }
544
545 /* Use the extension as a first guess on the file type */
546 type = MUS_NONE;
547 ext = strrchr(file, '.');
548 /* No need to guard these with #ifdef *_MUSIC stuff,
549 * since we simply call Mix_LoadMUSType_RW() later */
550 if ( ext ) {
551 ++ext; /* skip the dot in the extension */
552 if ( MIX_string_equals(ext, "WAV") ) {
553 type = MUS_WAV;
554 } else if ( MIX_string_equals(ext, "MID") ||
555 MIX_string_equals(ext, "MIDI") ||
556 MIX_string_equals(ext, "KAR") ) {
557 type = MUS_MID;
558 } else if ( MIX_string_equals(ext, "OGG") ) {
559 type = MUS_OGG;
560 } else if ( MIX_string_equals(ext, "FLAC") ) {
561 type = MUS_FLAC;
562 } else if ( MIX_string_equals(ext, "MPG") ||
563 MIX_string_equals(ext, "MPEG") ||
564 MIX_string_equals(ext, "MP3") ||
565 MIX_string_equals(ext, "MAD") ) {
566 type = MUS_MP3;
567 }
568 }
569 if ( type == MUS_NONE ) {
570 type = detect_music_type(rw);
571 }
572
573 /* We need to know if a specific error occurs; if not, we'll set a
574 * generic one, so we clear the current one. */
575 Mix_SetError("");
576 music = Mix_LoadMUSType_RW(rw, type, SDL_TRUE);
577 if ( music == NULL && Mix_GetError()[0] == '\0' ) {
578 SDL_FreeRW(rw);
579 Mix_SetError("Couldn't open '%s'", file);
580 }
581 return music;
582}
583
584Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
585{
586 return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE);
587}
588
589Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc)
590{
591 Mix_Music *music;
592
593 if (!rw) {
594 Mix_SetError("RWops pointer is NULL");
595 return NULL;
596 }
597
598 /* If the caller wants auto-detection, figure out what kind of file
599 * this is. */
600 if (type == MUS_NONE) {
601 if ((type = detect_music_type(rw)) == MUS_NONE) {
602 /* Don't call Mix_SetError() here since detect_music_type()
603 * does that. */
604 return NULL;
605 }
606 }
607
608 /* Allocate memory for the music structure */
609 music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
610 if (music == NULL ) {
611 Mix_SetError("Out of memory");
612 return NULL;
613 }
614 music->error = 0;
615
616 switch (type) {
617#ifdef WAV_MUSIC
618 case MUS_WAV:
619 /* The WAVE loader needs the first 4 bytes of the header */
620 {
621 Uint8 magic[5];
622 int start = SDL_RWtell(rw);
623 if (SDL_RWread(rw, magic, 1, 4) != 4) {
624 Mix_SetError("Couldn't read from RWops");
625 return MUS_NONE;
626 }
627 SDL_RWseek(rw, start, RW_SEEK_SET);
628 magic[4] = '\0';
629 music->type = MUS_WAV;
630 music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc);
631 }
632 if (music->data.wave == NULL) {
633 music->error = 1;
634 }
635 break;
636#endif
637#ifdef OGG_MUSIC
638 case MUS_OGG:
639 music->type = MUS_OGG;
640 music->data.ogg = OGG_new_RW(rw, freesrc);
641 if ( music->data.ogg == NULL ) {
642 music->error = 1;
643 }
644 break;
645#endif
646#ifdef FLAC_MUSIC
647 case MUS_FLAC:
648 music->type = MUS_FLAC;
649 music->data.flac = FLAC_new_RW(rw, freesrc);
650 if ( music->data.flac == NULL ) {
651 music->error = 1;
652 }
653 break;
654#endif
655#ifdef MP3_MUSIC
656 case MUS_MP3:
657 if ( Mix_Init(MIX_INIT_MP3) ) {
658 SMPEG_Info info;
659 music->type = MUS_MP3;
660 music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
661 if ( !info.has_audio ) {
662 Mix_SetError("MPEG file does not have any audio stream.");
663 music->error = 1;
664 } else {
665 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
666 }
667 } else {
668 music->error = 1;
669 }
670 break;
671#elif defined(MP3_MAD_MUSIC)
672 case MUS_MP3:
673 music->type = MUS_MP3_MAD;
674 music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc);
675 if (music->data.mp3_mad == 0) {
676 Mix_SetError("Could not initialize MPEG stream.");
677 music->error = 1;
678 }
679 break;
680#endif
681#ifdef MID_MUSIC
682 case MUS_MID:
683 music->type = MUS_MID;
684#ifdef USE_NATIVE_MIDI
685 if ( native_midi_ok ) {
686 music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc);
687 if ( music->data.nativemidi == NULL ) {
688 Mix_SetError("%s", native_midi_error());
689 music->error = 1;
690 }
691 break;
692 }
693#endif
694#ifdef USE_FLUIDSYNTH_MIDI
695 if ( fluidsynth_ok ) {
696 music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc);
697 if ( music->data.fluidsynthmidi == NULL ) {
698 music->error = 1;
699 }
700 break;
701 }
702#endif
703#ifdef USE_TIMIDITY_MIDI
704 if ( timidity_ok ) {
705 music->data.midi = Timidity_LoadSong_RW(rw, freesrc);
706 if ( music->data.midi == NULL ) {
707 Mix_SetError("%s", Timidity_Error());
708 music->error = 1;
709 }
710 //else
711 //printf("Timidity successfully loaded song!\n");
712 } else {
713 Mix_SetError("%s", Timidity_Error());
714 music->error = 1;
715 }
716#endif
717 break;
718#endif
719#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
720 case MUS_MOD:
721 music->error = 1;
722#ifdef MODPLUG_MUSIC
723 if ( music->error ) {
724 music->type = MUS_MODPLUG;
725 music->data.modplug = modplug_new_RW(rw, freesrc);
726 if ( music->data.modplug ) {
727 music->error = 0;
728 }
729 }
730#endif
731#ifdef MOD_MUSIC
732 if ( music->error ) {
733 music->type = MUS_MOD;
734 music->data.module = MOD_new_RW(rw, freesrc);
735 if ( music->data.module ) {
736 music->error = 0;
737 }
738 }
739#endif
740 break;
741#endif
742
743 default:
744 Mix_SetError("Unrecognized music format");
745 music->error=1;
746 } /* switch (want) */
747
748
749 if (music->error) {
750 SDL_free(music);
751 music=NULL;
752 }
753 return(music);
754}
755
756/* Free a music chunk previously loaded */
757void Mix_FreeMusic(Mix_Music *music)
758{
759 if ( music ) {
760 /* Stop the music if it's currently playing */
761 SDL_LockAudio();
762 if ( music == music_playing ) {
763 /* Wait for any fade out to finish */
764 while ( music->fading == MIX_FADING_OUT ) {
765 SDL_UnlockAudio();
766 SDL_Delay(100);
767 SDL_LockAudio();
768 }
769 if ( music == music_playing ) {
770 music_internal_halt();
771 }
772 }
773 SDL_UnlockAudio();
774 switch (music->type) {
775#ifdef CMD_MUSIC
776 case MUS_CMD:
777 MusicCMD_FreeSong(music->data.cmd);
778 break;
779#endif
780#ifdef WAV_MUSIC
781 case MUS_WAV:
782 WAVStream_FreeSong(music->data.wave);
783 break;
784#endif
785#ifdef MODPLUG_MUSIC
786 case MUS_MODPLUG:
787 modplug_delete(music->data.modplug);
788 break;
789#endif
790#ifdef MOD_MUSIC
791 case MUS_MOD:
792 MOD_delete(music->data.module);
793 break;
794#endif
795#ifdef MID_MUSIC
796 case MUS_MID:
797#ifdef USE_NATIVE_MIDI
798 if ( native_midi_ok ) {
799 native_midi_freesong(music->data.nativemidi);
800 goto skip;
801 }
802#endif
803#ifdef USE_FLUIDSYNTH_MIDI
804 if ( fluidsynth_ok ) {
805 fluidsynth_freesong(music->data.fluidsynthmidi);
806 goto skip;
807 }
808#endif
809#ifdef USE_TIMIDITY_MIDI
810 if ( timidity_ok ) {
811 Timidity_FreeSong(music->data.midi);
812 goto skip;
813 }
814#endif
815 break;
816#endif
817#ifdef OGG_MUSIC
818 case MUS_OGG:
819 OGG_delete(music->data.ogg);
820 break;
821#endif
822#ifdef FLAC_MUSIC
823 case MUS_FLAC:
824 FLAC_delete(music->data.flac);
825 break;
826#endif
827#ifdef MP3_MUSIC
828 case MUS_MP3:
829 smpeg.SMPEG_delete(music->data.mp3);
830 break;
831#endif
832#ifdef MP3_MAD_MUSIC
833 case MUS_MP3_MAD:
834 mad_closeFile(music->data.mp3_mad);
835 break;
836#endif
837 default:
838 /* Unknown music type?? */
839 break;
840 }
841
842 skip:
843 SDL_free(music);
844 }
845}
846
847/* Find out the music format of a mixer music, or the currently playing
848 music, if 'music' is NULL.
849*/
850Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
851{
852 Mix_MusicType type = MUS_NONE;
853
854 if ( music ) {
855 type = music->type;
856 } else {
857 SDL_LockAudio();
858 if ( music_playing ) {
859 type = music_playing->type;
860 }
861 SDL_UnlockAudio();
862 }
863 return(type);
864}
865
866/* Play a music chunk. Returns 0, or -1 if there was an error.
867 */
868static int music_internal_play(Mix_Music *music, double position)
869{
870 int retval = 0;
871
872#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
873 /* This fixes a bug with native MIDI on Mac OS X, where you
874 can't really stop and restart MIDI from the audio callback.
875 */
876 if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
877 /* Just a seek suffices to restart playing */
878 music_internal_position(position);
879 return 0;
880 }
881#endif
882
883 /* Note the music we're playing */
884 if ( music_playing ) {
885 music_internal_halt();
886 }
887 music_playing = music;
888
889 /* Set the initial volume */
890 if ( music->type != MUS_MOD ) {
891 music_internal_initialize_volume();
892 }
893
894 /* Set up for playback */
895 switch (music->type) {
896#ifdef CMD_MUSIC
897 case MUS_CMD:
898 MusicCMD_Start(music->data.cmd);
899 break;
900#endif
901#ifdef WAV_MUSIC
902 case MUS_WAV:
903 WAVStream_Start(music->data.wave);
904 break;
905#endif
906#ifdef MODPLUG_MUSIC
907 case MUS_MODPLUG:
908 /* can't set volume until file is loaded, so finally set it now */
909 music_internal_initialize_volume();
910 modplug_play(music->data.modplug);
911 break;
912#endif
913#ifdef MOD_MUSIC
914 case MUS_MOD:
915 MOD_play(music->data.module);
916 /* Player_SetVolume() does nothing before Player_Start() */
917 music_internal_initialize_volume();
918 break;
919#endif
920#ifdef MID_MUSIC
921 case MUS_MID:
922#ifdef USE_NATIVE_MIDI
923 if ( native_midi_ok ) {
924 native_midi_start(music->data.nativemidi, music_loops);
925 goto skip;
926 }
927#endif
928#ifdef USE_FLUIDSYNTH_MIDI
929 if (fluidsynth_ok ) {
930 fluidsynth_start(music->data.fluidsynthmidi);
931 goto skip;
932 }
933#endif
934#ifdef USE_TIMIDITY_MIDI
935 if ( timidity_ok ) {
936 Timidity_Start(music->data.midi);
937 goto skip;
938 }
939#endif
940 break;
941#endif
942#ifdef OGG_MUSIC
943 case MUS_OGG:
944 OGG_play(music->data.ogg);
945 break;
946#endif
947#ifdef FLAC_MUSIC
948 case MUS_FLAC:
949 FLAC_play(music->data.flac);
950 break;
951#endif
952#ifdef MP3_MUSIC
953 case MUS_MP3:
954 smpeg.SMPEG_enableaudio(music->data.mp3,1);
955 smpeg.SMPEG_enablevideo(music->data.mp3,0);
956 smpeg.SMPEG_play(music_playing->data.mp3);
957 break;
958#endif
959#ifdef MP3_MAD_MUSIC
960 case MUS_MP3_MAD:
961 mad_start(music->data.mp3_mad);
962 break;
963#endif
964 default:
965 Mix_SetError("Can't play unknown music type");
966 retval = -1;
967 break;
968 }
969
970skip:
971 /* Set the playback position, note any errors if an offset is used */
972 if ( retval == 0 ) {
973 if ( position > 0.0 ) {
974 if ( music_internal_position(position) < 0 ) {
975 Mix_SetError("Position not implemented for music type");
976 retval = -1;
977 }
978 } else {
979 music_internal_position(0.0);
980 }
981 }
982
983 /* If the setup failed, we're not playing any music anymore */
984 if ( retval < 0 ) {
985 music_playing = NULL;
986 }
987 return(retval);
988}
989int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
990{
991 int retval;
992
993 if ( ms_per_step == 0 ) {
994 SDL_SetError("Audio device hasn't been opened");
995 return(-1);
996 }
997
998 /* Don't play null pointers :-) */
999 if ( music == NULL ) {
1000 Mix_SetError("music parameter was NULL");
1001 return(-1);
1002 }
1003
1004 /* Setup the data */
1005 if ( ms ) {
1006 music->fading = MIX_FADING_IN;
1007 } else {
1008 music->fading = MIX_NO_FADING;
1009 }
1010 music->fade_step = 0;
1011 music->fade_steps = ms/ms_per_step;
1012
1013 /* Play the puppy */
1014 SDL_LockAudio();
1015 /* If the current music is fading out, wait for the fade to complete */
1016 while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
1017 SDL_UnlockAudio();
1018 SDL_Delay(100);
1019 SDL_LockAudio();
1020 }
1021 music_active = 1;
1022 if (loops == 1) {
1023 /* Loop is the number of times to play the audio */
1024 loops = 0;
1025 }
1026 music_loops = loops;
1027 retval = music_internal_play(music, position);
1028 SDL_UnlockAudio();
1029
1030 return(retval);
1031}
1032int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
1033{
1034 return Mix_FadeInMusicPos(music, loops, ms, 0.0);
1035}
1036int Mix_PlayMusic(Mix_Music *music, int loops)
1037{
1038 return Mix_FadeInMusicPos(music, loops, 0, 0.0);
1039}
1040
1041/* Set the playing music position */
1042int music_internal_position(double position)
1043{
1044 int retval = 0;
1045
1046 switch (music_playing->type) {
1047#ifdef MODPLUG_MUSIC
1048 case MUS_MODPLUG:
1049 modplug_jump_to_time(music_playing->data.modplug, position);
1050 break;
1051#endif
1052#ifdef MOD_MUSIC
1053 case MUS_MOD:
1054 MOD_jump_to_time(music_playing->data.module, position);
1055 break;
1056#endif
1057#ifdef OGG_MUSIC
1058 case MUS_OGG:
1059 OGG_jump_to_time(music_playing->data.ogg, position);
1060 break;
1061#endif
1062#ifdef FLAC_MUSIC
1063 case MUS_FLAC:
1064 FLAC_jump_to_time(music_playing->data.flac, position);
1065 break;
1066#endif
1067#ifdef MP3_MUSIC
1068 case MUS_MP3:
1069 smpeg.SMPEG_rewind(music_playing->data.mp3);
1070 smpeg.SMPEG_play(music_playing->data.mp3);
1071 if ( position > 0.0 ) {
1072 smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
1073 }
1074 break;
1075#endif
1076#ifdef MP3_MAD_MUSIC
1077 case MUS_MP3_MAD:
1078 mad_seek(music_playing->data.mp3_mad, position);
1079 break;
1080#endif
1081 default:
1082 /* TODO: Implement this for other music backends */
1083 retval = -1;
1084 break;
1085 }
1086 return(retval);
1087}
1088int Mix_SetMusicPosition(double position)
1089{
1090 int retval;
1091
1092 SDL_LockAudio();
1093 if ( music_playing ) {
1094 retval = music_internal_position(position);
1095 if ( retval < 0 ) {
1096 Mix_SetError("Position not implemented for music type");
1097 }
1098 } else {
1099 Mix_SetError("Music isn't playing");
1100 retval = -1;
1101 }
1102 SDL_UnlockAudio();
1103
1104 return(retval);
1105}
1106
1107/* Set the music's initial volume */
1108static void music_internal_initialize_volume(void)
1109{
1110 if ( music_playing->fading == MIX_FADING_IN ) {
1111 music_internal_volume(0);
1112 } else {
1113 music_internal_volume(music_volume);
1114 }
1115}
1116
1117/* Set the music volume */
1118static void music_internal_volume(int volume)
1119{
1120 switch (music_playing->type) {
1121#ifdef CMD_MUSIC
1122 case MUS_CMD:
1123 MusicCMD_SetVolume(volume);
1124 break;
1125#endif
1126#ifdef WAV_MUSIC
1127 case MUS_WAV:
1128 WAVStream_SetVolume(volume);
1129 break;
1130#endif
1131#ifdef MODPLUG_MUSIC
1132 case MUS_MODPLUG:
1133 modplug_setvolume(music_playing->data.modplug, volume);
1134 break;
1135#endif
1136#ifdef MOD_MUSIC
1137 case MUS_MOD:
1138 MOD_setvolume(music_playing->data.module, volume);
1139 break;
1140#endif
1141#ifdef MID_MUSIC
1142 case MUS_MID:
1143#ifdef USE_NATIVE_MIDI
1144 if ( native_midi_ok ) {
1145 native_midi_setvolume(volume);
1146 return;
1147 }
1148#endif
1149#ifdef USE_FLUIDSYNTH_MIDI
1150 if ( fluidsynth_ok ) {
1151 fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
1152 return;
1153 }
1154#endif
1155#ifdef USE_TIMIDITY_MIDI
1156 if ( timidity_ok ) {
1157 Timidity_SetVolume(volume);
1158 return;
1159 }
1160#endif
1161 break;
1162#endif
1163#ifdef OGG_MUSIC
1164 case MUS_OGG:
1165 OGG_setvolume(music_playing->data.ogg, volume);
1166 break;
1167#endif
1168#ifdef FLAC_MUSIC
1169 case MUS_FLAC:
1170 FLAC_setvolume(music_playing->data.flac, volume);
1171 break;
1172#endif
1173#ifdef MP3_MUSIC
1174 case MUS_MP3:
1175 smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
1176 break;
1177#endif
1178#ifdef MP3_MAD_MUSIC
1179 case MUS_MP3_MAD:
1180 mad_setVolume(music_playing->data.mp3_mad, volume);
1181 break;
1182#endif
1183 default:
1184 /* Unknown music type?? */
1185 break;
1186 }
1187}
1188int Mix_VolumeMusic(int volume)
1189{
1190 int prev_volume;
1191
1192 prev_volume = music_volume;
1193 if ( volume < 0 ) {
1194 return prev_volume;
1195 }
1196 if ( volume > SDL_MIX_MAXVOLUME ) {
1197 volume = SDL_MIX_MAXVOLUME;
1198 }
1199 music_volume = volume;
1200 SDL_LockAudio();
1201 if ( music_playing ) {
1202 music_internal_volume(music_volume);
1203 }
1204 SDL_UnlockAudio();
1205 return(prev_volume);
1206}
1207
1208/* Halt playing of music */
1209static void music_internal_halt(void)
1210{
1211 switch (music_playing->type) {
1212#ifdef CMD_MUSIC
1213 case MUS_CMD:
1214 MusicCMD_Stop(music_playing->data.cmd);
1215 break;
1216#endif
1217#ifdef WAV_MUSIC
1218 case MUS_WAV:
1219 WAVStream_Stop();
1220 break;
1221#endif
1222#ifdef MODPLUG_MUSIC
1223 case MUS_MODPLUG:
1224 modplug_stop(music_playing->data.modplug);
1225 break;
1226#endif
1227#ifdef MOD_MUSIC
1228 case MUS_MOD:
1229 MOD_stop(music_playing->data.module);
1230 break;
1231#endif
1232#ifdef MID_MUSIC
1233 case MUS_MID:
1234#ifdef USE_NATIVE_MIDI
1235 if ( native_midi_ok ) {
1236 native_midi_stop();
1237 goto skip;
1238 }
1239#endif
1240#ifdef USE_FLUIDSYNTH_MIDI
1241 if ( fluidsynth_ok ) {
1242 fluidsynth_stop(music_playing->data.fluidsynthmidi);
1243 goto skip;
1244 }
1245#endif
1246#ifdef USE_TIMIDITY_MIDI
1247 if ( timidity_ok ) {
1248 Timidity_Stop();
1249 goto skip;
1250 }
1251#endif
1252 break;
1253#endif
1254#ifdef OGG_MUSIC
1255 case MUS_OGG:
1256 OGG_stop(music_playing->data.ogg);
1257 break;
1258#endif
1259#ifdef FLAC_MUSIC
1260 case MUS_FLAC:
1261 FLAC_stop(music_playing->data.flac);
1262 break;
1263#endif
1264#ifdef MP3_MUSIC
1265 case MUS_MP3:
1266 smpeg.SMPEG_stop(music_playing->data.mp3);
1267 break;
1268#endif
1269#ifdef MP3_MAD_MUSIC
1270 case MUS_MP3_MAD:
1271 mad_stop(music_playing->data.mp3_mad);
1272 break;
1273#endif
1274 default:
1275 /* Unknown music type?? */
1276 return;
1277 }
1278
1279skip:
1280 music_playing->fading = MIX_NO_FADING;
1281 music_playing = NULL;
1282}
1283int Mix_HaltMusic(void)
1284{
1285 SDL_LockAudio();
1286 if ( music_playing ) {
1287 music_internal_halt();
1288 }
1289 SDL_UnlockAudio();
1290
1291 return(0);
1292}
1293
1294/* Progressively stop the music */
1295int Mix_FadeOutMusic(int ms)
1296{
1297 int retval = 0;
1298
1299 if ( ms_per_step == 0 ) {
1300 SDL_SetError("Audio device hasn't been opened");
1301 return 0;
1302 }
1303
1304 if (ms <= 0) { /* just halt immediately. */
1305 Mix_HaltMusic();
1306 return 1;
1307 }
1308
1309 SDL_LockAudio();
1310 if ( music_playing) {
1311 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
1312 if ( music_playing->fading == MIX_NO_FADING ) {
1313 music_playing->fade_step = 0;
1314 } else {
1315 int step;
1316 int old_fade_steps = music_playing->fade_steps;
1317 if ( music_playing->fading == MIX_FADING_OUT ) {
1318 step = music_playing->fade_step;
1319 } else {
1320 step = old_fade_steps
1321 - music_playing->fade_step + 1;
1322 }
1323 music_playing->fade_step = (step * fade_steps)
1324 / old_fade_steps;
1325 }
1326 music_playing->fading = MIX_FADING_OUT;
1327 music_playing->fade_steps = fade_steps;
1328 retval = 1;
1329 }
1330 SDL_UnlockAudio();
1331
1332 return(retval);
1333}
1334
1335Mix_Fading Mix_FadingMusic(void)
1336{
1337 Mix_Fading fading = MIX_NO_FADING;
1338
1339 SDL_LockAudio();
1340 if ( music_playing ) {
1341 fading = music_playing->fading;
1342 }
1343 SDL_UnlockAudio();
1344
1345 return(fading);
1346}
1347
1348/* Pause/Resume the music stream */
1349void Mix_PauseMusic(void)
1350{
1351 music_active = 0;
1352}
1353
1354void Mix_ResumeMusic(void)
1355{
1356 music_active = 1;
1357}
1358
1359void Mix_RewindMusic(void)
1360{
1361 Mix_SetMusicPosition(0.0);
1362}
1363
1364int Mix_PausedMusic(void)
1365{
1366 return (music_active == 0);
1367}
1368
1369/* Check the status of the music */
1370static int music_internal_playing()
1371{
1372 int playing = 1;
1373
1374 if (music_playing == NULL) {
1375 return 0;
1376 }
1377
1378 switch (music_playing->type) {
1379#ifdef CMD_MUSIC
1380 case MUS_CMD:
1381 if (!MusicCMD_Active(music_playing->data.cmd)) {
1382 playing = 0;
1383 }
1384 break;
1385#endif
1386#ifdef WAV_MUSIC
1387 case MUS_WAV:
1388 if ( ! WAVStream_Active() ) {
1389 playing = 0;
1390 }
1391 break;
1392#endif
1393#ifdef MODPLUG_MUSIC
1394 case MUS_MODPLUG:
1395 if ( ! modplug_playing(music_playing->data.modplug) ) {
1396 playing = 0;
1397 }
1398 break;
1399#endif
1400#ifdef MOD_MUSIC
1401 case MUS_MOD:
1402 if ( ! MOD_playing(music_playing->data.module) ) {
1403 playing = 0;
1404 }
1405 break;
1406#endif
1407#ifdef MID_MUSIC
1408 case MUS_MID:
1409#ifdef USE_NATIVE_MIDI
1410 if ( native_midi_ok ) {
1411 if ( ! native_midi_active() )
1412 playing = 0;
1413 goto skip;
1414 }
1415#endif
1416#ifdef USE_FLUIDSYNTH_MIDI
1417 if ( fluidsynth_ok ) {
1418 if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
1419 playing = 0;
1420 goto skip;
1421 }
1422#endif
1423#ifdef USE_TIMIDITY_MIDI
1424 if ( timidity_ok ) {
1425 if ( ! Timidity_Active() )
1426 playing = 0;
1427 goto skip;
1428 }
1429#endif
1430 break;
1431#endif
1432#ifdef OGG_MUSIC
1433 case MUS_OGG:
1434 if ( ! OGG_playing(music_playing->data.ogg) ) {
1435 playing = 0;
1436 }
1437 break;
1438#endif
1439#ifdef FLAC_MUSIC
1440 case MUS_FLAC:
1441 if ( ! FLAC_playing(music_playing->data.flac) ) {
1442 playing = 0;
1443 }
1444 break;
1445#endif
1446#ifdef MP3_MUSIC
1447 case MUS_MP3:
1448 if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
1449 playing = 0;
1450 break;
1451#endif
1452#ifdef MP3_MAD_MUSIC
1453 case MUS_MP3_MAD:
1454 if (!mad_isPlaying(music_playing->data.mp3_mad)) {
1455 playing = 0;
1456 }
1457 break;
1458#endif
1459 default:
1460 playing = 0;
1461 break;
1462 }
1463
1464skip:
1465 return(playing);
1466}
1467int Mix_PlayingMusic(void)
1468{
1469 int playing = 0;
1470
1471 SDL_LockAudio();
1472 if ( music_playing ) {
1473 playing = music_loops || music_internal_playing();
1474 }
1475 SDL_UnlockAudio();
1476
1477 return(playing);
1478}
1479
1480/* Set the external music playback command */
1481int Mix_SetMusicCMD(const char *command)
1482{
1483 Mix_HaltMusic();
1484 if ( music_cmd ) {
1485 SDL_free(music_cmd);
1486 music_cmd = NULL;
1487 }
1488 if ( command ) {
1489 music_cmd = (char *)SDL_malloc(strlen(command)+1);
1490 if ( music_cmd == NULL ) {
1491 return(-1);
1492 }
1493 strcpy(music_cmd, command);
1494 }
1495 return(0);
1496}
1497
1498int Mix_SetSynchroValue(int i)
1499{
1500 /* Not supported by any players at this time */
1501 return(-1);
1502}
1503
1504int Mix_GetSynchroValue(void)
1505{
1506 /* Not supported by any players at this time */
1507 return(-1);
1508}
1509
1510
1511/* Uninitialize the music players */
1512void close_music(void)
1513{
1514 Mix_HaltMusic();
1515#ifdef CMD_MUSIC
1516 Mix_SetMusicCMD(NULL);
1517#endif
1518#ifdef MODPLUG_MUSIC
1519 modplug_exit();
1520#endif
1521#ifdef MOD_MUSIC
1522 MOD_exit();
1523#endif
1524#ifdef MID_MUSIC
1525# ifdef USE_TIMIDITY_MIDI
1526 Timidity_Close();
1527# endif
1528#endif
1529
1530 /* rcg06042009 report available decoders at runtime. */
1531 SDL_free(music_decoders);
1532 music_decoders = NULL;
1533 num_decoders = 0;
1534
1535 ms_per_step = 0;
1536}
1537
1538int Mix_SetSoundFonts(const char *paths)
1539{
1540#ifdef MID_MUSIC
1541 if (soundfont_paths) {
1542 SDL_free(soundfont_paths);
1543 soundfont_paths = NULL;
1544 }
1545
1546 if (paths) {
1547 if (!(soundfont_paths = SDL_strdup(paths))) {
1548 Mix_SetError("Insufficient memory to set SoundFonts");
1549 return 0;
1550 }
1551 }
1552#endif
1553 return 1;
1554}
1555
1556#ifdef MID_MUSIC
1557const char* Mix_GetSoundFonts(void)
1558{
1559 const char* force = getenv("SDL_FORCE_SOUNDFONTS");
1560
1561 if (!soundfont_paths || (force && force[0] == '1')) {
1562 return getenv("SDL_SOUNDFONTS");
1563 } else {
1564 return soundfont_paths;
1565 }
1566}
1567
1568int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
1569{
1570 char *context, *path, *paths;
1571 const char* cpaths = Mix_GetSoundFonts();
1572
1573 if (!cpaths) {
1574 Mix_SetError("No SoundFonts have been requested");
1575 return 0;
1576 }
1577
1578 if (!(paths = SDL_strdup(cpaths))) {
1579 Mix_SetError("Insufficient memory to iterate over SoundFonts");
1580 return 0;
1581 }
1582
1583#if defined(__MINGW32__) || defined(__MINGW64__)
1584 for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
Franklin Weia855d622017-01-21 15:18:31 -05001585#else
1586 for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
1587#endif
1588 if (!function(path, data)) {
1589 SDL_free(paths);
1590 return 0;
1591 }
1592 }
1593
1594 SDL_free(paths);
1595 return 1;
1596}
1597#endif