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