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