music.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 15 Jun 2011 03:41:31 -0400
changeset 509 777497efacaa
parent 508 de8e7a4f5936
child 510 3a4c352a9a00
permissions -rw-r--r--
Let the music-finished hook start a new track without a skip in the audio.

Previously, there'd be no more music mixed until the next SDL audio callback
fired. Now if the hook (re)starts a track, it'll start mixing right away,
into whatever space is left in the callback where the hook was called.

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