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