1 /*
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 <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include "SDL_endian.h"
29 #include "SDL_audio.h"
30 #include "SDL_timer.h"
31 
32 #include "SDL_mixer.h"
33 
34 #ifdef CMD_MUSIC
35 #include "music_cmd.h"
36 #endif
37 #ifdef WAV_MUSIC
38 #include "wavestream.h"
39 #endif
40 #ifdef MODPLUG_MUSIC
41 #include "music_modplug.h"
42 #endif
43 #ifdef MOD_MUSIC
44 #include "music_mod.h"
45 #endif
46 #ifdef MID_MUSIC
47 #  ifdef USE_TIMIDITY_MIDI
48 #    include "timidity.h"
49 #  endif
50 #  ifdef USE_FLUIDSYNTH_MIDI
51 #    include "fluidsynth.h"
52 #  endif
53 #  ifdef USE_NATIVE_MIDI
54 #    include "native_midi.h"
55 #  endif
56 #endif
57 #ifdef OGG_MUSIC
58 #include "music_ogg.h"
59 #endif
60 #ifdef MP3_MUSIC
61 #include "dynamic_mp3.h"
62 #endif
63 #ifdef MP3_MAD_MUSIC
64 #include "music_mad.h"
65 #endif
66 #ifdef FLAC_MUSIC
67 #include "music_flac.h"
68 #endif
69 
70 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
71 static SDL_AudioSpec used_mixer;
72 #endif
73 
74 
75 int volatile music_active = 1;
76 static int volatile music_stopped = 0;
77 static int music_loops = 0;
78 static char *music_cmd = NULL;
79 static Mix_Music * volatile music_playing = NULL;
80 static int music_volume = MIX_MAX_VOLUME;
81 
82 struct _Mix_Music {
83 	Mix_MusicType type;
84 	union {
85 #ifdef CMD_MUSIC
86 		MusicCMD *cmd;
87 #endif
88 #ifdef WAV_MUSIC
89 		WAVStream *wave;
90 #endif
91 #ifdef MODPLUG_MUSIC
92 		modplug_data *modplug;
93 #endif
94 #ifdef MOD_MUSIC
95 		struct MODULE *module;
96 #endif
97 #ifdef MID_MUSIC
98 #ifdef USE_TIMIDITY_MIDI
99 		MidiSong *midi;
100 #endif
101 #ifdef USE_FLUIDSYNTH_MIDI
102 		FluidSynthMidiSong *fluidsynthmidi;
103 #endif
104 #ifdef USE_NATIVE_MIDI
105 		NativeMidiSong *nativemidi;
106 #endif
107 #endif
108 #ifdef OGG_MUSIC
109 		OGG_music *ogg;
110 #endif
111 #ifdef MP3_MUSIC
112 		SMPEG *mp3;
113 #endif
114 #ifdef MP3_MAD_MUSIC
115 		mad_data *mp3_mad;
116 #endif
117 #ifdef FLAC_MUSIC
118 		FLAC_music *flac;
119 #endif
120 	} data;
121 	Mix_Fading fading;
122 	int fade_step;
123 	int fade_steps;
124 	int error;
125 };
126 #ifdef MID_MUSIC
127 #ifdef USE_TIMIDITY_MIDI
128 static int timidity_ok;
129 static int samplesize;
130 #endif
131 #ifdef USE_FLUIDSYNTH_MIDI
132 static int fluidsynth_ok;
133 #endif
134 #ifdef USE_NATIVE_MIDI
135 static int native_midi_ok;
136 #endif
137 #endif
138 
139 /* Used to calculate fading steps */
140 static int ms_per_step;
141 
142 /* rcg06042009 report available decoders at runtime. */
143 static const char **music_decoders = NULL;
144 static int num_decoders = 0;
145 
146 /* Semicolon-separated SoundFont paths */
147 #ifdef MID_MUSIC
148 char* soundfont_paths = NULL;
149 #endif
150 
151 int Mix_GetNumMusicDecoders(void)
152 {
153 	return(num_decoders);
154 }
155 
156 const char *Mix_GetMusicDecoder(int index)
157 {
158 	if ((index < 0) || (index >= num_decoders)) {
159 		return NULL;
160 	}
161 	return(music_decoders[index]);
162 }
163 
164 static void add_music_decoder(const char *decoder)
165 {
166 	void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
167 	if (ptr == NULL) {
168 		return;  /* oh well, go on without it. */
169 	}
170 	music_decoders = (const char **) ptr;
171 	music_decoders[num_decoders++] = decoder;
172 }
173 
174 /* Local low-level functions prototypes */
175 static void music_internal_initialize_volume(void);
176 static void music_internal_volume(int volume);
177 static int  music_internal_play(Mix_Music *music, double position);
178 static int  music_internal_position(double position);
179 static int  music_internal_playing();
180 static void music_internal_halt(void);
181 
182 
183 /* Support for hooking when the music has finished */
184 static void (*music_finished_hook)(void) = NULL;
185 
186 void Mix_HookMusicFinished(void (*music_finished)(void))
187 {
188 	SDL_LockAudio();
189 	music_finished_hook = music_finished;
190 	SDL_UnlockAudio();
191 }
192 
193 
194 /* If music isn't playing, halt it if no looping is required, restart it */
195 /* otherwhise. NOP if the music is playing */
196 static int music_halt_or_loop (void)
197 {
198 	/* Restart music if it has to loop */
199 
200 	if (!music_internal_playing())
201 	{
202 #ifdef USE_NATIVE_MIDI
203 		/* Native MIDI handles looping internally */
204 		if (music_playing->type == MUS_MID && native_midi_ok) {
205 			music_loops = 0;
206 		}
207 #endif
208 
209 		/* Restart music if it has to loop at a high level */
210 		if (music_loops)
211 		{
212 			Mix_Fading current_fade;
213 			--music_loops;
214 			current_fade = music_playing->fading;
215 			music_internal_play(music_playing, 0.0);
216 			music_playing->fading = current_fade;
217 		}
218 		else
219 		{
220 			music_internal_halt();
221 			if (music_finished_hook)
222 				music_finished_hook();
223 
224 			return 0;
225 		}
226 	}
227 
228 	return 1;
229 }
230 
231 
232 
233 /* Mixing function */
234 void music_mixer(void *udata, Uint8 *stream, int len)
235 {
236 	int left = 0;
237 
238 	if ( music_playing && music_active ) {
239 		/* Handle fading */
240 		if ( music_playing->fading != MIX_NO_FADING ) {
241 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
242 				int volume;
243 				int fade_step = music_playing->fade_step;
244 				int fade_steps = music_playing->fade_steps;
245 
246 				if ( music_playing->fading == MIX_FADING_OUT ) {
247 					volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
248 				} else { /* Fading in */
249 					volume = (music_volume * fade_step) / fade_steps;
250 				}
251 				music_internal_volume(volume);
252 			} else {
253 				if ( music_playing->fading == MIX_FADING_OUT ) {
254 					music_internal_halt();
255 					if ( music_finished_hook ) {
256 						music_finished_hook();
257 					}
258 					return;
259 				}
260 				music_playing->fading = MIX_NO_FADING;
261 			}
262 		}
263 
264 		music_halt_or_loop();
265 		if (!music_internal_playing())
266 			return;
267 
268 		switch (music_playing->type) {
269 #ifdef CMD_MUSIC
270 			case MUS_CMD:
271 				/* The playing is done externally */
272 				break;
273 #endif
274 #ifdef WAV_MUSIC
275 			case MUS_WAV:
276 				left = WAVStream_PlaySome(stream, len);
277 				break;
278 #endif
279 #ifdef MODPLUG_MUSIC
280 			case MUS_MODPLUG:
281 				left = modplug_playAudio(music_playing->data.modplug, stream, len);
282 				break;
283 #endif
284 #ifdef MOD_MUSIC
285 			case MUS_MOD:
286 				left = MOD_playAudio(music_playing->data.module, stream, len);
287 				break;
288 #endif
289 #ifdef MID_MUSIC
290 			case MUS_MID:
291 #ifdef USE_NATIVE_MIDI
292   				if ( native_midi_ok ) {
293 					/* Native midi is handled asynchronously */
294 					goto skip;
295 	  			}
296 #endif
297 #ifdef USE_FLUIDSYNTH_MIDI
298 				if ( fluidsynth_ok ) {
299 					fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
300 					goto skip;
301 				}
302 #endif
303 #ifdef USE_TIMIDITY_MIDI
304 				if ( timidity_ok ) {
305 					int samples = len / samplesize;
306   					Timidity_PlaySome(stream, samples);
307 					goto skip;
308 				}
309 #endif
310 				break;
311 #endif
312 #ifdef OGG_MUSIC
313 			case MUS_OGG:
314 
315 				left = OGG_playAudio(music_playing->data.ogg, stream, len);
316 				break;
317 #endif
318 #ifdef FLAC_MUSIC
319 			case MUS_FLAC:
320 				left = FLAC_playAudio(music_playing->data.flac, stream, len);
321 				break;
322 #endif
323 #ifdef MP3_MUSIC
324 			case MUS_MP3:
325 				left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
326 				break;
327 #endif
328 #ifdef MP3_MAD_MUSIC
329 			case MUS_MP3_MAD:
330 				left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
331 				break;
332 #endif
333 			default:
334 				/* Unknown music type?? */
335 				break;
336 		}
337 	}
338 
339 skip:
340 	/* Handle seamless music looping */
341 	if (left > 0 && left < len) {
342 		music_halt_or_loop();
343 		if (music_internal_playing())
344 			music_mixer(udata, stream+(len-left), left);
345 	}
346 }
347 
348 /* Initialize the music players with a certain desired audio format */
349 int 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 */
429 int 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 
441 static 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. */
464 static 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 */
513 Mix_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 
584 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
585 {
586 	return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE);
587 }
588 
589 Mix_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 			Mix_SetError("%s", Timidity_Error());
712 			music->error = 1;
713 		}
714 #endif
715 		break;
716 #endif
717 #if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
718 	case MUS_MOD:
719 		music->error = 1;
720 #ifdef MODPLUG_MUSIC
721 		if ( music->error ) {
722 			music->type = MUS_MODPLUG;
723 			music->data.modplug = modplug_new_RW(rw, freesrc);
724 			if ( music->data.modplug ) {
725 				music->error = 0;
726 			}
727 		}
728 #endif
729 #ifdef MOD_MUSIC
730 		if ( music->error ) {
731 			music->type = MUS_MOD;
732 			music->data.module = MOD_new_RW(rw, freesrc);
733 			if ( music->data.module ) {
734 				music->error = 0;
735 			}
736 		}
737 #endif
738 		break;
739 #endif
740 
741 	default:
742 		Mix_SetError("Unrecognized music format");
743 		music->error=1;
744 	} /* switch (want) */
745 
746 
747 	if (music->error) {
748 		SDL_free(music);
749 		music=NULL;
750 	}
751 	return(music);
752 }
753 
754 /* Free a music chunk previously loaded */
755 void Mix_FreeMusic(Mix_Music *music)
756 {
757 	if ( music ) {
758 		/* Stop the music if it's currently playing */
759 		SDL_LockAudio();
760 		if ( music == music_playing ) {
761 			/* Wait for any fade out to finish */
762 			while ( music->fading == MIX_FADING_OUT ) {
763 				SDL_UnlockAudio();
764 				SDL_Delay(100);
765 				SDL_LockAudio();
766 			}
767 			if ( music == music_playing ) {
768 				music_internal_halt();
769 			}
770 		}
771 		SDL_UnlockAudio();
772 		switch (music->type) {
773 #ifdef CMD_MUSIC
774 			case MUS_CMD:
775 				MusicCMD_FreeSong(music->data.cmd);
776 				break;
777 #endif
778 #ifdef WAV_MUSIC
779 			case MUS_WAV:
780 				WAVStream_FreeSong(music->data.wave);
781 				break;
782 #endif
783 #ifdef MODPLUG_MUSIC
784 			case MUS_MODPLUG:
785 				modplug_delete(music->data.modplug);
786 				break;
787 #endif
788 #ifdef MOD_MUSIC
789 			case MUS_MOD:
790 				MOD_delete(music->data.module);
791 				break;
792 #endif
793 #ifdef MID_MUSIC
794 			case MUS_MID:
795 #ifdef USE_NATIVE_MIDI
796   				if ( native_midi_ok ) {
797 					native_midi_freesong(music->data.nativemidi);
798 					goto skip;
799 				}
800 #endif
801 #ifdef USE_FLUIDSYNTH_MIDI
802 				if ( fluidsynth_ok ) {
803 					fluidsynth_freesong(music->data.fluidsynthmidi);
804 					goto skip;
805 				}
806 #endif
807 #ifdef USE_TIMIDITY_MIDI
808 				if ( timidity_ok ) {
809 					Timidity_FreeSong(music->data.midi);
810 					goto skip;
811 				}
812 #endif
813 				break;
814 #endif
815 #ifdef OGG_MUSIC
816 			case MUS_OGG:
817 				OGG_delete(music->data.ogg);
818 				break;
819 #endif
820 #ifdef FLAC_MUSIC
821 			case MUS_FLAC:
822 				FLAC_delete(music->data.flac);
823 				break;
824 #endif
825 #ifdef MP3_MUSIC
826 			case MUS_MP3:
827 				smpeg.SMPEG_delete(music->data.mp3);
828 				break;
829 #endif
830 #ifdef MP3_MAD_MUSIC
831 			case MUS_MP3_MAD:
832 				mad_closeFile(music->data.mp3_mad);
833 				break;
834 #endif
835 			default:
836 				/* Unknown music type?? */
837 				break;
838 		}
839 
840     skip:
841 		SDL_free(music);
842 	}
843 }
844 
845 /* Find out the music format of a mixer music, or the currently playing
846    music, if 'music' is NULL.
847 */
848 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
849 {
850 	Mix_MusicType type = MUS_NONE;
851 
852 	if ( music ) {
853 		type = music->type;
854 	} else {
855 		SDL_LockAudio();
856 		if ( music_playing ) {
857 			type = music_playing->type;
858 		}
859 		SDL_UnlockAudio();
860 	}
861 	return(type);
862 }
863 
864 /* Play a music chunk.  Returns 0, or -1 if there was an error.
865  */
866 static int music_internal_play(Mix_Music *music, double position)
867 {
868 	int retval = 0;
869 
870 #if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
871 	/* This fixes a bug with native MIDI on Mac OS X, where you
872 	   can't really stop and restart MIDI from the audio callback.
873 	*/
874 	if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
875 		/* Just a seek suffices to restart playing */
876 		music_internal_position(position);
877 		return 0;
878 	}
879 #endif
880 
881 	/* Note the music we're playing */
882 	if ( music_playing ) {
883 		music_internal_halt();
884 	}
885 	music_playing = music;
886 
887 	/* Set the initial volume */
888 	if ( music->type != MUS_MOD ) {
889 		music_internal_initialize_volume();
890 	}
891 
892 	/* Set up for playback */
893 	switch (music->type) {
894 #ifdef CMD_MUSIC
895 	    case MUS_CMD:
896 		MusicCMD_Start(music->data.cmd);
897 		break;
898 #endif
899 #ifdef WAV_MUSIC
900 	    case MUS_WAV:
901 		WAVStream_Start(music->data.wave);
902 		break;
903 #endif
904 #ifdef MODPLUG_MUSIC
905 	    case MUS_MODPLUG:
906 		/* can't set volume until file is loaded, so finally set it now */
907 		music_internal_initialize_volume();
908 		modplug_play(music->data.modplug);
909 		break;
910 #endif
911 #ifdef MOD_MUSIC
912 	    case MUS_MOD:
913 		MOD_play(music->data.module);
914 		/* Player_SetVolume() does nothing before Player_Start() */
915 		music_internal_initialize_volume();
916 		break;
917 #endif
918 #ifdef MID_MUSIC
919 	    case MUS_MID:
920 #ifdef USE_NATIVE_MIDI
921 		if ( native_midi_ok ) {
922 			native_midi_start(music->data.nativemidi, music_loops);
923 			goto skip;
924 		}
925 #endif
926 #ifdef USE_FLUIDSYNTH_MIDI
927 		if (fluidsynth_ok ) {
928 			fluidsynth_start(music->data.fluidsynthmidi);
929 			goto skip;
930 		}
931 #endif
932 #ifdef USE_TIMIDITY_MIDI
933 		if ( timidity_ok ) {
934 			Timidity_Start(music->data.midi);
935 			goto skip;
936 		}
937 #endif
938 		break;
939 #endif
940 #ifdef OGG_MUSIC
941 	    case MUS_OGG:
942 		OGG_play(music->data.ogg);
943 		break;
944 #endif
945 #ifdef FLAC_MUSIC
946 	    case MUS_FLAC:
947 		FLAC_play(music->data.flac);
948 		break;
949 #endif
950 #ifdef MP3_MUSIC
951 	    case MUS_MP3:
952 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
953 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
954 		smpeg.SMPEG_play(music_playing->data.mp3);
955 		break;
956 #endif
957 #ifdef MP3_MAD_MUSIC
958 	    case MUS_MP3_MAD:
959 		mad_start(music->data.mp3_mad);
960 		break;
961 #endif
962 	    default:
963 		Mix_SetError("Can't play unknown music type");
964 		retval = -1;
965 		break;
966 	}
967 
968 skip:
969 	/* Set the playback position, note any errors if an offset is used */
970 	if ( retval == 0 ) {
971 		if ( position > 0.0 ) {
972 			if ( music_internal_position(position) < 0 ) {
973 				Mix_SetError("Position not implemented for music type");
974 				retval = -1;
975 			}
976 		} else {
977 			music_internal_position(0.0);
978 		}
979 	}
980 
981 	/* If the setup failed, we're not playing any music anymore */
982 	if ( retval < 0 ) {
983 		music_playing = NULL;
984 	}
985 	return(retval);
986 }
987 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
988 {
989 	int retval;
990 
991 	if ( ms_per_step == 0 ) {
992 		SDL_SetError("Audio device hasn't been opened");
993 		return(-1);
994 	}
995 
996 	/* Don't play null pointers :-) */
997 	if ( music == NULL ) {
998 		Mix_SetError("music parameter was NULL");
999 		return(-1);
1000 	}
1001 
1002 	/* Setup the data */
1003 	if ( ms ) {
1004 		music->fading = MIX_FADING_IN;
1005 	} else {
1006 		music->fading = MIX_NO_FADING;
1007 	}
1008 	music->fade_step = 0;
1009 	music->fade_steps = ms/ms_per_step;
1010 
1011 	/* Play the puppy */
1012 	SDL_LockAudio();
1013 	/* If the current music is fading out, wait for the fade to complete */
1014 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
1015 		SDL_UnlockAudio();
1016 		SDL_Delay(100);
1017 		SDL_LockAudio();
1018 	}
1019 	music_active = 1;
1020 	if (loops == 1) {
1021 		/* Loop is the number of times to play the audio */
1022 		loops = 0;
1023 	}
1024 	music_loops = loops;
1025 	retval = music_internal_play(music, position);
1026 	SDL_UnlockAudio();
1027 
1028 	return(retval);
1029 }
1030 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
1031 {
1032 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
1033 }
1034 int Mix_PlayMusic(Mix_Music *music, int loops)
1035 {
1036 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
1037 }
1038 
1039 /* Set the playing music position */
1040 int music_internal_position(double position)
1041 {
1042 	int retval = 0;
1043 
1044 	switch (music_playing->type) {
1045 #ifdef MODPLUG_MUSIC
1046 	    case MUS_MODPLUG:
1047 		modplug_jump_to_time(music_playing->data.modplug, position);
1048 		break;
1049 #endif
1050 #ifdef MOD_MUSIC
1051 	    case MUS_MOD:
1052 		MOD_jump_to_time(music_playing->data.module, position);
1053 		break;
1054 #endif
1055 #ifdef OGG_MUSIC
1056 	    case MUS_OGG:
1057 		OGG_jump_to_time(music_playing->data.ogg, position);
1058 		break;
1059 #endif
1060 #ifdef FLAC_MUSIC
1061 	    case MUS_FLAC:
1062 		FLAC_jump_to_time(music_playing->data.flac, position);
1063 		break;
1064 #endif
1065 #ifdef MP3_MUSIC
1066 	    case MUS_MP3:
1067 		smpeg.SMPEG_rewind(music_playing->data.mp3);
1068 		smpeg.SMPEG_play(music_playing->data.mp3);
1069 		if ( position > 0.0 ) {
1070 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
1071 		}
1072 		break;
1073 #endif
1074 #ifdef MP3_MAD_MUSIC
1075 	    case MUS_MP3_MAD:
1076 		mad_seek(music_playing->data.mp3_mad, position);
1077 		break;
1078 #endif
1079 	    default:
1080 		/* TODO: Implement this for other music backends */
1081 		retval = -1;
1082 		break;
1083 	}
1084 	return(retval);
1085 }
1086 int Mix_SetMusicPosition(double position)
1087 {
1088 	int retval;
1089 
1090 	SDL_LockAudio();
1091 	if ( music_playing ) {
1092 		retval = music_internal_position(position);
1093 		if ( retval < 0 ) {
1094 			Mix_SetError("Position not implemented for music type");
1095 		}
1096 	} else {
1097 		Mix_SetError("Music isn't playing");
1098 		retval = -1;
1099 	}
1100 	SDL_UnlockAudio();
1101 
1102 	return(retval);
1103 }
1104 
1105 /* Set the music's initial volume */
1106 static void music_internal_initialize_volume(void)
1107 {
1108 	if ( music_playing->fading == MIX_FADING_IN ) {
1109 		music_internal_volume(0);
1110 	} else {
1111 		music_internal_volume(music_volume);
1112 	}
1113 }
1114 
1115 /* Set the music volume */
1116 static void music_internal_volume(int volume)
1117 {
1118 	switch (music_playing->type) {
1119 #ifdef CMD_MUSIC
1120 	    case MUS_CMD:
1121 		MusicCMD_SetVolume(volume);
1122 		break;
1123 #endif
1124 #ifdef WAV_MUSIC
1125 	    case MUS_WAV:
1126 		WAVStream_SetVolume(volume);
1127 		break;
1128 #endif
1129 #ifdef MODPLUG_MUSIC
1130 	    case MUS_MODPLUG:
1131 		modplug_setvolume(music_playing->data.modplug, volume);
1132 		break;
1133 #endif
1134 #ifdef MOD_MUSIC
1135 	    case MUS_MOD:
1136 		MOD_setvolume(music_playing->data.module, volume);
1137 		break;
1138 #endif
1139 #ifdef MID_MUSIC
1140 	    case MUS_MID:
1141 #ifdef USE_NATIVE_MIDI
1142 		if ( native_midi_ok ) {
1143 			native_midi_setvolume(volume);
1144 			return;
1145 		}
1146 #endif
1147 #ifdef USE_FLUIDSYNTH_MIDI
1148 		if ( fluidsynth_ok ) {
1149 			fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
1150 			return;
1151 		}
1152 #endif
1153 #ifdef USE_TIMIDITY_MIDI
1154 		if ( timidity_ok ) {
1155 			Timidity_SetVolume(volume);
1156 			return;
1157 		}
1158 #endif
1159 		break;
1160 #endif
1161 #ifdef OGG_MUSIC
1162 	    case MUS_OGG:
1163 		OGG_setvolume(music_playing->data.ogg, volume);
1164 		break;
1165 #endif
1166 #ifdef FLAC_MUSIC
1167 	    case MUS_FLAC:
1168 		FLAC_setvolume(music_playing->data.flac, volume);
1169 		break;
1170 #endif
1171 #ifdef MP3_MUSIC
1172 	    case MUS_MP3:
1173 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
1174 		break;
1175 #endif
1176 #ifdef MP3_MAD_MUSIC
1177 	    case MUS_MP3_MAD:
1178 		mad_setVolume(music_playing->data.mp3_mad, volume);
1179 		break;
1180 #endif
1181 	    default:
1182 		/* Unknown music type?? */
1183 		break;
1184 	}
1185 }
1186 int Mix_VolumeMusic(int volume)
1187 {
1188 	int prev_volume;
1189 
1190 	prev_volume = music_volume;
1191 	if ( volume < 0 ) {
1192 		return prev_volume;
1193 	}
1194 	if ( volume > SDL_MIX_MAXVOLUME ) {
1195 		volume = SDL_MIX_MAXVOLUME;
1196 	}
1197 	music_volume = volume;
1198 	SDL_LockAudio();
1199 	if ( music_playing ) {
1200 		music_internal_volume(music_volume);
1201 	}
1202 	SDL_UnlockAudio();
1203 	return(prev_volume);
1204 }
1205 
1206 /* Halt playing of music */
1207 static void music_internal_halt(void)
1208 {
1209 	switch (music_playing->type) {
1210 #ifdef CMD_MUSIC
1211 	    case MUS_CMD:
1212 		MusicCMD_Stop(music_playing->data.cmd);
1213 		break;
1214 #endif
1215 #ifdef WAV_MUSIC
1216 	    case MUS_WAV:
1217 		WAVStream_Stop();
1218 		break;
1219 #endif
1220 #ifdef MODPLUG_MUSIC
1221 	    case MUS_MODPLUG:
1222 		modplug_stop(music_playing->data.modplug);
1223 		break;
1224 #endif
1225 #ifdef MOD_MUSIC
1226 	    case MUS_MOD:
1227 		MOD_stop(music_playing->data.module);
1228 		break;
1229 #endif
1230 #ifdef MID_MUSIC
1231 	    case MUS_MID:
1232 #ifdef USE_NATIVE_MIDI
1233 		if ( native_midi_ok ) {
1234 			native_midi_stop();
1235 			goto skip;
1236 		}
1237 #endif
1238 #ifdef USE_FLUIDSYNTH_MIDI
1239 		if ( fluidsynth_ok ) {
1240 			fluidsynth_stop(music_playing->data.fluidsynthmidi);
1241 			goto skip;
1242 		}
1243 #endif
1244 #ifdef USE_TIMIDITY_MIDI
1245 		if ( timidity_ok ) {
1246 			Timidity_Stop();
1247 			goto skip;
1248 		}
1249 #endif
1250 		break;
1251 #endif
1252 #ifdef OGG_MUSIC
1253 	    case MUS_OGG:
1254 		OGG_stop(music_playing->data.ogg);
1255 		break;
1256 #endif
1257 #ifdef FLAC_MUSIC
1258 	    case MUS_FLAC:
1259 		FLAC_stop(music_playing->data.flac);
1260 		break;
1261 #endif
1262 #ifdef MP3_MUSIC
1263 	    case MUS_MP3:
1264 		smpeg.SMPEG_stop(music_playing->data.mp3);
1265 		break;
1266 #endif
1267 #ifdef MP3_MAD_MUSIC
1268 	    case MUS_MP3_MAD:
1269 		mad_stop(music_playing->data.mp3_mad);
1270 		break;
1271 #endif
1272 	    default:
1273 		/* Unknown music type?? */
1274 		return;
1275 	}
1276 
1277 skip:
1278 	music_playing->fading = MIX_NO_FADING;
1279 	music_playing = NULL;
1280 }
1281 int Mix_HaltMusic(void)
1282 {
1283 	SDL_LockAudio();
1284 	if ( music_playing ) {
1285 		music_internal_halt();
1286 	}
1287 	SDL_UnlockAudio();
1288 
1289 	return(0);
1290 }
1291 
1292 /* Progressively stop the music */
1293 int Mix_FadeOutMusic(int ms)
1294 {
1295 	int retval = 0;
1296 
1297 	if ( ms_per_step == 0 ) {
1298 		SDL_SetError("Audio device hasn't been opened");
1299 		return 0;
1300 	}
1301 
1302 	if (ms <= 0) {  /* just halt immediately. */
1303 		Mix_HaltMusic();
1304 		return 1;
1305 	}
1306 
1307 	SDL_LockAudio();
1308 	if ( music_playing) {
1309                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
1310                 if ( music_playing->fading == MIX_NO_FADING ) {
1311 	        	music_playing->fade_step = 0;
1312                 } else {
1313                         int step;
1314                         int old_fade_steps = music_playing->fade_steps;
1315                         if ( music_playing->fading == MIX_FADING_OUT ) {
1316                                 step = music_playing->fade_step;
1317                         } else {
1318                                 step = old_fade_steps
1319                                         - music_playing->fade_step + 1;
1320                         }
1321                         music_playing->fade_step = (step * fade_steps)
1322                                 / old_fade_steps;
1323                 }
1324 		music_playing->fading = MIX_FADING_OUT;
1325 		music_playing->fade_steps = fade_steps;
1326 		retval = 1;
1327 	}
1328 	SDL_UnlockAudio();
1329 
1330 	return(retval);
1331 }
1332 
1333 Mix_Fading Mix_FadingMusic(void)
1334 {
1335 	Mix_Fading fading = MIX_NO_FADING;
1336 
1337 	SDL_LockAudio();
1338 	if ( music_playing ) {
1339 		fading = music_playing->fading;
1340 	}
1341 	SDL_UnlockAudio();
1342 
1343 	return(fading);
1344 }
1345 
1346 /* Pause/Resume the music stream */
1347 void Mix_PauseMusic(void)
1348 {
1349 	music_active = 0;
1350 }
1351 
1352 void Mix_ResumeMusic(void)
1353 {
1354 	music_active = 1;
1355 }
1356 
1357 void Mix_RewindMusic(void)
1358 {
1359 	Mix_SetMusicPosition(0.0);
1360 }
1361 
1362 int Mix_PausedMusic(void)
1363 {
1364 	return (music_active == 0);
1365 }
1366 
1367 /* Check the status of the music */
1368 static int music_internal_playing()
1369 {
1370 	int playing = 1;
1371 
1372 	if (music_playing == NULL) {
1373 		return 0;
1374 	}
1375 
1376 	switch (music_playing->type) {
1377 #ifdef CMD_MUSIC
1378 	    case MUS_CMD:
1379 		if (!MusicCMD_Active(music_playing->data.cmd)) {
1380 			playing = 0;
1381 		}
1382 		break;
1383 #endif
1384 #ifdef WAV_MUSIC
1385 	    case MUS_WAV:
1386 		if ( ! WAVStream_Active() ) {
1387 			playing = 0;
1388 		}
1389 		break;
1390 #endif
1391 #ifdef MODPLUG_MUSIC
1392 	    case MUS_MODPLUG:
1393 		if ( ! modplug_playing(music_playing->data.modplug) ) {
1394 			playing = 0;
1395 		}
1396 		break;
1397 #endif
1398 #ifdef MOD_MUSIC
1399 	    case MUS_MOD:
1400 		if ( ! MOD_playing(music_playing->data.module) ) {
1401 			playing = 0;
1402 		}
1403 		break;
1404 #endif
1405 #ifdef MID_MUSIC
1406 	    case MUS_MID:
1407 #ifdef USE_NATIVE_MIDI
1408 		if ( native_midi_ok ) {
1409 			if ( ! native_midi_active() )
1410 				playing = 0;
1411 			goto skip;
1412 		}
1413 #endif
1414 #ifdef USE_FLUIDSYNTH_MIDI
1415 		if ( fluidsynth_ok ) {
1416 			if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
1417 				playing = 0;
1418 			goto skip;
1419 		}
1420 #endif
1421 #ifdef USE_TIMIDITY_MIDI
1422 		if ( timidity_ok ) {
1423 			if ( ! Timidity_Active() )
1424 				playing = 0;
1425 			goto skip;
1426 		}
1427 #endif
1428 		break;
1429 #endif
1430 #ifdef OGG_MUSIC
1431 	    case MUS_OGG:
1432 		if ( ! OGG_playing(music_playing->data.ogg) ) {
1433 			playing = 0;
1434 		}
1435 		break;
1436 #endif
1437 #ifdef FLAC_MUSIC
1438 	    case MUS_FLAC:
1439 		if ( ! FLAC_playing(music_playing->data.flac) ) {
1440 			playing = 0;
1441 		}
1442 		break;
1443 #endif
1444 #ifdef MP3_MUSIC
1445 	    case MUS_MP3:
1446 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
1447 			playing = 0;
1448 		break;
1449 #endif
1450 #ifdef MP3_MAD_MUSIC
1451 	    case MUS_MP3_MAD:
1452 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
1453 			playing = 0;
1454 		}
1455 		break;
1456 #endif
1457 	    default:
1458 		playing = 0;
1459 		break;
1460 	}
1461 
1462 skip:
1463 	return(playing);
1464 }
1465 int Mix_PlayingMusic(void)
1466 {
1467 	int playing = 0;
1468 
1469 	SDL_LockAudio();
1470 	if ( music_playing ) {
1471 		playing = music_loops || music_internal_playing();
1472 	}
1473 	SDL_UnlockAudio();
1474 
1475 	return(playing);
1476 }
1477 
1478 /* Set the external music playback command */
1479 int Mix_SetMusicCMD(const char *command)
1480 {
1481 	Mix_HaltMusic();
1482 	if ( music_cmd ) {
1483 		SDL_free(music_cmd);
1484 		music_cmd = NULL;
1485 	}
1486 	if ( command ) {
1487 		music_cmd = (char *)SDL_malloc(strlen(command)+1);
1488 		if ( music_cmd == NULL ) {
1489 			return(-1);
1490 		}
1491 		strcpy(music_cmd, command);
1492 	}
1493 	return(0);
1494 }
1495 
1496 int Mix_SetSynchroValue(int i)
1497 {
1498 	/* Not supported by any players at this time */
1499 	return(-1);
1500 }
1501 
1502 int Mix_GetSynchroValue(void)
1503 {
1504 	/* Not supported by any players at this time */
1505 	return(-1);
1506 }
1507 
1508 
1509 /* Uninitialize the music players */
1510 void close_music(void)
1511 {
1512 	Mix_HaltMusic();
1513 #ifdef CMD_MUSIC
1514 	Mix_SetMusicCMD(NULL);
1515 #endif
1516 #ifdef MODPLUG_MUSIC
1517 	modplug_exit();
1518 #endif
1519 #ifdef MOD_MUSIC
1520 	MOD_exit();
1521 #endif
1522 #ifdef MID_MUSIC
1523 # ifdef USE_TIMIDITY_MIDI
1524 	Timidity_Close();
1525 # endif
1526 #endif
1527 
1528 	/* rcg06042009 report available decoders at runtime. */
1529 	SDL_free(music_decoders);
1530 	music_decoders = NULL;
1531 	num_decoders = 0;
1532 
1533 	ms_per_step = 0;
1534 }
1535 
1536 int Mix_SetSoundFonts(const char *paths)
1537 {
1538 #ifdef MID_MUSIC
1539 	if (soundfont_paths) {
1540 		SDL_free(soundfont_paths);
1541 		soundfont_paths = NULL;
1542 	}
1543 
1544 	if (paths) {
1545 		if (!(soundfont_paths = SDL_strdup(paths))) {
1546 			Mix_SetError("Insufficient memory to set SoundFonts");
1547 			return 0;
1548 		}
1549 	}
1550 #endif
1551 	return 1;
1552 }
1553 
1554 #ifdef MID_MUSIC
1555 const char* Mix_GetSoundFonts(void)
1556 {
1557 	const char* force = getenv("SDL_FORCE_SOUNDFONTS");
1558 
1559 	if (!soundfont_paths || (force && force[0] == '1')) {
1560 		return getenv("SDL_SOUNDFONTS");
1561 	} else {
1562 		return soundfont_paths;
1563 	}
1564 }
1565 
1566 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
1567 {
1568 	char *context, *path, *paths;
1569 	const char* cpaths = Mix_GetSoundFonts();
1570 
1571 	if (!cpaths) {
1572 		Mix_SetError("No SoundFonts have been requested");
1573 		return 0;
1574 	}
1575 
1576 	if (!(paths = SDL_strdup(cpaths))) {
1577 		Mix_SetError("Insufficient memory to iterate over SoundFonts");
1578 		return 0;
1579 	}
1580 
1581 #if defined(__MINGW32__) || defined(__MINGW64__)
1582 	for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
1583 #elif defined(_WIN32)
1584 	for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
1585 #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
1598