music.c
author Ozkan Sezer <sezeroz@gmail.com>
Sun, 07 Oct 2018 00:02:40 +0300
branchSDL-1.2
changeset 870 329ecac70afb
parent 864 c8dc1ec196f5
child 871 284d10d87cc9
permissions -rw-r--r--
fix a typo. (from 2.0 branch commit 6fa075aa693e).
     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 				return MUS_NONE;
   626 			}
   627 			SDL_RWseek(rw, start, RW_SEEK_SET);
   628 			magic[4] = '\0';
   629 			music->type = MUS_WAV;
   630 			music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc);
   631 		}
   632 		if (music->data.wave == NULL) {
   633 			music->error = 1;
   634 		}
   635 		break;
   636 #endif
   637 #ifdef OGG_MUSIC
   638 	case MUS_OGG:
   639 		music->type = MUS_OGG;
   640 		music->data.ogg = OGG_new_RW(rw, freesrc);
   641 		if ( music->data.ogg == NULL ) {
   642 			music->error = 1;
   643 		}
   644 		break;
   645 #endif
   646 #ifdef FLAC_MUSIC
   647 	case MUS_FLAC:
   648 		music->type = MUS_FLAC;
   649 		music->data.flac = FLAC_new_RW(rw, freesrc);
   650 		if ( music->data.flac == NULL ) {
   651 			music->error = 1;
   652 		}
   653 		break;
   654 #endif
   655 #ifdef MP3_MUSIC
   656 	case MUS_MP3:
   657 		if ( Mix_Init(MIX_INIT_MP3) ) {
   658 			SMPEG_Info info;
   659 			music->type = MUS_MP3;
   660 			music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
   661 			if ( !info.has_audio ) {
   662 				Mix_SetError("MPEG file does not have any audio stream.");
   663 				music->error = 1;
   664 			} else {
   665 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   666 			}
   667 		} else {
   668 			music->error = 1;
   669 		}
   670 		break;
   671 #elif defined(MP3_MAD_MUSIC)
   672 	case MUS_MP3:
   673 		music->type = MUS_MP3_MAD;
   674 		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc);
   675 		if (music->data.mp3_mad == 0) {
   676 			Mix_SetError("Could not initialize MPEG stream.");
   677 			music->error = 1;
   678 		}
   679 		break;
   680 #endif
   681 #ifdef MID_MUSIC
   682 	case MUS_MID:
   683 		music->type = MUS_MID;
   684 #ifdef USE_NATIVE_MIDI
   685 		if ( native_midi_ok ) {
   686 			music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc);
   687 	  		if ( music->data.nativemidi == NULL ) {
   688 		  		Mix_SetError("%s", native_midi_error());
   689 			  	music->error = 1;
   690 			}
   691 			break;
   692 		}
   693 #endif
   694 #ifdef USE_FLUIDSYNTH_MIDI
   695 		if ( fluidsynth_ok ) {
   696 			music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc);
   697 			if ( music->data.fluidsynthmidi == NULL ) {
   698 				music->error = 1;
   699 			}
   700 			break;
   701 		}
   702 #endif
   703 #ifdef USE_TIMIDITY_MIDI
   704 		if ( timidity_ok ) {
   705 			music->data.midi = Timidity_LoadSong_RW(rw, freesrc);
   706 			if ( music->data.midi == NULL ) {
   707 				Mix_SetError("%s", Timidity_Error());
   708 				music->error = 1;
   709 			}
   710 		} else {
   711 			Mix_SetError("%s", Timidity_Error());
   712 			music->error = 1;
   713 		}
   714 #endif
   715 		break;
   716 #endif
   717 #if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
   718 	case MUS_MOD:
   719 		music->error = 1;
   720 #ifdef MODPLUG_MUSIC
   721 		if ( music->error ) {
   722 			music->type = MUS_MODPLUG;
   723 			music->data.modplug = modplug_new_RW(rw, freesrc);
   724 			if ( music->data.modplug ) {
   725 				music->error = 0;
   726 			}
   727 		}
   728 #endif
   729 #ifdef MOD_MUSIC
   730 		if ( music->error ) {
   731 			music->type = MUS_MOD;
   732 			music->data.module = MOD_new_RW(rw, freesrc);
   733 			if ( music->data.module ) {
   734 				music->error = 0;
   735 			}
   736 		}
   737 #endif
   738 		break;
   739 #endif
   740 
   741 	default:
   742 		Mix_SetError("Unrecognized music format");
   743 		music->error=1;
   744 	} /* switch (want) */
   745 
   746 
   747 	if (music->error) {
   748 		SDL_free(music);
   749 		music=NULL;
   750 	}
   751 	return(music);
   752 }
   753 
   754 /* Free a music chunk previously loaded */
   755 void Mix_FreeMusic(Mix_Music *music)
   756 {
   757 	if ( music ) {
   758 		/* Stop the music if it's currently playing */
   759 		SDL_LockAudio();
   760 		if ( music == music_playing ) {
   761 			/* Wait for any fade out to finish */
   762 			while ( music->fading == MIX_FADING_OUT ) {
   763 				SDL_UnlockAudio();
   764 				SDL_Delay(100);
   765 				SDL_LockAudio();
   766 			}
   767 			if ( music == music_playing ) {
   768 				music_internal_halt();
   769 			}
   770 		}
   771 		SDL_UnlockAudio();
   772 		switch (music->type) {
   773 #ifdef CMD_MUSIC
   774 			case MUS_CMD:
   775 				MusicCMD_FreeSong(music->data.cmd);
   776 				break;
   777 #endif
   778 #ifdef WAV_MUSIC
   779 			case MUS_WAV:
   780 				WAVStream_FreeSong(music->data.wave);
   781 				break;
   782 #endif
   783 #ifdef MODPLUG_MUSIC
   784 			case MUS_MODPLUG:
   785 				modplug_delete(music->data.modplug);
   786 				break;
   787 #endif
   788 #ifdef MOD_MUSIC
   789 			case MUS_MOD:
   790 				MOD_delete(music->data.module);
   791 				break;
   792 #endif
   793 #ifdef MID_MUSIC
   794 			case MUS_MID:
   795 #ifdef USE_NATIVE_MIDI
   796   				if ( native_midi_ok ) {
   797 					native_midi_freesong(music->data.nativemidi);
   798 					goto skip;
   799 				}
   800 #endif
   801 #ifdef USE_FLUIDSYNTH_MIDI
   802 				if ( fluidsynth_ok ) {
   803 					fluidsynth_freesong(music->data.fluidsynthmidi);
   804 					goto skip;
   805 				}
   806 #endif
   807 #ifdef USE_TIMIDITY_MIDI
   808 				if ( timidity_ok ) {
   809 					Timidity_FreeSong(music->data.midi);
   810 					goto skip;
   811 				}
   812 #endif
   813 				break;
   814 #endif
   815 #ifdef OGG_MUSIC
   816 			case MUS_OGG:
   817 				OGG_delete(music->data.ogg);
   818 				break;
   819 #endif
   820 #ifdef FLAC_MUSIC
   821 			case MUS_FLAC:
   822 				FLAC_delete(music->data.flac);
   823 				break;
   824 #endif
   825 #ifdef MP3_MUSIC
   826 			case MUS_MP3:
   827 				smpeg.SMPEG_delete(music->data.mp3);
   828 				break;
   829 #endif
   830 #ifdef MP3_MAD_MUSIC
   831 			case MUS_MP3_MAD:
   832 				mad_closeFile(music->data.mp3_mad);
   833 				break;
   834 #endif
   835 			default:
   836 				/* Unknown music type?? */
   837 				break;
   838 		}
   839 
   840     skip:
   841 		SDL_free(music);
   842 	}
   843 }
   844 
   845 /* Find out the music format of a mixer music, or the currently playing
   846    music, if 'music' is NULL.
   847 */
   848 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   849 {
   850 	Mix_MusicType type = MUS_NONE;
   851 
   852 	if ( music ) {
   853 		type = music->type;
   854 	} else {
   855 		SDL_LockAudio();
   856 		if ( music_playing ) {
   857 			type = music_playing->type;
   858 		}
   859 		SDL_UnlockAudio();
   860 	}
   861 	return(type);
   862 }
   863 
   864 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   865  */
   866 static int music_internal_play(Mix_Music *music, double position)
   867 {
   868 	int retval = 0;
   869 
   870 #if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
   871 	/* This fixes a bug with native MIDI on Mac OS X, where you
   872 	   can't really stop and restart MIDI from the audio callback.
   873 	*/
   874 	if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
   875 		/* Just a seek suffices to restart playing */
   876 		music_internal_position(position);
   877 		return 0;
   878 	}
   879 #endif
   880 
   881 	/* Note the music we're playing */
   882 	if ( music_playing ) {
   883 		music_internal_halt();
   884 	}
   885 	music_playing = music;
   886 
   887 	/* Set the initial volume */
   888 	if ( music->type != MUS_MOD ) {
   889 		music_internal_initialize_volume();
   890 	}
   891 
   892 	/* Set up for playback */
   893 	switch (music->type) {
   894 #ifdef CMD_MUSIC
   895 	    case MUS_CMD:
   896 		MusicCMD_Start(music->data.cmd);
   897 		break;
   898 #endif
   899 #ifdef WAV_MUSIC
   900 	    case MUS_WAV:
   901 		WAVStream_Start(music->data.wave);
   902 		break;
   903 #endif
   904 #ifdef MODPLUG_MUSIC
   905 	    case MUS_MODPLUG:
   906 		/* can't set volume until file is loaded, so finally set it now */
   907 		music_internal_initialize_volume();
   908 		modplug_play(music->data.modplug);
   909 		break;
   910 #endif
   911 #ifdef MOD_MUSIC
   912 	    case MUS_MOD:
   913 		MOD_play(music->data.module);
   914 		/* Player_SetVolume() does nothing before Player_Start() */
   915 		music_internal_initialize_volume();
   916 		break;
   917 #endif
   918 #ifdef MID_MUSIC
   919 	    case MUS_MID:
   920 #ifdef USE_NATIVE_MIDI
   921 		if ( native_midi_ok ) {
   922 			native_midi_start(music->data.nativemidi, music_loops);
   923 			goto skip;
   924 		}
   925 #endif
   926 #ifdef USE_FLUIDSYNTH_MIDI
   927 		if (fluidsynth_ok ) {
   928 			fluidsynth_start(music->data.fluidsynthmidi);
   929 			goto skip;
   930 		}
   931 #endif
   932 #ifdef USE_TIMIDITY_MIDI
   933 		if ( timidity_ok ) {
   934 			Timidity_Start(music->data.midi);
   935 			goto skip;
   936 		}
   937 #endif
   938 		break;
   939 #endif
   940 #ifdef OGG_MUSIC
   941 	    case MUS_OGG:
   942 		OGG_play(music->data.ogg);
   943 		break;
   944 #endif
   945 #ifdef FLAC_MUSIC
   946 	    case MUS_FLAC:
   947 		FLAC_play(music->data.flac);
   948 		break;
   949 #endif
   950 #ifdef MP3_MUSIC
   951 	    case MUS_MP3:
   952 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
   953 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
   954 		smpeg.SMPEG_play(music_playing->data.mp3);
   955 		break;
   956 #endif
   957 #ifdef MP3_MAD_MUSIC
   958 	    case MUS_MP3_MAD:
   959 		mad_start(music->data.mp3_mad);
   960 		break;
   961 #endif
   962 	    default:
   963 		Mix_SetError("Can't play unknown music type");
   964 		retval = -1;
   965 		break;
   966 	}
   967 
   968 skip:
   969 	/* Set the playback position, note any errors if an offset is used */
   970 	if ( retval == 0 ) {
   971 		if ( position > 0.0 ) {
   972 			if ( music_internal_position(position) < 0 ) {
   973 				Mix_SetError("Position not implemented for music type");
   974 				retval = -1;
   975 			}
   976 		} else {
   977 			music_internal_position(0.0);
   978 		}
   979 	}
   980 
   981 	/* If the setup failed, we're not playing any music anymore */
   982 	if ( retval < 0 ) {
   983 		music_playing = NULL;
   984 	}
   985 	return(retval);
   986 }
   987 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   988 {
   989 	int retval;
   990 
   991 	if ( ms_per_step == 0 ) {
   992 		SDL_SetError("Audio device hasn't been opened");
   993 		return(-1);
   994 	}
   995 
   996 	/* Don't play null pointers :-) */
   997 	if ( music == NULL ) {
   998 		Mix_SetError("music parameter was NULL");
   999 		return(-1);
  1000 	}
  1001 
  1002 	/* Setup the data */
  1003 	if ( ms ) {
  1004 		music->fading = MIX_FADING_IN;
  1005 	} else {
  1006 		music->fading = MIX_NO_FADING;
  1007 	}
  1008 	music->fade_step = 0;
  1009 	music->fade_steps = ms/ms_per_step;
  1010 
  1011 	/* Play the puppy */
  1012 	SDL_LockAudio();
  1013 	/* If the current music is fading out, wait for the fade to complete */
  1014 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
  1015 		SDL_UnlockAudio();
  1016 		SDL_Delay(100);
  1017 		SDL_LockAudio();
  1018 	}
  1019 	if (loops == 1) {
  1020 		/* Loop is the number of times to play the audio */
  1021 		loops = 0;
  1022 	}
  1023 	music_loops = loops;
  1024 	retval = music_internal_play(music, position);
  1025 	music_active = (retval == 0);
  1026 	SDL_UnlockAudio();
  1027 
  1028 	return(retval);
  1029 }
  1030 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
  1031 {
  1032 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
  1033 }
  1034 int Mix_PlayMusic(Mix_Music *music, int loops)
  1035 {
  1036 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
  1037 }
  1038 
  1039 /* Set the playing music position */
  1040 int music_internal_position(double position)
  1041 {
  1042 	int retval = 0;
  1043 
  1044 	switch (music_playing->type) {
  1045 #ifdef MODPLUG_MUSIC
  1046 	    case MUS_MODPLUG:
  1047 		modplug_jump_to_time(music_playing->data.modplug, position);
  1048 		break;
  1049 #endif
  1050 #ifdef MOD_MUSIC
  1051 	    case MUS_MOD:
  1052 		MOD_jump_to_time(music_playing->data.module, position);
  1053 		break;
  1054 #endif
  1055 #ifdef OGG_MUSIC
  1056 	    case MUS_OGG:
  1057 		OGG_jump_to_time(music_playing->data.ogg, position);
  1058 		break;
  1059 #endif
  1060 #ifdef FLAC_MUSIC
  1061 	    case MUS_FLAC:
  1062 		FLAC_jump_to_time(music_playing->data.flac, position);
  1063 		break;
  1064 #endif
  1065 #ifdef MP3_MUSIC
  1066 	    case MUS_MP3:
  1067 		smpeg.SMPEG_rewind(music_playing->data.mp3);
  1068 		smpeg.SMPEG_play(music_playing->data.mp3);
  1069 		if ( position > 0.0 ) {
  1070 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
  1071 		}
  1072 		break;
  1073 #endif
  1074 #ifdef MP3_MAD_MUSIC
  1075 	    case MUS_MP3_MAD:
  1076 		mad_seek(music_playing->data.mp3_mad, position);
  1077 		break;
  1078 #endif
  1079 	    default:
  1080 		/* TODO: Implement this for other music backends */
  1081 		retval = -1;
  1082 		break;
  1083 	}
  1084 	return(retval);
  1085 }
  1086 int Mix_SetMusicPosition(double position)
  1087 {
  1088 	int retval;
  1089 
  1090 	SDL_LockAudio();
  1091 	if ( music_playing ) {
  1092 		retval = music_internal_position(position);
  1093 		if ( retval < 0 ) {
  1094 			Mix_SetError("Position not implemented for music type");
  1095 		}
  1096 	} else {
  1097 		Mix_SetError("Music isn't playing");
  1098 		retval = -1;
  1099 	}
  1100 	SDL_UnlockAudio();
  1101 
  1102 	return(retval);
  1103 }
  1104 
  1105 /* Set the music's initial volume */
  1106 static void music_internal_initialize_volume(void)
  1107 {
  1108 	if ( music_playing->fading == MIX_FADING_IN ) {
  1109 		music_internal_volume(0);
  1110 	} else {
  1111 		music_internal_volume(music_volume);
  1112 	}
  1113 }
  1114 
  1115 /* Set the music volume */
  1116 static void music_internal_volume(int volume)
  1117 {
  1118 	switch (music_playing->type) {
  1119 #ifdef CMD_MUSIC
  1120 	    case MUS_CMD:
  1121 		MusicCMD_SetVolume(volume);
  1122 		break;
  1123 #endif
  1124 #ifdef WAV_MUSIC
  1125 	    case MUS_WAV:
  1126 		WAVStream_SetVolume(volume);
  1127 		break;
  1128 #endif
  1129 #ifdef MODPLUG_MUSIC
  1130 	    case MUS_MODPLUG:
  1131 		modplug_setvolume(music_playing->data.modplug, volume);
  1132 		break;
  1133 #endif
  1134 #ifdef MOD_MUSIC
  1135 	    case MUS_MOD:
  1136 		MOD_setvolume(music_playing->data.module, volume);
  1137 		break;
  1138 #endif
  1139 #ifdef MID_MUSIC
  1140 	    case MUS_MID:
  1141 #ifdef USE_NATIVE_MIDI
  1142 		if ( native_midi_ok ) {
  1143 			native_midi_setvolume(volume);
  1144 			return;
  1145 		}
  1146 #endif
  1147 #ifdef USE_FLUIDSYNTH_MIDI
  1148 		if ( fluidsynth_ok ) {
  1149 			fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1150 			return;
  1151 		}
  1152 #endif
  1153 #ifdef USE_TIMIDITY_MIDI
  1154 		if ( timidity_ok ) {
  1155 			Timidity_SetVolume(volume);
  1156 			return;
  1157 		}
  1158 #endif
  1159 		break;
  1160 #endif
  1161 #ifdef OGG_MUSIC
  1162 	    case MUS_OGG:
  1163 		OGG_setvolume(music_playing->data.ogg, volume);
  1164 		break;
  1165 #endif
  1166 #ifdef FLAC_MUSIC
  1167 	    case MUS_FLAC:
  1168 		FLAC_setvolume(music_playing->data.flac, volume);
  1169 		break;
  1170 #endif
  1171 #ifdef MP3_MUSIC
  1172 	    case MUS_MP3:
  1173 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1174 		break;
  1175 #endif
  1176 #ifdef MP3_MAD_MUSIC
  1177 	    case MUS_MP3_MAD:
  1178 		mad_setVolume(music_playing->data.mp3_mad, volume);
  1179 		break;
  1180 #endif
  1181 	    default:
  1182 		/* Unknown music type?? */
  1183 		break;
  1184 	}
  1185 }
  1186 int Mix_VolumeMusic(int volume)
  1187 {
  1188 	int prev_volume;
  1189 
  1190 	prev_volume = music_volume;
  1191 	if ( volume < 0 ) {
  1192 		return prev_volume;
  1193 	}
  1194 	if ( volume > SDL_MIX_MAXVOLUME ) {
  1195 		volume = SDL_MIX_MAXVOLUME;
  1196 	}
  1197 	music_volume = volume;
  1198 	SDL_LockAudio();
  1199 	if ( music_playing ) {
  1200 		music_internal_volume(music_volume);
  1201 	}
  1202 	SDL_UnlockAudio();
  1203 	return(prev_volume);
  1204 }
  1205 
  1206 /* Halt playing of music */
  1207 static void music_internal_halt(void)
  1208 {
  1209 	switch (music_playing->type) {
  1210 #ifdef CMD_MUSIC
  1211 	    case MUS_CMD:
  1212 		MusicCMD_Stop(music_playing->data.cmd);
  1213 		break;
  1214 #endif
  1215 #ifdef WAV_MUSIC
  1216 	    case MUS_WAV:
  1217 		WAVStream_Stop();
  1218 		break;
  1219 #endif
  1220 #ifdef MODPLUG_MUSIC
  1221 	    case MUS_MODPLUG:
  1222 		modplug_stop(music_playing->data.modplug);
  1223 		break;
  1224 #endif
  1225 #ifdef MOD_MUSIC
  1226 	    case MUS_MOD:
  1227 		MOD_stop(music_playing->data.module);
  1228 		break;
  1229 #endif
  1230 #ifdef MID_MUSIC
  1231 	    case MUS_MID:
  1232 #ifdef USE_NATIVE_MIDI
  1233 		if ( native_midi_ok ) {
  1234 			native_midi_stop();
  1235 			goto skip;
  1236 		}
  1237 #endif
  1238 #ifdef USE_FLUIDSYNTH_MIDI
  1239 		if ( fluidsynth_ok ) {
  1240 			fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1241 			goto skip;
  1242 		}
  1243 #endif
  1244 #ifdef USE_TIMIDITY_MIDI
  1245 		if ( timidity_ok ) {
  1246 			Timidity_Stop();
  1247 			goto skip;
  1248 		}
  1249 #endif
  1250 		break;
  1251 #endif
  1252 #ifdef OGG_MUSIC
  1253 	    case MUS_OGG:
  1254 		OGG_stop(music_playing->data.ogg);
  1255 		break;
  1256 #endif
  1257 #ifdef FLAC_MUSIC
  1258 	    case MUS_FLAC:
  1259 		FLAC_stop(music_playing->data.flac);
  1260 		break;
  1261 #endif
  1262 #ifdef MP3_MUSIC
  1263 	    case MUS_MP3:
  1264 		smpeg.SMPEG_stop(music_playing->data.mp3);
  1265 		break;
  1266 #endif
  1267 #ifdef MP3_MAD_MUSIC
  1268 	    case MUS_MP3_MAD:
  1269 		mad_stop(music_playing->data.mp3_mad);
  1270 		break;
  1271 #endif
  1272 	    default:
  1273 		/* Unknown music type?? */
  1274 		return;
  1275 	}
  1276 
  1277 skip:
  1278 	music_playing->fading = MIX_NO_FADING;
  1279 	music_playing = NULL;
  1280 }
  1281 int Mix_HaltMusic(void)
  1282 {
  1283 	SDL_LockAudio();
  1284 	if ( music_playing ) {
  1285 		music_internal_halt();
  1286 		if ( music_finished_hook ) {
  1287 			music_finished_hook();
  1288 		}
  1289 	}
  1290 	SDL_UnlockAudio();
  1291 
  1292 	return(0);
  1293 }
  1294 
  1295 /* Progressively stop the music */
  1296 int Mix_FadeOutMusic(int ms)
  1297 {
  1298 	int retval = 0;
  1299 
  1300 	if ( ms_per_step == 0 ) {
  1301 		SDL_SetError("Audio device hasn't been opened");
  1302 		return 0;
  1303 	}
  1304 
  1305 	if (ms <= 0) {  /* just halt immediately. */
  1306 		Mix_HaltMusic();
  1307 		return 1;
  1308 	}
  1309 
  1310 	SDL_LockAudio();
  1311 	if ( music_playing) {
  1312                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1313                 if ( music_playing->fading == MIX_NO_FADING ) {
  1314 	        	music_playing->fade_step = 0;
  1315                 } else {
  1316                         int step;
  1317                         int old_fade_steps = music_playing->fade_steps;
  1318                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1319                                 step = music_playing->fade_step;
  1320                         } else {
  1321                                 step = old_fade_steps
  1322                                         - music_playing->fade_step + 1;
  1323                         }
  1324                         music_playing->fade_step = (step * fade_steps)
  1325                                 / old_fade_steps;
  1326                 }
  1327 		music_playing->fading = MIX_FADING_OUT;
  1328 		music_playing->fade_steps = fade_steps;
  1329 		retval = 1;
  1330 	}
  1331 	SDL_UnlockAudio();
  1332 
  1333 	return(retval);
  1334 }
  1335 
  1336 Mix_Fading Mix_FadingMusic(void)
  1337 {
  1338 	Mix_Fading fading = MIX_NO_FADING;
  1339 
  1340 	SDL_LockAudio();
  1341 	if ( music_playing ) {
  1342 		fading = music_playing->fading;
  1343 	}
  1344 	SDL_UnlockAudio();
  1345 
  1346 	return(fading);
  1347 }
  1348 
  1349 /* Pause/Resume the music stream */
  1350 void Mix_PauseMusic(void)
  1351 {
  1352 	music_active = 0;
  1353 }
  1354 
  1355 void Mix_ResumeMusic(void)
  1356 {
  1357 	music_active = 1;
  1358 }
  1359 
  1360 void Mix_RewindMusic(void)
  1361 {
  1362 	Mix_SetMusicPosition(0.0);
  1363 }
  1364 
  1365 int Mix_PausedMusic(void)
  1366 {
  1367 	return (music_active == 0);
  1368 }
  1369 
  1370 /* Check the status of the music */
  1371 static int music_internal_playing()
  1372 {
  1373 	int playing = 1;
  1374 
  1375 	if (music_playing == NULL) {
  1376 		return 0;
  1377 	}
  1378 
  1379 	switch (music_playing->type) {
  1380 #ifdef CMD_MUSIC
  1381 	    case MUS_CMD:
  1382 		if (!MusicCMD_Active(music_playing->data.cmd)) {
  1383 			playing = 0;
  1384 		}
  1385 		break;
  1386 #endif
  1387 #ifdef WAV_MUSIC
  1388 	    case MUS_WAV:
  1389 		if ( ! WAVStream_Active() ) {
  1390 			playing = 0;
  1391 		}
  1392 		break;
  1393 #endif
  1394 #ifdef MODPLUG_MUSIC
  1395 	    case MUS_MODPLUG:
  1396 		if ( ! modplug_playing(music_playing->data.modplug) ) {
  1397 			playing = 0;
  1398 		}
  1399 		break;
  1400 #endif
  1401 #ifdef MOD_MUSIC
  1402 	    case MUS_MOD:
  1403 		if ( ! MOD_playing(music_playing->data.module) ) {
  1404 			playing = 0;
  1405 		}
  1406 		break;
  1407 #endif
  1408 #ifdef MID_MUSIC
  1409 	    case MUS_MID:
  1410 #ifdef USE_NATIVE_MIDI
  1411 		if ( native_midi_ok ) {
  1412 			if ( ! native_midi_active() )
  1413 				playing = 0;
  1414 			goto skip;
  1415 		}
  1416 #endif
  1417 #ifdef USE_FLUIDSYNTH_MIDI
  1418 		if ( fluidsynth_ok ) {
  1419 			if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1420 				playing = 0;
  1421 			goto skip;
  1422 		}
  1423 #endif
  1424 #ifdef USE_TIMIDITY_MIDI
  1425 		if ( timidity_ok ) {
  1426 			if ( ! Timidity_Active() )
  1427 				playing = 0;
  1428 			goto skip;
  1429 		}
  1430 #endif
  1431 		break;
  1432 #endif
  1433 #ifdef OGG_MUSIC
  1434 	    case MUS_OGG:
  1435 		if ( ! OGG_playing(music_playing->data.ogg) ) {
  1436 			playing = 0;
  1437 		}
  1438 		break;
  1439 #endif
  1440 #ifdef FLAC_MUSIC
  1441 	    case MUS_FLAC:
  1442 		if ( ! FLAC_playing(music_playing->data.flac) ) {
  1443 			playing = 0;
  1444 		}
  1445 		break;
  1446 #endif
  1447 #ifdef MP3_MUSIC
  1448 	    case MUS_MP3:
  1449 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1450 			playing = 0;
  1451 		break;
  1452 #endif
  1453 #ifdef MP3_MAD_MUSIC
  1454 	    case MUS_MP3_MAD:
  1455 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1456 			playing = 0;
  1457 		}
  1458 		break;
  1459 #endif
  1460 	    default:
  1461 		playing = 0;
  1462 		break;
  1463 	}
  1464 
  1465 skip:
  1466 	return(playing);
  1467 }
  1468 int Mix_PlayingMusic(void)
  1469 {
  1470 	int playing = 0;
  1471 
  1472 	SDL_LockAudio();
  1473 	if ( music_playing ) {
  1474 		playing = music_loops || music_internal_playing();
  1475 	}
  1476 	SDL_UnlockAudio();
  1477 
  1478 	return(playing);
  1479 }
  1480 
  1481 /* Set the external music playback command */
  1482 int Mix_SetMusicCMD(const char *command)
  1483 {
  1484 	Mix_HaltMusic();
  1485 	if ( music_cmd ) {
  1486 		SDL_free(music_cmd);
  1487 		music_cmd = NULL;
  1488 	}
  1489 	if ( command ) {
  1490 		music_cmd = (char *)SDL_malloc(strlen(command)+1);
  1491 		if ( music_cmd == NULL ) {
  1492 			return(-1);
  1493 		}
  1494 		strcpy(music_cmd, command);
  1495 	}
  1496 	return(0);
  1497 }
  1498 
  1499 int Mix_SetSynchroValue(int i)
  1500 {
  1501 	/* Not supported by any players at this time */
  1502 	return(-1);
  1503 }
  1504 
  1505 int Mix_GetSynchroValue(void)
  1506 {
  1507 	/* Not supported by any players at this time */
  1508 	return(-1);
  1509 }
  1510 
  1511 
  1512 /* Uninitialize the music players */
  1513 void close_music(void)
  1514 {
  1515 	Mix_HaltMusic();
  1516 #ifdef CMD_MUSIC
  1517 	Mix_SetMusicCMD(NULL);
  1518 #endif
  1519 #ifdef MODPLUG_MUSIC
  1520 	modplug_exit();
  1521 #endif
  1522 #ifdef MOD_MUSIC
  1523 	MOD_exit();
  1524 #endif
  1525 #ifdef MID_MUSIC
  1526 # ifdef USE_TIMIDITY_MIDI
  1527 	Timidity_Close();
  1528 # endif
  1529 #endif
  1530 
  1531 	/* rcg06042009 report available decoders at runtime. */
  1532 	SDL_free(music_decoders);
  1533 	music_decoders = NULL;
  1534 	num_decoders = 0;
  1535 
  1536 	ms_per_step = 0;
  1537 }
  1538 
  1539 int Mix_SetSoundFonts(const char *paths)
  1540 {
  1541 #ifdef MID_MUSIC
  1542 	if (soundfont_paths) {
  1543 		SDL_free(soundfont_paths);
  1544 		soundfont_paths = NULL;
  1545 	}
  1546 
  1547 	if (paths) {
  1548 		if (!(soundfont_paths = SDL_strdup(paths))) {
  1549 			Mix_SetError("Insufficient memory to set SoundFonts");
  1550 			return 0;
  1551 		}
  1552 	}
  1553 #endif
  1554 	return 1;
  1555 }
  1556 
  1557 #ifdef MID_MUSIC
  1558 const char* Mix_GetSoundFonts(void)
  1559 {
  1560 	const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1561 
  1562 	if (!soundfont_paths || (force && force[0] == '1')) {
  1563 		return getenv("SDL_SOUNDFONTS");
  1564 	} else {
  1565 		return soundfont_paths;
  1566 	}
  1567 }
  1568 
  1569 int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
  1570 {
  1571 	char *context, *path, *paths;
  1572 	const char* cpaths = Mix_GetSoundFonts();
  1573 
  1574 	if (!cpaths) {
  1575 		Mix_SetError("No SoundFonts have been requested");
  1576 		return 0;
  1577 	}
  1578 
  1579 	if (!(paths = SDL_strdup(cpaths))) {
  1580 		Mix_SetError("Insufficient memory to iterate over SoundFonts");
  1581 		return 0;
  1582 	}
  1583 
  1584 #if defined(__MINGW32__) || defined(__MINGW64__)
  1585 	for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
  1586 #elif defined(_WIN32)
  1587 	for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
  1588 #else
  1589 	for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
  1590 #endif
  1591 		if (!function(path, data)) {
  1592 			SDL_free(paths);
  1593 			return 0;
  1594 		}
  1595 	}
  1596 
  1597 	SDL_free(paths);
  1598 	return 1;
  1599 }
  1600 #endif