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