music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2012 14:23:22 -0500
changeset 531 f9c790738ec3
parent 529 9ca74f21d466
child 533 f19368c22ebd
permissions -rwxr-xr-x
This fix really is specific to native MIDI on Mac OS X
     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 #ifdef __MACOSX__
   743 	/* This fixes a bug with native MIDI on Mac OS X, where you
   744 	   can't really stop and restart MIDI from the audio callback.
   745 	*/
   746 	if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
   747 		/* Just a seek suffices to restart playing */
   748 		music_internal_position(position);
   749 		return 0;
   750 	}
   751 #endif
   752 
   753 	/* Note the music we're playing */
   754 	if ( music_playing ) {
   755 		music_internal_halt();
   756 	}
   757 	music_playing = music;
   758 
   759 	/* Set the initial volume */
   760 	if ( music->type != MUS_MOD ) {
   761 		music_internal_initialize_volume();
   762 	}
   763 
   764 	/* Set up for playback */
   765 	switch (music->type) {
   766 #ifdef CMD_MUSIC
   767 	    case MUS_CMD:
   768 		MusicCMD_Start(music->data.cmd);
   769 		break;
   770 #endif
   771 #ifdef WAV_MUSIC
   772 	    case MUS_WAV:
   773 		WAVStream_Start(music->data.wave);
   774 		break;
   775 #endif
   776 #ifdef MODPLUG_MUSIC
   777 	    case MUS_MODPLUG:
   778 		/* can't set volume until file is loaded, so finally set it now */
   779 		music_internal_initialize_volume();
   780 		modplug_play(music->data.modplug);
   781 		break;
   782 #endif
   783 #ifdef MOD_MUSIC
   784 	    case MUS_MOD:
   785 		MOD_play(music->data.module);
   786 		/* Player_SetVolume() does nothing before Player_Start() */
   787 		music_internal_initialize_volume();
   788 		break;
   789 #endif
   790 #ifdef MID_MUSIC
   791 	    case MUS_MID:
   792 #ifdef USE_NATIVE_MIDI
   793 		if ( native_midi_ok ) {
   794 			native_midi_start(music->data.nativemidi);
   795 			goto skip;
   796 		}
   797 #endif
   798 #ifdef USE_FLUIDSYNTH_MIDI
   799 		if (fluidsynth_ok ) {
   800 			fluidsynth_start(music->data.fluidsynthmidi);
   801 			goto skip;
   802 		}
   803 #endif
   804 #ifdef USE_TIMIDITY_MIDI
   805 		if ( timidity_ok ) {
   806 			Timidity_Start(music->data.midi);
   807 			goto skip;
   808 		}
   809 #endif
   810 		break;
   811 #endif
   812 #ifdef OGG_MUSIC
   813 	    case MUS_OGG:
   814 		OGG_play(music->data.ogg);
   815 		break;
   816 #endif
   817 #ifdef FLAC_MUSIC
   818 	    case MUS_FLAC:
   819 		FLAC_play(music->data.flac);
   820 		break;
   821 #endif
   822 #ifdef MP3_MUSIC
   823 	    case MUS_MP3:
   824 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
   825 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
   826 		smpeg.SMPEG_play(music_playing->data.mp3);
   827 		break;
   828 #endif
   829 #ifdef MP3_MAD_MUSIC
   830 	    case MUS_MP3_MAD:
   831 		mad_start(music->data.mp3_mad);
   832 		break;
   833 #endif
   834 	    default:
   835 		Mix_SetError("Can't play unknown music type");
   836 		retval = -1;
   837 		break;
   838 	}
   839 
   840 skip:
   841 	/* Set the playback position, note any errors if an offset is used */
   842 	if ( retval == 0 ) {
   843 		if ( position > 0.0 ) {
   844 			if ( music_internal_position(position) < 0 ) {
   845 				Mix_SetError("Position not implemented for music type");
   846 				retval = -1;
   847 			}
   848 		} else {
   849 			music_internal_position(0.0);
   850 		}
   851 	}
   852 
   853 	/* If the setup failed, we're not playing any music anymore */
   854 	if ( retval < 0 ) {
   855 		music_playing = NULL;
   856 	}
   857 	return(retval);
   858 }
   859 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   860 {
   861 	int retval;
   862 
   863 	if ( ms_per_step == 0 ) {
   864 		SDL_SetError("Audio device hasn't been opened");
   865 		return(-1);
   866 	}
   867 
   868 	/* Don't play null pointers :-) */
   869 	if ( music == NULL ) {
   870 		Mix_SetError("music parameter was NULL");
   871 		return(-1);
   872 	}
   873 
   874 	/* Setup the data */
   875 	if ( ms ) {
   876 		music->fading = MIX_FADING_IN;
   877 	} else {
   878 		music->fading = MIX_NO_FADING;
   879 	}
   880 	music->fade_step = 0;
   881 	music->fade_steps = ms/ms_per_step;
   882 
   883 	/* Play the puppy */
   884 	SDL_LockAudio();
   885 	/* If the current music is fading out, wait for the fade to complete */
   886 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
   887 		SDL_UnlockAudio();
   888 		SDL_Delay(100);
   889 		SDL_LockAudio();
   890 	}
   891 	music_active = 1;
   892 	music_loops = loops;
   893 	retval = music_internal_play(music, position);
   894 	SDL_UnlockAudio();
   895 
   896 	return(retval);
   897 }
   898 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   899 {
   900 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   901 }
   902 int Mix_PlayMusic(Mix_Music *music, int loops)
   903 {
   904 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   905 }
   906 
   907 /* Set the playing music position */
   908 int music_internal_position(double position)
   909 {
   910 	int retval = 0;
   911 
   912 	switch (music_playing->type) {
   913 #ifdef MODPLUG_MUSIC
   914 	    case MUS_MODPLUG:
   915 		modplug_jump_to_time(music_playing->data.modplug, position);
   916 		break;
   917 #endif
   918 #ifdef MOD_MUSIC
   919 	    case MUS_MOD:
   920 		MOD_jump_to_time(music_playing->data.module, position);
   921 		break;
   922 #endif
   923 #ifdef MID_MUSIC
   924 	    case MUS_MID:
   925 #ifdef USE_NATIVE_MIDI
   926 		if ( native_midi_ok ) {
   927 			retval = native_midi_jump_to_time(music_playing->data.nativemidi, position);
   928 			break;
   929 		}
   930 #endif
   931 		/* TODO: Implement this for other music backends */
   932 		retval = -1;
   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