music.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 18 Jul 2011 23:35:08 -0700
changeset 538 b5e3fe1b5a09
parent 533 f19368c22ebd
child 541 323b314739ef
permissions -rwxr-xr-x
Mix_LoadMUS(): Don't check MP3 magic when we've got filenames.

This will allow corrupt, but otherwise-playable MP3s to work.

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