music.c
author Ozkan Sezer
Sat, 14 Dec 2019 18:14:10 +0300
branchSDL-1.2
changeset 1081 119300487b73
parent 945 c606c85c8863
permissions -rw-r--r--
backport default/2.0 commits 6c6adcc and 1e215d1 for fluidsynth support:

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