music.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 04 Jan 2012 00:16:03 -0500
changeset 542 3de4970b36d4
parent 541 323b314739ef
child 547 a9a5f18ea123
permissions -rwxr-xr-x
Fixed bug 1252 - Added Mix_LoadMUSType_RW() so you can tell SDL_mixer what type the music is

This involved a complete refactoring of the music loading so it's entirely rwops based and has improved music type detection code.
     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 = 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 *)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 			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 *)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 		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 		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 #ifdef __MACOSX__
   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 		if ( position > 0.0 ) {
  1068 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
  1069 		} else {
  1070 			smpeg.SMPEG_rewind(music_playing->data.mp3);
  1071 			smpeg.SMPEG_play(music_playing->data.mp3);
  1072 		}
  1073 		break;
  1074 #endif
  1075 #ifdef MP3_MAD_MUSIC
  1076 	    case MUS_MP3_MAD:
  1077 		mad_seek(music_playing->data.mp3_mad, position);
  1078 		break;
  1079 #endif
  1080 	    default:
  1081 		/* TODO: Implement this for other music backends */
  1082 		retval = -1;
  1083 		break;
  1084 	}
  1085 	return(retval);
  1086 }
  1087 int Mix_SetMusicPosition(double position)
  1088 {
  1089 	int retval;
  1090 
  1091 	SDL_LockAudio();
  1092 	if ( music_playing ) {
  1093 		retval = music_internal_position(position);
  1094 		if ( retval < 0 ) {
  1095 			Mix_SetError("Position not implemented for music type");
  1096 		}
  1097 	} else {
  1098 		Mix_SetError("Music isn't playing");
  1099 		retval = -1;
  1100 	}
  1101 	SDL_UnlockAudio();
  1102 
  1103 	return(retval);
  1104 }
  1105 
  1106 /* Set the music's initial volume */
  1107 static void music_internal_initialize_volume(void)
  1108 {
  1109 	if ( music_playing->fading == MIX_FADING_IN ) {
  1110 		music_internal_volume(0);
  1111 	} else {
  1112 		music_internal_volume(music_volume);
  1113 	}
  1114 }
  1115 
  1116 /* Set the music volume */
  1117 static void music_internal_volume(int volume)
  1118 {
  1119 	switch (music_playing->type) {
  1120 #ifdef CMD_MUSIC
  1121 	    case MUS_CMD:
  1122 		MusicCMD_SetVolume(volume);
  1123 		break;
  1124 #endif
  1125 #ifdef WAV_MUSIC
  1126 	    case MUS_WAV:
  1127 		WAVStream_SetVolume(volume);
  1128 		break;
  1129 #endif
  1130 #ifdef MODPLUG_MUSIC
  1131 	    case MUS_MODPLUG:
  1132 		modplug_setvolume(music_playing->data.modplug, volume);
  1133 		break;
  1134 #endif
  1135 #ifdef MOD_MUSIC
  1136 	    case MUS_MOD:
  1137 		MOD_setvolume(music_playing->data.module, volume);
  1138 		break;
  1139 #endif
  1140 #ifdef MID_MUSIC
  1141 	    case MUS_MID:
  1142 #ifdef USE_NATIVE_MIDI
  1143 		if ( native_midi_ok ) {
  1144 			native_midi_setvolume(volume);
  1145 			return;
  1146 		}
  1147 #endif
  1148 #ifdef USE_FLUIDSYNTH_MIDI
  1149 		if ( fluidsynth_ok ) {
  1150 			fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1151 			return;
  1152 		}
  1153 #endif
  1154 #ifdef USE_TIMIDITY_MIDI
  1155 		if ( timidity_ok ) {
  1156 			Timidity_SetVolume(volume);
  1157 			return;
  1158 		}
  1159 #endif
  1160 		break;
  1161 #endif
  1162 #ifdef OGG_MUSIC
  1163 	    case MUS_OGG:
  1164 		OGG_setvolume(music_playing->data.ogg, volume);
  1165 		break;
  1166 #endif
  1167 #ifdef FLAC_MUSIC
  1168 	    case MUS_FLAC:
  1169 		FLAC_setvolume(music_playing->data.flac, volume);
  1170 		break;
  1171 #endif
  1172 #ifdef MP3_MUSIC
  1173 	    case MUS_MP3:
  1174 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1175 		break;
  1176 #endif
  1177 #ifdef MP3_MAD_MUSIC
  1178 	    case MUS_MP3_MAD:
  1179 		mad_setVolume(music_playing->data.mp3_mad, volume);
  1180 		break;
  1181 #endif
  1182 	    default:
  1183 		/* Unknown music type?? */
  1184 		break;
  1185 	}
  1186 }
  1187 int Mix_VolumeMusic(int volume)
  1188 {
  1189 	int prev_volume;
  1190 
  1191 	prev_volume = music_volume;
  1192 	if ( volume < 0 ) {
  1193 		return prev_volume;
  1194 	}
  1195 	if ( volume > SDL_MIX_MAXVOLUME ) {
  1196 		volume = SDL_MIX_MAXVOLUME;
  1197 	}
  1198 	music_volume = volume;
  1199 	SDL_LockAudio();
  1200 	if ( music_playing ) {
  1201 		music_internal_volume(music_volume);
  1202 	}
  1203 	SDL_UnlockAudio();
  1204 	return(prev_volume);
  1205 }
  1206 
  1207 /* Halt playing of music */
  1208 static void music_internal_halt(void)
  1209 {
  1210 	switch (music_playing->type) {
  1211 #ifdef CMD_MUSIC
  1212 	    case MUS_CMD:
  1213 		MusicCMD_Stop(music_playing->data.cmd);
  1214 		break;
  1215 #endif
  1216 #ifdef WAV_MUSIC
  1217 	    case MUS_WAV:
  1218 		WAVStream_Stop();
  1219 		break;
  1220 #endif
  1221 #ifdef MODPLUG_MUSIC
  1222 	    case MUS_MODPLUG:
  1223 		modplug_stop(music_playing->data.modplug);
  1224 		break;
  1225 #endif
  1226 #ifdef MOD_MUSIC
  1227 	    case MUS_MOD:
  1228 		MOD_stop(music_playing->data.module);
  1229 		break;
  1230 #endif
  1231 #ifdef MID_MUSIC
  1232 	    case MUS_MID:
  1233 #ifdef USE_NATIVE_MIDI
  1234 		if ( native_midi_ok ) {
  1235 			native_midi_stop();
  1236 			goto skip;
  1237 		}
  1238 #endif
  1239 #ifdef USE_FLUIDSYNTH_MIDI
  1240 		if ( fluidsynth_ok ) {
  1241 			fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1242 			goto skip;
  1243 		}
  1244 #endif
  1245 #ifdef USE_TIMIDITY_MIDI
  1246 		if ( timidity_ok ) {
  1247 			Timidity_Stop();
  1248 			goto skip;
  1249 		}
  1250 #endif
  1251 		break;
  1252 #endif
  1253 #ifdef OGG_MUSIC
  1254 	    case MUS_OGG:
  1255 		OGG_stop(music_playing->data.ogg);
  1256 		break;
  1257 #endif
  1258 #ifdef FLAC_MUSIC
  1259 	    case MUS_FLAC:
  1260 		FLAC_stop(music_playing->data.flac);
  1261 		break;
  1262 #endif
  1263 #ifdef MP3_MUSIC
  1264 	    case MUS_MP3:
  1265 		smpeg.SMPEG_stop(music_playing->data.mp3);
  1266 		break;
  1267 #endif
  1268 #ifdef MP3_MAD_MUSIC
  1269 	    case MUS_MP3_MAD:
  1270 		mad_stop(music_playing->data.mp3_mad);
  1271 		break;
  1272 #endif
  1273 	    default:
  1274 		/* Unknown music type?? */
  1275 		return;
  1276 	}
  1277 
  1278 skip:
  1279 	music_playing->fading = MIX_NO_FADING;
  1280 	music_playing = NULL;
  1281 }
  1282 int Mix_HaltMusic(void)
  1283 {
  1284 	SDL_LockAudio();
  1285 	if ( music_playing ) {
  1286 		music_internal_halt();
  1287 	}
  1288 	SDL_UnlockAudio();
  1289 
  1290 	return(0);
  1291 }
  1292 
  1293 /* Progressively stop the music */
  1294 int Mix_FadeOutMusic(int ms)
  1295 {
  1296 	int retval = 0;
  1297 
  1298 	if ( ms_per_step == 0 ) {
  1299 		SDL_SetError("Audio device hasn't been opened");
  1300 		return 0;
  1301 	}
  1302 
  1303 	if (ms <= 0) {  /* just halt immediately. */
  1304 		Mix_HaltMusic();
  1305 		return 1;
  1306 	}
  1307 
  1308 	SDL_LockAudio();
  1309 	if ( music_playing) {
  1310                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1311                 if ( music_playing->fading == MIX_NO_FADING ) {
  1312 	        	music_playing->fade_step = 0;
  1313                 } else {
  1314                         int step;
  1315                         int old_fade_steps = music_playing->fade_steps;
  1316                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1317                                 step = music_playing->fade_step;
  1318                         } else {
  1319                                 step = old_fade_steps
  1320                                         - music_playing->fade_step + 1;
  1321                         }
  1322                         music_playing->fade_step = (step * fade_steps)
  1323                                 / old_fade_steps;
  1324                 }
  1325 		music_playing->fading = MIX_FADING_OUT;
  1326 		music_playing->fade_steps = fade_steps;
  1327 		retval = 1;
  1328 	}
  1329 	SDL_UnlockAudio();
  1330 
  1331 	return(retval);
  1332 }
  1333 
  1334 Mix_Fading Mix_FadingMusic(void)
  1335 {
  1336 	Mix_Fading fading = MIX_NO_FADING;
  1337 
  1338 	SDL_LockAudio();
  1339 	if ( music_playing ) {
  1340 		fading = music_playing->fading;
  1341 	}
  1342 	SDL_UnlockAudio();
  1343 
  1344 	return(fading);
  1345 }
  1346 
  1347 /* Pause/Resume the music stream */
  1348 void Mix_PauseMusic(void)
  1349 {
  1350 	music_active = 0;
  1351 }
  1352 
  1353 void Mix_ResumeMusic(void)
  1354 {
  1355 	music_active = 1;
  1356 }
  1357 
  1358 void Mix_RewindMusic(void)
  1359 {
  1360 	Mix_SetMusicPosition(0.0);
  1361 }
  1362 
  1363 int Mix_PausedMusic(void)
  1364 {
  1365 	return (music_active == 0);
  1366 }
  1367 
  1368 /* Check the status of the music */
  1369 static int music_internal_playing()
  1370 {
  1371 	int playing = 1;
  1372 
  1373 	if (music_playing == NULL) {
  1374 		return 0;
  1375 	}
  1376 
  1377 	switch (music_playing->type) {
  1378 #ifdef CMD_MUSIC
  1379 	    case MUS_CMD:
  1380 		if (!MusicCMD_Active(music_playing->data.cmd)) {
  1381 			playing = 0;
  1382 		}
  1383 		break;
  1384 #endif
  1385 #ifdef WAV_MUSIC
  1386 	    case MUS_WAV:
  1387 		if ( ! WAVStream_Active() ) {
  1388 			playing = 0;
  1389 		}
  1390 		break;
  1391 #endif
  1392 #ifdef MODPLUG_MUSIC
  1393 	    case MUS_MODPLUG:
  1394 		if ( ! modplug_playing(music_playing->data.modplug) ) {
  1395 			playing = 0;
  1396 		}
  1397 		break;
  1398 #endif
  1399 #ifdef MOD_MUSIC
  1400 	    case MUS_MOD:
  1401 		if ( ! MOD_playing(music_playing->data.module) ) {
  1402 			playing = 0;
  1403 		}
  1404 		break;
  1405 #endif
  1406 #ifdef MID_MUSIC
  1407 	    case MUS_MID:
  1408 #ifdef USE_NATIVE_MIDI
  1409 		if ( native_midi_ok ) {
  1410 			if ( ! native_midi_active() )
  1411 				playing = 0;
  1412 			goto skip;
  1413 		}
  1414 #endif
  1415 #ifdef USE_FLUIDSYNTH_MIDI
  1416 		if ( fluidsynth_ok ) {
  1417 			if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1418 				playing = 0;
  1419 			goto skip;
  1420 		}
  1421 #endif
  1422 #ifdef USE_TIMIDITY_MIDI
  1423 		if ( timidity_ok ) {
  1424 			if ( ! Timidity_Active() )
  1425 				playing = 0;
  1426 			goto skip;
  1427 		}
  1428 #endif
  1429 		break;
  1430 #endif
  1431 #ifdef OGG_MUSIC
  1432 	    case MUS_OGG:
  1433 		if ( ! OGG_playing(music_playing->data.ogg) ) {
  1434 			playing = 0;
  1435 		}
  1436 		break;
  1437 #endif
  1438 #ifdef FLAC_MUSIC
  1439 	    case MUS_FLAC:
  1440 		if ( ! FLAC_playing(music_playing->data.flac) ) {
  1441 			playing = 0;
  1442 		}
  1443 		break;
  1444 #endif
  1445 #ifdef MP3_MUSIC
  1446 	    case MUS_MP3:
  1447 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1448 			playing = 0;
  1449 		break;
  1450 #endif
  1451 #ifdef MP3_MAD_MUSIC
  1452 	    case MUS_MP3_MAD:
  1453 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1454 			playing = 0;
  1455 		}
  1456 		break;
  1457 #endif
  1458 	    default:
  1459 		playing = 0;
  1460 		break;
  1461 	}
  1462 
  1463 skip:
  1464 	return(playing);
  1465 }
  1466 int Mix_PlayingMusic(void)
  1467 {
  1468 	int playing = 0;
  1469 
  1470 	SDL_LockAudio();
  1471 	if ( music_playing ) {
  1472 		playing = music_loops || music_internal_playing();
  1473 	}
  1474 	SDL_UnlockAudio();
  1475 
  1476 	return(playing);
  1477 }
  1478 
  1479 /* Set the external music playback command */
  1480 int Mix_SetMusicCMD(const char *command)
  1481 {
  1482 	Mix_HaltMusic();
  1483 	if ( music_cmd ) {
  1484 		free(music_cmd);
  1485 		music_cmd = NULL;
  1486 	}
  1487 	if ( command ) {
  1488 		music_cmd = (char *)malloc(strlen(command)+1);
  1489 		if ( music_cmd == NULL ) {
  1490 			return(-1);
  1491 		}
  1492 		strcpy(music_cmd, command);
  1493 	}
  1494 	return(0);
  1495 }
  1496 
  1497 int Mix_SetSynchroValue(int i)
  1498 {
  1499 	/* Not supported by any players at this time */
  1500 	return(-1);
  1501 }
  1502 
  1503 int Mix_GetSynchroValue(void)
  1504 {
  1505 	/* Not supported by any players at this time */
  1506 	return(-1);
  1507 }
  1508 
  1509 
  1510 /* Uninitialize the music players */
  1511 void close_music(void)
  1512 {
  1513 	Mix_HaltMusic();
  1514 #ifdef CMD_MUSIC
  1515 	Mix_SetMusicCMD(NULL);
  1516 #endif
  1517 #ifdef MODPLUG_MUSIC
  1518 	modplug_exit();
  1519 #endif
  1520 #ifdef MOD_MUSIC
  1521 	MOD_exit();
  1522 #endif
  1523 #ifdef MID_MUSIC
  1524 # ifdef USE_TIMIDITY_MIDI
  1525 	Timidity_Close();
  1526 # endif
  1527 #endif
  1528 
  1529 	/* rcg06042009 report available decoders at runtime. */
  1530 	free(music_decoders);
  1531 	music_decoders = NULL;
  1532 	num_decoders = 0;
  1533 
  1534 	ms_per_step = 0;
  1535 }
  1536 
  1537 int Mix_SetSoundFonts(const char *paths)
  1538 {
  1539 #ifdef MID_MUSIC
  1540 	if (soundfont_paths) {
  1541 		free(soundfont_paths);
  1542 		soundfont_paths = NULL;
  1543 	}
  1544 
  1545 	if (paths) {
  1546 		if (!(soundfont_paths = strdup(paths))) {
  1547 			Mix_SetError("Insufficient memory to set SoundFonts");
  1548 			return 0;
  1549 		}
  1550 	}
  1551 #endif
  1552 	return 1;
  1553 }
  1554 
  1555 #ifdef MID_MUSIC
  1556 const char* Mix_GetSoundFonts(void)
  1557 {
  1558 	const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1559 
  1560 	if (!soundfont_paths || (force && force[0] == '1')) {
  1561 		return getenv("SDL_SOUNDFONTS");
  1562 	} else {
  1563 		return soundfont_paths;
  1564 	}
  1565 }
  1566 
  1567 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1568 {
  1569 	char *context, *path, *paths;
  1570 	const char* cpaths = Mix_GetSoundFonts();
  1571 
  1572 	if (!cpaths) {
  1573 		Mix_SetError("No SoundFonts have been requested");
  1574 		return 0;
  1575 	}
  1576 
  1577 	if (!(paths = strdup(cpaths))) {
  1578 		Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1579 		return 0;
  1580 	}
  1581 
  1582 #if defined(__MINGW32__) || defined(__MINGW64__)
  1583 	for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1584 #elif defined(_WIN32)
  1585 	for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1586 #else
  1587 	for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1588 #endif
  1589 		if (!function(path, data)) {
  1590 			free(paths);
  1591 			return 0;
  1592 		}
  1593 	}
  1594 
  1595 	free(paths);
  1596 	return 1;
  1597 }
  1598 #endif