music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2012 16:45:58 -0500
changeset 533 f19368c22ebd
parent 531 f9c790738ec3
child 538 b5e3fe1b5a09
permissions -rwxr-xr-x
Better fix for looping on Mac OS X. This also gives event perfect looping on Windows and theoretically on Haiku.
     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 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   571 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   572 		if ( Mix_Init(MIX_INIT_MP3) ) {
   573 			SMPEG_Info info;
   574 			music->type = MUS_MP3;
   575 			music->data.mp3 = smpeg.SMPEG_new(file, &info, 0);
   576 			if ( !info.has_audio ) {
   577 				Mix_SetError("MPEG file does not have any audio stream.");
   578 				music->error = 1;
   579 			} else {
   580 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   581 			}
   582 		} else {
   583 			music->error = 1;
   584 		}
   585 	} else
   586 #endif
   587 #ifdef MP3_MAD_MUSIC
   588 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   589 	     (ext && MIX_string_equals(ext, "MP3")) ||
   590 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   591 	     (ext && MIX_string_equals(ext, "MAD")) ||
   592 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   593 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   594 		music->type = MUS_MP3_MAD;
   595 		music->data.mp3_mad = mad_openFile(file, &used_mixer);
   596 		if (music->data.mp3_mad == 0) {
   597 		    Mix_SetError("Could not initialize MPEG stream.");
   598 			music->error = 1;
   599 		}
   600 	} else
   601 #endif
   602 #ifdef MODPLUG_MUSIC
   603 	if ( 1 ) {
   604 		music->type = MUS_MODPLUG;
   605 		music->data.modplug = modplug_new(file);
   606 		if ( music->data.modplug == NULL ) {
   607 			music->error = 1;
   608 		}
   609 	} else
   610 #endif
   611 #ifdef MOD_MUSIC
   612 	if ( 1 ) {
   613 		music->type = MUS_MOD;
   614 		music->data.module = MOD_new(file);
   615 		if ( music->data.module == NULL ) {
   616 			music->error = 1;
   617 		}
   618 	} else
   619 #endif
   620 	{
   621 		Mix_SetError("Unrecognized music format");
   622 		music->error = 1;
   623 	}
   624 
   625 skip:
   626 	if ( music->error ) {
   627 		free(music);
   628 		music = NULL;
   629 	}
   630 	return(music);
   631 }
   632 
   633 /* Free a music chunk previously loaded */
   634 void Mix_FreeMusic(Mix_Music *music)
   635 {
   636 	if ( music ) {
   637 		/* Stop the music if it's currently playing */
   638 		SDL_LockAudio();
   639 		if ( music == music_playing ) {
   640 			/* Wait for any fade out to finish */
   641 			while ( music->fading == MIX_FADING_OUT ) {
   642 				SDL_UnlockAudio();
   643 				SDL_Delay(100);
   644 				SDL_LockAudio();
   645 			}
   646 			if ( music == music_playing ) {
   647 				music_internal_halt();
   648 			}
   649 		}
   650 		SDL_UnlockAudio();
   651 		switch (music->type) {
   652 #ifdef CMD_MUSIC
   653 			case MUS_CMD:
   654 				MusicCMD_FreeSong(music->data.cmd);
   655 				break;
   656 #endif
   657 #ifdef WAV_MUSIC
   658 			case MUS_WAV:
   659 				WAVStream_FreeSong(music->data.wave);
   660 				break;
   661 #endif
   662 #ifdef MODPLUG_MUSIC
   663 			case MUS_MODPLUG:
   664 				modplug_delete(music->data.modplug);
   665 				break;
   666 #endif
   667 #ifdef MOD_MUSIC
   668 			case MUS_MOD:
   669 				MOD_delete(music->data.module);
   670 				break;
   671 #endif
   672 #ifdef MID_MUSIC
   673 			case MUS_MID:
   674 #ifdef USE_NATIVE_MIDI
   675   				if ( native_midi_ok ) {
   676 					native_midi_freesong(music->data.nativemidi);
   677 					goto skip;
   678 				}
   679 #endif
   680 #ifdef USE_FLUIDSYNTH_MIDI
   681 				if ( fluidsynth_ok ) {
   682 					fluidsynth_freesong(music->data.fluidsynthmidi);
   683 					goto skip;
   684 				}
   685 #endif
   686 #ifdef USE_TIMIDITY_MIDI
   687 				if ( timidity_ok ) {
   688 					Timidity_FreeSong(music->data.midi);
   689 					goto skip;
   690 				}
   691 #endif
   692 				break;
   693 #endif
   694 #ifdef OGG_MUSIC
   695 			case MUS_OGG:
   696 				OGG_delete(music->data.ogg);
   697 				break;
   698 #endif
   699 #ifdef FLAC_MUSIC
   700 			case MUS_FLAC:
   701 				FLAC_delete(music->data.flac);
   702 				break;
   703 #endif
   704 #ifdef MP3_MUSIC
   705 			case MUS_MP3:
   706 				smpeg.SMPEG_delete(music->data.mp3);
   707 				break;
   708 #endif
   709 #ifdef MP3_MAD_MUSIC
   710 			case MUS_MP3_MAD:
   711 				mad_closeFile(music->data.mp3_mad);
   712 				break;
   713 #endif
   714 			default:
   715 				/* Unknown music type?? */
   716 				break;
   717 		}
   718 
   719     skip:
   720 		free(music);
   721 	}
   722 }
   723 
   724 /* Find out the music format of a mixer music, or the currently playing
   725    music, if 'music' is NULL.
   726 */
   727 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   728 {
   729 	Mix_MusicType type = MUS_NONE;
   730 
   731 	if ( music ) {
   732 		type = music->type;
   733 	} else {
   734 		SDL_LockAudio();
   735 		if ( music_playing ) {
   736 			type = music_playing->type;
   737 		}
   738 		SDL_UnlockAudio();
   739 	}
   740 	return(type);
   741 }
   742 
   743 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   744  */
   745 static int music_internal_play(Mix_Music *music, double position)
   746 {
   747 	int retval = 0;
   748 
   749 #ifdef __MACOSX__
   750 	/* This fixes a bug with native MIDI on Mac OS X, where you
   751 	   can't really stop and restart MIDI from the audio callback.
   752 	*/
   753 	if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
   754 		/* Just a seek suffices to restart playing */
   755 		music_internal_position(position);
   756 		return 0;
   757 	}
   758 #endif
   759 
   760 	/* Note the music we're playing */
   761 	if ( music_playing ) {
   762 		music_internal_halt();
   763 	}
   764 	music_playing = music;
   765 
   766 	/* Set the initial volume */
   767 	if ( music->type != MUS_MOD ) {
   768 		music_internal_initialize_volume();
   769 	}
   770 
   771 	/* Set up for playback */
   772 	switch (music->type) {
   773 #ifdef CMD_MUSIC
   774 	    case MUS_CMD:
   775 		MusicCMD_Start(music->data.cmd);
   776 		break;
   777 #endif
   778 #ifdef WAV_MUSIC
   779 	    case MUS_WAV:
   780 		WAVStream_Start(music->data.wave);
   781 		break;
   782 #endif
   783 #ifdef MODPLUG_MUSIC
   784 	    case MUS_MODPLUG:
   785 		/* can't set volume until file is loaded, so finally set it now */
   786 		music_internal_initialize_volume();
   787 		modplug_play(music->data.modplug);
   788 		break;
   789 #endif
   790 #ifdef MOD_MUSIC
   791 	    case MUS_MOD:
   792 		MOD_play(music->data.module);
   793 		/* Player_SetVolume() does nothing before Player_Start() */
   794 		music_internal_initialize_volume();
   795 		break;
   796 #endif
   797 #ifdef MID_MUSIC
   798 	    case MUS_MID:
   799 #ifdef USE_NATIVE_MIDI
   800 		if ( native_midi_ok ) {
   801 			native_midi_start(music->data.nativemidi, music_loops);
   802 			goto skip;
   803 		}
   804 #endif
   805 #ifdef USE_FLUIDSYNTH_MIDI
   806 		if (fluidsynth_ok ) {
   807 			fluidsynth_start(music->data.fluidsynthmidi);
   808 			goto skip;
   809 		}
   810 #endif
   811 #ifdef USE_TIMIDITY_MIDI
   812 		if ( timidity_ok ) {
   813 			Timidity_Start(music->data.midi);
   814 			goto skip;
   815 		}
   816 #endif
   817 		break;
   818 #endif
   819 #ifdef OGG_MUSIC
   820 	    case MUS_OGG:
   821 		OGG_play(music->data.ogg);
   822 		break;
   823 #endif
   824 #ifdef FLAC_MUSIC
   825 	    case MUS_FLAC:
   826 		FLAC_play(music->data.flac);
   827 		break;
   828 #endif
   829 #ifdef MP3_MUSIC
   830 	    case MUS_MP3:
   831 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
   832 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
   833 		smpeg.SMPEG_play(music_playing->data.mp3);
   834 		break;
   835 #endif
   836 #ifdef MP3_MAD_MUSIC
   837 	    case MUS_MP3_MAD:
   838 		mad_start(music->data.mp3_mad);
   839 		break;
   840 #endif
   841 	    default:
   842 		Mix_SetError("Can't play unknown music type");
   843 		retval = -1;
   844 		break;
   845 	}
   846 
   847 skip:
   848 	/* Set the playback position, note any errors if an offset is used */
   849 	if ( retval == 0 ) {
   850 		if ( position > 0.0 ) {
   851 			if ( music_internal_position(position) < 0 ) {
   852 				Mix_SetError("Position not implemented for music type");
   853 				retval = -1;
   854 			}
   855 		} else {
   856 			music_internal_position(0.0);
   857 		}
   858 	}
   859 
   860 	/* If the setup failed, we're not playing any music anymore */
   861 	if ( retval < 0 ) {
   862 		music_playing = NULL;
   863 	}
   864 	return(retval);
   865 }
   866 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   867 {
   868 	int retval;
   869 
   870 	if ( ms_per_step == 0 ) {
   871 		SDL_SetError("Audio device hasn't been opened");
   872 		return(-1);
   873 	}
   874 
   875 	/* Don't play null pointers :-) */
   876 	if ( music == NULL ) {
   877 		Mix_SetError("music parameter was NULL");
   878 		return(-1);
   879 	}
   880 
   881 	/* Setup the data */
   882 	if ( ms ) {
   883 		music->fading = MIX_FADING_IN;
   884 	} else {
   885 		music->fading = MIX_NO_FADING;
   886 	}
   887 	music->fade_step = 0;
   888 	music->fade_steps = ms/ms_per_step;
   889 
   890 	/* Play the puppy */
   891 	SDL_LockAudio();
   892 	/* If the current music is fading out, wait for the fade to complete */
   893 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
   894 		SDL_UnlockAudio();
   895 		SDL_Delay(100);
   896 		SDL_LockAudio();
   897 	}
   898 	music_active = 1;
   899 	if (loops == 1) {
   900 		/* Loop is the number of times to play the audio */
   901 		loops = 0;
   902 	}
   903 	music_loops = loops;
   904 	retval = music_internal_play(music, position);
   905 	SDL_UnlockAudio();
   906 
   907 	return(retval);
   908 }
   909 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   910 {
   911 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   912 }
   913 int Mix_PlayMusic(Mix_Music *music, int loops)
   914 {
   915 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   916 }
   917 
   918 /* Set the playing music position */
   919 int music_internal_position(double position)
   920 {
   921 	int retval = 0;
   922 
   923 	switch (music_playing->type) {
   924 #ifdef MODPLUG_MUSIC
   925 	    case MUS_MODPLUG:
   926 		modplug_jump_to_time(music_playing->data.modplug, position);
   927 		break;
   928 #endif
   929 #ifdef MOD_MUSIC
   930 	    case MUS_MOD:
   931 		MOD_jump_to_time(music_playing->data.module, position);
   932 		break;
   933 #endif
   934 #ifdef OGG_MUSIC
   935 	    case MUS_OGG:
   936 		OGG_jump_to_time(music_playing->data.ogg, position);
   937 		break;
   938 #endif
   939 #ifdef FLAC_MUSIC
   940 	    case MUS_FLAC:
   941 		FLAC_jump_to_time(music_playing->data.flac, position);
   942 		break;
   943 #endif
   944 #ifdef MP3_MUSIC
   945 	    case MUS_MP3:
   946 		if ( position > 0.0 ) {
   947 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
   948 		} else {
   949 			smpeg.SMPEG_rewind(music_playing->data.mp3);
   950 			smpeg.SMPEG_play(music_playing->data.mp3);
   951 		}
   952 		break;
   953 #endif
   954 #ifdef MP3_MAD_MUSIC
   955 	    case MUS_MP3_MAD:
   956 		mad_seek(music_playing->data.mp3_mad, position);
   957 		break;
   958 #endif
   959 	    default:
   960 		/* TODO: Implement this for other music backends */
   961 		retval = -1;
   962 		break;
   963 	}
   964 	return(retval);
   965 }
   966 int Mix_SetMusicPosition(double position)
   967 {
   968 	int retval;
   969 
   970 	SDL_LockAudio();
   971 	if ( music_playing ) {
   972 		retval = music_internal_position(position);
   973 		if ( retval < 0 ) {
   974 			Mix_SetError("Position not implemented for music type");
   975 		}
   976 	} else {
   977 		Mix_SetError("Music isn't playing");
   978 		retval = -1;
   979 	}
   980 	SDL_UnlockAudio();
   981 
   982 	return(retval);
   983 }
   984 
   985 /* Set the music's initial volume */
   986 static void music_internal_initialize_volume(void)
   987 {
   988 	if ( music_playing->fading == MIX_FADING_IN ) {
   989 		music_internal_volume(0);
   990 	} else {
   991 		music_internal_volume(music_volume);
   992 	}
   993 }
   994 
   995 /* Set the music volume */
   996 static void music_internal_volume(int volume)
   997 {
   998 	switch (music_playing->type) {
   999 #ifdef CMD_MUSIC
  1000 	    case MUS_CMD:
  1001 		MusicCMD_SetVolume(volume);
  1002 		break;
  1003 #endif
  1004 #ifdef WAV_MUSIC
  1005 	    case MUS_WAV:
  1006 		WAVStream_SetVolume(volume);
  1007 		break;
  1008 #endif
  1009 #ifdef MODPLUG_MUSIC
  1010 	    case MUS_MODPLUG:
  1011 		modplug_setvolume(music_playing->data.modplug, volume);
  1012 		break;
  1013 #endif
  1014 #ifdef MOD_MUSIC
  1015 	    case MUS_MOD:
  1016 		MOD_setvolume(music_playing->data.module, volume);
  1017 		break;
  1018 #endif
  1019 #ifdef MID_MUSIC
  1020 	    case MUS_MID:
  1021 #ifdef USE_NATIVE_MIDI
  1022 		if ( native_midi_ok ) {
  1023 			native_midi_setvolume(volume);
  1024 			return;
  1025 		}
  1026 #endif
  1027 #ifdef USE_FLUIDSYNTH_MIDI
  1028 		if ( fluidsynth_ok ) {
  1029 			fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1030 			return;
  1031 		}
  1032 #endif
  1033 #ifdef USE_TIMIDITY_MIDI
  1034 		if ( timidity_ok ) {
  1035 			Timidity_SetVolume(volume);
  1036 			return;
  1037 		}
  1038 #endif
  1039 		break;
  1040 #endif
  1041 #ifdef OGG_MUSIC
  1042 	    case MUS_OGG:
  1043 		OGG_setvolume(music_playing->data.ogg, volume);
  1044 		break;
  1045 #endif
  1046 #ifdef FLAC_MUSIC
  1047 	    case MUS_FLAC:
  1048 		FLAC_setvolume(music_playing->data.flac, volume);
  1049 		break;
  1050 #endif
  1051 #ifdef MP3_MUSIC
  1052 	    case MUS_MP3:
  1053 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1054 		break;
  1055 #endif
  1056 #ifdef MP3_MAD_MUSIC
  1057 	    case MUS_MP3_MAD:
  1058 		mad_setVolume(music_playing->data.mp3_mad, volume);
  1059 		break;
  1060 #endif
  1061 	    default:
  1062 		/* Unknown music type?? */
  1063 		break;
  1064 	}
  1065 }
  1066 int Mix_VolumeMusic(int volume)
  1067 {
  1068 	int prev_volume;
  1069 
  1070 	prev_volume = music_volume;
  1071 	if ( volume < 0 ) {
  1072 		return prev_volume;
  1073 	}
  1074 	if ( volume > SDL_MIX_MAXVOLUME ) {
  1075 		volume = SDL_MIX_MAXVOLUME;
  1076 	}
  1077 	music_volume = volume;
  1078 	SDL_LockAudio();
  1079 	if ( music_playing ) {
  1080 		music_internal_volume(music_volume);
  1081 	}
  1082 	SDL_UnlockAudio();
  1083 	return(prev_volume);
  1084 }
  1085 
  1086 /* Halt playing of music */
  1087 static void music_internal_halt(void)
  1088 {
  1089 	switch (music_playing->type) {
  1090 #ifdef CMD_MUSIC
  1091 	    case MUS_CMD:
  1092 		MusicCMD_Stop(music_playing->data.cmd);
  1093 		break;
  1094 #endif
  1095 #ifdef WAV_MUSIC
  1096 	    case MUS_WAV:
  1097 		WAVStream_Stop();
  1098 		break;
  1099 #endif
  1100 #ifdef MODPLUG_MUSIC
  1101 	    case MUS_MODPLUG:
  1102 		modplug_stop(music_playing->data.modplug);
  1103 		break;
  1104 #endif
  1105 #ifdef MOD_MUSIC
  1106 	    case MUS_MOD:
  1107 		MOD_stop(music_playing->data.module);
  1108 		break;
  1109 #endif
  1110 #ifdef MID_MUSIC
  1111 	    case MUS_MID:
  1112 #ifdef USE_NATIVE_MIDI
  1113 		if ( native_midi_ok ) {
  1114 			native_midi_stop();
  1115 			goto skip;
  1116 		}
  1117 #endif
  1118 #ifdef USE_FLUIDSYNTH_MIDI
  1119 		if ( fluidsynth_ok ) {
  1120 			fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1121 			goto skip;
  1122 		}
  1123 #endif
  1124 #ifdef USE_TIMIDITY_MIDI
  1125 		if ( timidity_ok ) {
  1126 			Timidity_Stop();
  1127 			goto skip;
  1128 		}
  1129 #endif
  1130 		break;
  1131 #endif
  1132 #ifdef OGG_MUSIC
  1133 	    case MUS_OGG:
  1134 		OGG_stop(music_playing->data.ogg);
  1135 		break;
  1136 #endif
  1137 #ifdef FLAC_MUSIC
  1138 	    case MUS_FLAC:
  1139 		FLAC_stop(music_playing->data.flac);
  1140 		break;
  1141 #endif
  1142 #ifdef MP3_MUSIC
  1143 	    case MUS_MP3:
  1144 		smpeg.SMPEG_stop(music_playing->data.mp3);
  1145 		break;
  1146 #endif
  1147 #ifdef MP3_MAD_MUSIC
  1148 	    case MUS_MP3_MAD:
  1149 		mad_stop(music_playing->data.mp3_mad);
  1150 		break;
  1151 #endif
  1152 	    default:
  1153 		/* Unknown music type?? */
  1154 		return;
  1155 	}
  1156 
  1157 skip:
  1158 	music_playing->fading = MIX_NO_FADING;
  1159 	music_playing = NULL;
  1160 }
  1161 int Mix_HaltMusic(void)
  1162 {
  1163 	SDL_LockAudio();
  1164 	if ( music_playing ) {
  1165 		music_internal_halt();
  1166 	}
  1167 	SDL_UnlockAudio();
  1168 
  1169 	return(0);
  1170 }
  1171 
  1172 /* Progressively stop the music */
  1173 int Mix_FadeOutMusic(int ms)
  1174 {
  1175 	int retval = 0;
  1176 
  1177 	if ( ms_per_step == 0 ) {
  1178 		SDL_SetError("Audio device hasn't been opened");
  1179 		return 0;
  1180 	}
  1181 
  1182 	if (ms <= 0) {  /* just halt immediately. */
  1183 		Mix_HaltMusic();
  1184 		return 1;
  1185 	}
  1186 
  1187 	SDL_LockAudio();
  1188 	if ( music_playing) {
  1189                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1190                 if ( music_playing->fading == MIX_NO_FADING ) {
  1191 	        	music_playing->fade_step = 0;
  1192                 } else {
  1193                         int step;
  1194                         int old_fade_steps = music_playing->fade_steps;
  1195                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1196                                 step = music_playing->fade_step;
  1197                         } else {
  1198                                 step = old_fade_steps
  1199                                         - music_playing->fade_step + 1;
  1200                         }
  1201                         music_playing->fade_step = (step * fade_steps)
  1202                                 / old_fade_steps;
  1203                 }
  1204 		music_playing->fading = MIX_FADING_OUT;
  1205 		music_playing->fade_steps = fade_steps;
  1206 		retval = 1;
  1207 	}
  1208 	SDL_UnlockAudio();
  1209 
  1210 	return(retval);
  1211 }
  1212 
  1213 Mix_Fading Mix_FadingMusic(void)
  1214 {
  1215 	Mix_Fading fading = MIX_NO_FADING;
  1216 
  1217 	SDL_LockAudio();
  1218 	if ( music_playing ) {
  1219 		fading = music_playing->fading;
  1220 	}
  1221 	SDL_UnlockAudio();
  1222 
  1223 	return(fading);
  1224 }
  1225 
  1226 /* Pause/Resume the music stream */
  1227 void Mix_PauseMusic(void)
  1228 {
  1229 	music_active = 0;
  1230 }
  1231 
  1232 void Mix_ResumeMusic(void)
  1233 {
  1234 	music_active = 1;
  1235 }
  1236 
  1237 void Mix_RewindMusic(void)
  1238 {
  1239 	Mix_SetMusicPosition(0.0);
  1240 }
  1241 
  1242 int Mix_PausedMusic(void)
  1243 {
  1244 	return (music_active == 0);
  1245 }
  1246 
  1247 /* Check the status of the music */
  1248 static int music_internal_playing()
  1249 {
  1250 	int playing = 1;
  1251 
  1252 	if (music_playing == NULL) {
  1253 		return 0;
  1254 	}
  1255 
  1256 	switch (music_playing->type) {
  1257 #ifdef CMD_MUSIC
  1258 	    case MUS_CMD:
  1259 		if (!MusicCMD_Active(music_playing->data.cmd)) {
  1260 			playing = 0;
  1261 		}
  1262 		break;
  1263 #endif
  1264 #ifdef WAV_MUSIC
  1265 	    case MUS_WAV:
  1266 		if ( ! WAVStream_Active() ) {
  1267 			playing = 0;
  1268 		}
  1269 		break;
  1270 #endif
  1271 #ifdef MODPLUG_MUSIC
  1272 	    case MUS_MODPLUG:
  1273 		if ( ! modplug_playing(music_playing->data.modplug) ) {
  1274 			playing = 0;
  1275 		}
  1276 		break;
  1277 #endif
  1278 #ifdef MOD_MUSIC
  1279 	    case MUS_MOD:
  1280 		if ( ! MOD_playing(music_playing->data.module) ) {
  1281 			playing = 0;
  1282 		}
  1283 		break;
  1284 #endif
  1285 #ifdef MID_MUSIC
  1286 	    case MUS_MID:
  1287 #ifdef USE_NATIVE_MIDI
  1288 		if ( native_midi_ok ) {
  1289 			if ( ! native_midi_active() )
  1290 				playing = 0;
  1291 			goto skip;
  1292 		}
  1293 #endif
  1294 #ifdef USE_FLUIDSYNTH_MIDI
  1295 		if ( fluidsynth_ok ) {
  1296 			if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1297 				playing = 0;
  1298 			goto skip;
  1299 		}
  1300 #endif
  1301 #ifdef USE_TIMIDITY_MIDI
  1302 		if ( timidity_ok ) {
  1303 			if ( ! Timidity_Active() )
  1304 				playing = 0;
  1305 			goto skip;
  1306 		}
  1307 #endif
  1308 		break;
  1309 #endif
  1310 #ifdef OGG_MUSIC
  1311 	    case MUS_OGG:
  1312 		if ( ! OGG_playing(music_playing->data.ogg) ) {
  1313 			playing = 0;
  1314 		}
  1315 		break;
  1316 #endif
  1317 #ifdef FLAC_MUSIC
  1318 	    case MUS_FLAC:
  1319 		if ( ! FLAC_playing(music_playing->data.flac) ) {
  1320 			playing = 0;
  1321 		}
  1322 		break;
  1323 #endif
  1324 #ifdef MP3_MUSIC
  1325 	    case MUS_MP3:
  1326 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1327 			playing = 0;
  1328 		break;
  1329 #endif
  1330 #ifdef MP3_MAD_MUSIC
  1331 	    case MUS_MP3_MAD:
  1332 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1333 			playing = 0;
  1334 		}
  1335 		break;
  1336 #endif
  1337 	    default:
  1338 		playing = 0;
  1339 		break;
  1340 	}
  1341 
  1342 skip:
  1343 	return(playing);
  1344 }
  1345 int Mix_PlayingMusic(void)
  1346 {
  1347 	int playing = 0;
  1348 
  1349 	SDL_LockAudio();
  1350 	if ( music_playing ) {
  1351 		playing = music_loops || music_internal_playing();
  1352 	}
  1353 	SDL_UnlockAudio();
  1354 
  1355 	return(playing);
  1356 }
  1357 
  1358 /* Set the external music playback command */
  1359 int Mix_SetMusicCMD(const char *command)
  1360 {
  1361 	Mix_HaltMusic();
  1362 	if ( music_cmd ) {
  1363 		free(music_cmd);
  1364 		music_cmd = NULL;
  1365 	}
  1366 	if ( command ) {
  1367 		music_cmd = (char *)malloc(strlen(command)+1);
  1368 		if ( music_cmd == NULL ) {
  1369 			return(-1);
  1370 		}
  1371 		strcpy(music_cmd, command);
  1372 	}
  1373 	return(0);
  1374 }
  1375 
  1376 int Mix_SetSynchroValue(int i)
  1377 {
  1378 	/* Not supported by any players at this time */
  1379 	return(-1);
  1380 }
  1381 
  1382 int Mix_GetSynchroValue(void)
  1383 {
  1384 	/* Not supported by any players at this time */
  1385 	return(-1);
  1386 }
  1387 
  1388 
  1389 /* Uninitialize the music players */
  1390 void close_music(void)
  1391 {
  1392 	Mix_HaltMusic();
  1393 #ifdef CMD_MUSIC
  1394 	Mix_SetMusicCMD(NULL);
  1395 #endif
  1396 #ifdef MODPLUG_MUSIC
  1397 	modplug_exit();
  1398 #endif
  1399 #ifdef MOD_MUSIC
  1400 	MOD_exit();
  1401 #endif
  1402 #ifdef MID_MUSIC
  1403 # ifdef USE_TIMIDITY_MIDI
  1404 	Timidity_Close();
  1405 # endif
  1406 #endif
  1407 
  1408 	/* rcg06042009 report available decoders at runtime. */
  1409 	free(music_decoders);
  1410 	music_decoders = NULL;
  1411 	num_decoders = 0;
  1412 
  1413 	ms_per_step = 0;
  1414 }
  1415 
  1416 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
  1417 {
  1418 	Uint8 magic[5];	  /*Apparently there is no way to check if the file is really a MOD,*/
  1419 	/*		    or there are too many formats supported by MikMod or MikMod does */
  1420 	/*		    this check by itself. If someone implements other formats (e.g. MP3) */
  1421 	/*		    the check can be uncommented */
  1422 	Uint8 moremagic[9];
  1423 	Mix_Music *music;
  1424 	int start;
  1425 	int freerw = 0;
  1426 
  1427 	if (!rw) {
  1428 		Mix_SetError("RWops pointer is NULL");
  1429 		return NULL;
  1430 	}
  1431 
  1432 	/* Figure out what kind of file this is */
  1433 	start = SDL_RWtell(rw);
  1434 	if ( SDL_RWread(rw,magic,1,4) != 4 ||
  1435 	     SDL_RWread(rw,moremagic,1,8) != 8 ) {
  1436 		Mix_SetError("Couldn't read from RWops");
  1437 		return NULL;
  1438 	}
  1439 	SDL_RWseek(rw, start, RW_SEEK_SET);
  1440 	magic[4]='\0';
  1441 	moremagic[8] = '\0';
  1442 
  1443 	/* Allocate memory for the music structure */
  1444 	music=(Mix_Music *)malloc(sizeof(Mix_Music));
  1445 	if (music==NULL ) {
  1446 		Mix_SetError("Out of memory");
  1447 		return(NULL);
  1448 	}
  1449 	music->error = 0;
  1450 
  1451 #ifdef WAV_MUSIC
  1452 	/* WAVE files have the magic four bytes "RIFF"
  1453 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
  1454 	 */
  1455 	if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
  1456 	     (strcmp((char *)magic, "FORM") == 0) ) {
  1457 		music->type = MUS_WAV;
  1458 		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freerw);
  1459 		if ( music->data.wave == NULL ) {
  1460 			music->error = 1;
  1461 		}
  1462 
  1463 	} else
  1464 #endif
  1465 #ifdef OGG_MUSIC
  1466 	/* Ogg Vorbis files have the magic four bytes "OggS" */
  1467 	if ( strcmp((char *)magic, "OggS") == 0 ) {
  1468 		music->type = MUS_OGG;
  1469 		music->data.ogg = OGG_new_RW(rw, freerw);
  1470 		if ( music->data.ogg == NULL ) {
  1471 			music->error = 1;
  1472 		}
  1473 	} else
  1474 #endif
  1475 #ifdef FLAC_MUSIC
  1476 	/* FLAC files have the magic four bytes "fLaC" */
  1477 	if ( strcmp((char *)magic, "fLaC") == 0 ) {
  1478 		music->type = MUS_FLAC;
  1479 		music->data.flac = FLAC_new_RW(rw, freerw);
  1480 		if ( music->data.flac == NULL ) {
  1481 			music->error = 1;
  1482 		}
  1483 	} else
  1484 #endif
  1485 #ifdef MP3_MUSIC
  1486 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1487 		if ( Mix_Init(MIX_INIT_MP3) ) {
  1488 			SMPEG_Info info;
  1489 			music->type = MUS_MP3;
  1490 			music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
  1491 			if ( !info.has_audio ) {
  1492 				Mix_SetError("MPEG file does not have any audio stream.");
  1493 				music->error = 1;
  1494 			} else {
  1495 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
  1496 			}
  1497 		} else {
  1498 			music->error = 1;
  1499 		}
  1500 	} else
  1501 #endif
  1502 #ifdef MP3_MAD_MUSIC
  1503 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1504 		music->type = MUS_MP3_MAD;
  1505 		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freerw);
  1506 		if (music->data.mp3_mad == 0) {
  1507 			Mix_SetError("Could not initialize MPEG stream.");
  1508 			music->error = 1;
  1509 		}
  1510 	} else
  1511 #endif
  1512 #ifdef MID_MUSIC
  1513 	/* MIDI files have the magic four bytes "MThd" */
  1514 	if ( strcmp((char *)magic, "MThd") == 0 ) {
  1515 		music->type = MUS_MID;
  1516 #ifdef USE_NATIVE_MIDI
  1517 		if ( native_midi_ok ) {
  1518 			music->data.nativemidi = native_midi_loadsong_RW(rw, freerw);
  1519 	  		if ( music->data.nativemidi == NULL ) {
  1520 		  		Mix_SetError("%s", native_midi_error());
  1521 			  	music->error = 1;
  1522 			}
  1523 			goto skip;
  1524 		}
  1525 #endif
  1526 #ifdef USE_FLUIDSYNTH_MIDI
  1527 		if ( fluidsynth_ok ) {
  1528 			music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freerw);
  1529 			if ( music->data.fluidsynthmidi == NULL ) {
  1530 				music->error = 1;
  1531 			}
  1532 			goto skip;
  1533 		}
  1534 #endif
  1535 #ifdef USE_TIMIDITY_MIDI
  1536 		if ( timidity_ok ) {
  1537 			music->data.midi = Timidity_LoadSong_RW(rw, freerw);
  1538 			if ( music->data.midi == NULL ) {
  1539 				Mix_SetError("%s", Timidity_Error());
  1540 				music->error = 1;
  1541 			}
  1542 		} else {
  1543 			Mix_SetError("%s", Timidity_Error());
  1544 			music->error = 1;
  1545 		}
  1546 #endif
  1547 	} else
  1548 #endif
  1549 #if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
  1550 	if (1) {
  1551 		music->error = 1;
  1552 #ifdef MODPLUG_MUSIC
  1553 		if ( music->error ) {
  1554 			music->type = MUS_MODPLUG;
  1555 			music->data.modplug = modplug_new_RW(rw, freerw);
  1556 			if ( music->data.modplug ) {
  1557 				music->error = 0;
  1558 			}
  1559 		}
  1560 #endif
  1561 #ifdef MOD_MUSIC
  1562 		if ( music->error ) {
  1563 			music->type = MUS_MOD;
  1564 			music->data.module = MOD_new_RW(rw, freerw);
  1565 			if ( music->data.module ) {
  1566 				music->error = 0;
  1567 			}
  1568 		}
  1569 #endif
  1570 	} else
  1571 #endif /* MODPLUG_MUSIC || MOD_MUSIC */
  1572 	{
  1573 		Mix_SetError("Unrecognized music format");
  1574 		music->error=1;
  1575 	}
  1576 
  1577 skip:
  1578 	if (music->error) {
  1579 		free(music);
  1580 		music=NULL;
  1581 	}
  1582 	return(music);
  1583 }
  1584 
  1585 int Mix_SetSoundFonts(const char *paths)
  1586 {
  1587 #ifdef MID_MUSIC
  1588 	if (soundfont_paths) {
  1589 		free(soundfont_paths);
  1590 		soundfont_paths = NULL;
  1591 	}
  1592 
  1593 	if (paths) {
  1594 		if (!(soundfont_paths = strdup(paths))) {
  1595 			Mix_SetError("Insufficient memory to set SoundFonts");
  1596 			return 0;
  1597 		}
  1598 	}
  1599 #endif
  1600 	return 1;
  1601 }
  1602 
  1603 #ifdef MID_MUSIC
  1604 const char* Mix_GetSoundFonts(void)
  1605 {
  1606 	const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1607 
  1608 	if (!soundfont_paths || (force && force[0] == '1')) {
  1609 		return getenv("SDL_SOUNDFONTS");
  1610 	} else {
  1611 		return soundfont_paths;
  1612 	}
  1613 }
  1614 
  1615 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1616 {
  1617 	char *context, *path, *paths;
  1618 	const char* cpaths = Mix_GetSoundFonts();
  1619 
  1620 	if (!cpaths) {
  1621 		Mix_SetError("No SoundFonts have been requested");
  1622 		return 0;
  1623 	}
  1624 
  1625 	if (!(paths = strdup(cpaths))) {
  1626 		Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1627 		return 0;
  1628 	}
  1629 
  1630 #if defined(__MINGW32__) || defined(__MINGW64__)
  1631 	for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1632 #elif defined(_WIN32)
  1633 	for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1634 #else
  1635 	for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1636 #endif
  1637 		if (!function(path, data)) {
  1638 			free(paths);
  1639 			return 0;
  1640 		}
  1641 	}
  1642 
  1643 	free(paths);
  1644 	return 1;
  1645 }
  1646 #endif