music.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 14 Nov 2009 20:44:30 +0000
changeset 479 3d8a5a7b1249
parent 473 60b7e1c4f6b2
child 481 286c27f54ea1
permissions -rw-r--r--
Sam Lantinga - Sat Nov 14 12:38:01 PST 2009
* Fixed initialization error and crashes if MikMod library isn't available
     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 MOD_MUSIC
    42 #include "music_mod.h"
    43 #endif
    44 #ifdef MID_MUSIC
    45 #  ifdef USE_TIMIDITY_MIDI
    46 #    include "timidity.h"
    47 #  endif
    48 #  ifdef USE_NATIVE_MIDI
    49 #    include "native_midi.h"
    50 #  endif
    51 #  if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
    52 #    define MIDI_ELSE	else
    53 #  else
    54 #    define MIDI_ELSE
    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 MOD_MUSIC
    92 		struct MODULE *module;
    93 #endif
    94 #ifdef MID_MUSIC
    95 #ifdef USE_TIMIDITY_MIDI
    96 		MidiSong *midi;
    97 #endif
    98 #ifdef USE_NATIVE_MIDI
    99 		NativeMidiSong *nativemidi;
   100 #endif
   101 #endif
   102 #ifdef OGG_MUSIC
   103 		OGG_music *ogg;
   104 #endif
   105 #ifdef MP3_MUSIC
   106 		SMPEG *mp3;
   107 #endif
   108 #ifdef MP3_MAD_MUSIC
   109 		mad_data *mp3_mad;
   110 #endif
   111 #ifdef FLAC_MUSIC
   112 		FLAC_music *flac;
   113 #endif
   114 	} data;
   115 	Mix_Fading fading;
   116 	int fade_step;
   117 	int fade_steps;
   118 	int error;
   119 };
   120 #ifdef MID_MUSIC
   121 #ifdef USE_TIMIDITY_MIDI
   122 static int timidity_ok;
   123 static int samplesize;
   124 #endif
   125 #ifdef USE_NATIVE_MIDI
   126 static int native_midi_ok;
   127 #endif
   128 #endif
   129 
   130 /* Used to calculate fading steps */
   131 static int ms_per_step;
   132 
   133 /* rcg06042009 report available decoders at runtime. */
   134 static const char **music_decoders = NULL;
   135 static int num_decoders = 0;
   136 
   137 int Mix_GetNumMusicDecoders(void)
   138 {
   139 	return(num_decoders);
   140 }
   141 
   142 const char *Mix_GetMusicDecoder(int index)
   143 {
   144 	if ((index < 0) || (index >= num_decoders)) {
   145 		return NULL;
   146 	}
   147 	return(music_decoders[index]);
   148 }
   149 
   150 static void add_music_decoder(const char *decoder)
   151 {
   152 	void *ptr = realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
   153 	if (ptr == NULL) {
   154 		return;  /* oh well, go on without it. */
   155 	}
   156 	music_decoders = (const char **) ptr;
   157 	music_decoders[num_decoders++] = decoder;
   158 }
   159 
   160 /* Local low-level functions prototypes */
   161 static void music_internal_initialize_volume(void);
   162 static void music_internal_volume(int volume);
   163 static int  music_internal_play(Mix_Music *music, double position);
   164 static int  music_internal_position(double position);
   165 static int  music_internal_playing();
   166 static void music_internal_halt(void);
   167 
   168 
   169 /* Support for hooking when the music has finished */
   170 static void (*music_finished_hook)(void) = NULL;
   171 
   172 void Mix_HookMusicFinished(void (*music_finished)(void))
   173 {
   174 	SDL_LockAudio();
   175 	music_finished_hook = music_finished;
   176 	SDL_UnlockAudio();
   177 }
   178 
   179 
   180 /* If music isn't playing, halt it if no looping is required, restart it */
   181 /* otherwhise. NOP if the music is playing */
   182 static int music_halt_or_loop (void)
   183 {
   184 	/* Restart music if it has to loop */
   185 	
   186 	if (!music_internal_playing()) 
   187 	{
   188 		/* Restart music if it has to loop at a high level */
   189 		if (music_loops && --music_loops)
   190 		{
   191 			Mix_Fading current_fade = music_playing->fading;
   192 			music_internal_play(music_playing, 0.0);
   193 			music_playing->fading = current_fade;
   194 		} 
   195 		else 
   196 		{
   197 			music_internal_halt();
   198 			if (music_finished_hook)
   199 				music_finished_hook();
   200 			
   201 			return 0;
   202 		}
   203 	}
   204 	
   205 	return 1;
   206 }
   207 
   208 
   209 
   210 /* Mixing function */
   211 void music_mixer(void *udata, Uint8 *stream, int len)
   212 {
   213 	int left = 0;
   214 
   215 	if ( music_playing && music_active ) {
   216 		/* Handle fading */
   217 		if ( music_playing->fading != MIX_NO_FADING ) {
   218 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   219 				int volume;
   220 				int fade_step = music_playing->fade_step;
   221 				int fade_steps = music_playing->fade_steps;
   222 
   223 				if ( music_playing->fading == MIX_FADING_OUT ) {
   224 					volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
   225 				} else { /* Fading in */
   226 					volume = (music_volume * fade_step) / fade_steps;
   227 				}
   228 				music_internal_volume(volume);
   229 			} else {
   230 				if ( music_playing->fading == MIX_FADING_OUT ) {
   231 					music_internal_halt();
   232 					if ( music_finished_hook ) {
   233 						music_finished_hook();
   234 					}
   235 					return;
   236 				}
   237 				music_playing->fading = MIX_NO_FADING;
   238 			}
   239 		}
   240 		
   241 		if (music_halt_or_loop() == 0)
   242 			return;
   243 		
   244 		
   245 		switch (music_playing->type) {
   246 #ifdef CMD_MUSIC
   247 			case MUS_CMD:
   248 				/* The playing is done externally */
   249 				break;
   250 #endif
   251 #ifdef WAV_MUSIC
   252 			case MUS_WAV:
   253 				left = WAVStream_PlaySome(stream, len);
   254 				break;
   255 #endif
   256 #ifdef MOD_MUSIC
   257 			case MUS_MOD:
   258 				left = MOD_playAudio(music_playing->data.module, stream, len);
   259 				break;
   260 #endif
   261 #ifdef MID_MUSIC
   262 #ifdef USE_TIMIDITY_MIDI
   263 			case MUS_MID:
   264 				if ( timidity_ok ) {
   265 					int samples = len / samplesize;
   266   					Timidity_PlaySome(stream, samples);
   267 				}
   268 				break;
   269 #endif
   270 #endif
   271 #ifdef OGG_MUSIC
   272 			case MUS_OGG:
   273 				
   274 				left = OGG_playAudio(music_playing->data.ogg, stream, len);
   275 				break;
   276 #endif
   277 #ifdef FLAC_MUSIC
   278 			case MUS_FLAC:
   279 				left = FLAC_playAudio(music_playing->data.flac, stream, len);
   280 				break;
   281 #endif
   282 #ifdef MP3_MUSIC
   283 			case MUS_MP3:
   284 				left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
   285 				break;
   286 #endif
   287 #ifdef MP3_MAD_MUSIC
   288 			case MUS_MP3_MAD:
   289 				left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
   290 				break;
   291 #endif
   292 			default:
   293 				/* Unknown music type?? */
   294 				break;
   295 		}
   296 	}
   297 
   298 	/* Handle seamless music looping */
   299 	if (left > 0 && left < len && music_halt_or_loop()) {
   300 		music_mixer(udata, stream+(len-left), left);
   301 	}
   302 }
   303 
   304 /* Initialize the music players with a certain desired audio format */
   305 int open_music(SDL_AudioSpec *mixer)
   306 {
   307 #ifdef WAV_MUSIC
   308 	if ( WAVStream_Init(mixer) == 0 ) {
   309 		add_music_decoder("WAVE");
   310 	}
   311 #endif
   312 #ifdef MOD_MUSIC
   313 	if ( MOD_init(mixer) == 0 ) {
   314 		add_music_decoder("MIKMOD");
   315 	}
   316 #endif
   317 #ifdef MID_MUSIC
   318 #ifdef USE_TIMIDITY_MIDI
   319 	samplesize = mixer->size / mixer->samples;
   320 	if ( Timidity_Init(mixer->freq, mixer->format,
   321 	                    mixer->channels, mixer->samples) == 0 ) {
   322 		timidity_ok = 1;
   323 		add_music_decoder("TIMIDITY");
   324 	} else {
   325 		timidity_ok = 0;
   326 	}
   327 #endif
   328 #ifdef USE_NATIVE_MIDI
   329 #ifdef USE_TIMIDITY_MIDI
   330 	native_midi_ok = !timidity_ok;
   331 	if ( !native_midi_ok ) {
   332 		native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
   333 	}
   334 	if ( native_midi_ok )
   335 #endif
   336 		native_midi_ok = native_midi_detect();
   337 	if ( native_midi_ok )
   338 		add_music_decoder("NATIVEMIDI");
   339 #endif
   340 #endif
   341 #ifdef OGG_MUSIC
   342 	if ( OGG_init(mixer) == 0 ) {
   343 		add_music_decoder("OGG");
   344 	}
   345 #endif
   346 #ifdef FLAC_MUSIC
   347 	if ( FLAC_init(mixer) == 0 ) {
   348 		add_music_decoder("FLAC");
   349 	}
   350 #endif
   351 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
   352 	/* Keep a copy of the mixer */
   353 	used_mixer = *mixer;
   354 	add_music_decoder("MP3");
   355 #endif
   356 
   357 	music_playing = NULL;
   358 	music_stopped = 0;
   359 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   360 
   361 	/* Calculate the number of ms for each callback */
   362 	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   363 
   364 	return(0);
   365 }
   366 
   367 /* Portable case-insensitive string compare function */
   368 int MIX_string_equals(const char *str1, const char *str2)
   369 {
   370 	while ( *str1 && *str2 ) {
   371 		if ( toupper((unsigned char)*str1) !=
   372 		     toupper((unsigned char)*str2) )
   373 			break;
   374 		++str1;
   375 		++str2;
   376 	}
   377 	return (!*str1 && !*str2);
   378 }
   379 
   380 /* Load a music file */
   381 Mix_Music *Mix_LoadMUS(const char *file)
   382 {
   383 	FILE *fp;
   384 	char *ext;
   385 	Uint8 magic[5], moremagic[9];
   386 	Mix_Music *music;
   387 
   388 	/* Figure out what kind of file this is */
   389 	fp = fopen(file, "rb");
   390 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   391 		if ( fp != NULL ) {
   392 			fclose(fp);
   393 		}
   394 		Mix_SetError("Couldn't read from '%s'", file);
   395 		return(NULL);
   396 	}
   397 	if (!fread(moremagic, 8, 1, fp)) {
   398 		Mix_SetError("Couldn't read from '%s'", file);
   399 		return(NULL);
   400 	}
   401 	magic[4] = '\0';
   402 	moremagic[8] = '\0';
   403 	fclose(fp);
   404 
   405 	/* Figure out the file extension, so we can determine the type */
   406 	ext = strrchr(file, '.');
   407 	if ( ext ) ++ext; /* skip the dot in the extension */
   408 
   409 	/* Allocate memory for the music structure */
   410 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   411 	if ( music == NULL ) {
   412 		Mix_SetError("Out of memory");
   413 		return(NULL);
   414 	}
   415 	music->error = 0;
   416 
   417 #ifdef CMD_MUSIC
   418 	if ( music_cmd ) {
   419 		music->type = MUS_CMD;
   420 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   421 		if ( music->data.cmd == NULL ) {
   422 			music->error = 1;
   423 		}
   424 	} else
   425 #endif
   426 #ifdef WAV_MUSIC
   427 	/* WAVE files have the magic four bytes "RIFF"
   428 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   429 	 */
   430 	if ( (ext && MIX_string_equals(ext, "WAV")) ||
   431 	     ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
   432 	     (strcmp((char *)magic, "FORM") == 0) ) {
   433 		music->type = MUS_WAV;
   434 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   435 		if ( music->data.wave == NULL ) {
   436 		  	Mix_SetError("Unable to load WAV file");
   437 			music->error = 1;
   438 		}
   439 	} else
   440 #endif
   441 #ifdef MID_MUSIC
   442 	/* MIDI files have the magic four bytes "MThd" */
   443 	if ( (ext && MIX_string_equals(ext, "MID")) ||
   444 	     (ext && MIX_string_equals(ext, "MIDI")) ||
   445 	     strcmp((char *)magic, "MThd") == 0  ||
   446 	     ( strcmp((char *)magic, "RIFF") == 0  &&
   447 	  	strcmp((char *)(moremagic+4), "RMID") == 0 ) ) {
   448 		music->type = MUS_MID;
   449 #ifdef USE_NATIVE_MIDI
   450   		if ( native_midi_ok ) {
   451   			music->data.nativemidi = native_midi_loadsong(file);
   452 	  		if ( music->data.nativemidi == NULL ) {
   453 		  		Mix_SetError("%s", native_midi_error());
   454 			  	music->error = 1;
   455 			}
   456 	  	} MIDI_ELSE
   457 #endif
   458 #ifdef USE_TIMIDITY_MIDI
   459 		if ( timidity_ok ) {
   460 			music->data.midi = Timidity_LoadSong(file);
   461 			if ( music->data.midi == NULL ) {
   462 				Mix_SetError("%s", Timidity_Error());
   463 				music->error = 1;
   464 			}
   465 		} else {
   466 			Mix_SetError("%s", Timidity_Error());
   467 			music->error = 1;
   468 		}
   469 #endif
   470 	} else
   471 #endif
   472 #ifdef OGG_MUSIC
   473 	/* Ogg Vorbis files have the magic four bytes "OggS" */
   474 	if ( (ext && MIX_string_equals(ext, "OGG")) ||
   475 	     strcmp((char *)magic, "OggS") == 0 ) {
   476 		music->type = MUS_OGG;
   477 		music->data.ogg = OGG_new(file);
   478 		if ( music->data.ogg == NULL ) {
   479 			music->error = 1;
   480 		}
   481 	} else
   482 #endif
   483 #ifdef FLAC_MUSIC
   484 	/* FLAC files have the magic four bytes "fLaC" */
   485 	if ( (ext && MIX_string_equals(ext, "FLAC")) ||
   486 		 strcmp((char *)magic, "fLaC") == 0 ) {
   487 		music->type = MUS_FLAC;
   488 		music->data.flac = FLAC_new(file);
   489 		if ( music->data.flac == NULL ) {
   490 			music->error = 1;
   491 		}
   492 	} else
   493 #endif
   494 #ifdef MP3_MUSIC
   495 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   496 	     (ext && MIX_string_equals(ext, "MP3")) ||
   497 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   498 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   499 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   500 		if ( Mix_Init(MIX_INIT_MP3) ) {
   501 			SMPEG_Info info;
   502 			music->type = MUS_MP3;
   503 			music->data.mp3 = smpeg.SMPEG_new(file, &info, 0);
   504 			if ( !info.has_audio ) {
   505 				Mix_SetError("MPEG file does not have any audio stream.");
   506 				music->error = 1;
   507 			} else {
   508 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   509 			}
   510 		} else {
   511 			music->error = 1;
   512 		}
   513 	} else
   514 #endif
   515 #ifdef MP3_MAD_MUSIC
   516 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   517 	     (ext && MIX_string_equals(ext, "MP3")) ||
   518 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   519 	     (ext && MIX_string_equals(ext, "MAD")) ||
   520 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   521 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   522 		music->type = MUS_MP3_MAD;
   523 		music->data.mp3_mad = mad_openFile(file, &used_mixer);
   524 		if (music->data.mp3_mad == 0) {
   525 		    Mix_SetError("Could not initialize MPEG stream.");
   526 			music->error = 1;
   527 		}
   528 	} else
   529 #endif
   530 #ifdef MOD_MUSIC
   531 	if ( 1 ) {
   532 		music->type = MUS_MOD;
   533 		music->data.module = MOD_new(file);
   534 		if ( music->data.module == NULL ) {
   535 			music->error = 1;
   536 		}
   537 	} else
   538 #endif
   539 	{
   540 		Mix_SetError("Unrecognized music format");
   541 		music->error = 1;
   542 	}
   543 	if ( music->error ) {
   544 		free(music);
   545 		music = NULL;
   546 	}
   547 	return(music);
   548 }
   549 
   550 /* Free a music chunk previously loaded */
   551 void Mix_FreeMusic(Mix_Music *music)
   552 {
   553 	if ( music ) {
   554 		/* Stop the music if it's currently playing */
   555 		SDL_LockAudio();
   556 		if ( music == music_playing ) {
   557 			/* Wait for any fade out to finish */
   558 			while ( music->fading == MIX_FADING_OUT ) {
   559 				SDL_UnlockAudio();
   560 				SDL_Delay(100);
   561 				SDL_LockAudio();
   562 			}
   563 			if ( music == music_playing ) {
   564 				music_internal_halt();
   565 			}
   566 		}
   567 		SDL_UnlockAudio();
   568 		switch (music->type) {
   569 #ifdef CMD_MUSIC
   570 			case MUS_CMD:
   571 				MusicCMD_FreeSong(music->data.cmd);
   572 				break;
   573 #endif
   574 #ifdef WAV_MUSIC
   575 			case MUS_WAV:
   576 				WAVStream_FreeSong(music->data.wave);
   577 				break;
   578 #endif
   579 #ifdef MOD_MUSIC
   580 			case MUS_MOD:
   581 				MOD_delete(music->data.module);
   582 				break;
   583 #endif
   584 #ifdef MID_MUSIC
   585 			case MUS_MID:
   586 #ifdef USE_NATIVE_MIDI
   587   				if ( native_midi_ok ) {
   588 					native_midi_freesong(music->data.nativemidi);
   589 				} MIDI_ELSE
   590 #endif
   591 #ifdef USE_TIMIDITY_MIDI
   592 				if ( timidity_ok ) {
   593 					Timidity_FreeSong(music->data.midi);
   594 				}
   595 #endif
   596 				break;
   597 #endif
   598 #ifdef OGG_MUSIC
   599 			case MUS_OGG:
   600 				OGG_delete(music->data.ogg);
   601 				break;
   602 #endif
   603 #ifdef FLAC_MUSIC
   604 			case MUS_FLAC:
   605 				FLAC_delete(music->data.flac);
   606 				break;
   607 #endif
   608 #ifdef MP3_MUSIC
   609 			case MUS_MP3:
   610 				smpeg.SMPEG_delete(music->data.mp3);
   611 				break;
   612 #endif
   613 #ifdef MP3_MAD_MUSIC
   614 			case MUS_MP3_MAD:
   615 				mad_closeFile(music->data.mp3_mad);
   616 				break;
   617 #endif
   618 			default:
   619 				/* Unknown music type?? */
   620 				break;
   621 		}
   622 		free(music);
   623 	}
   624 }
   625 
   626 /* Find out the music format of a mixer music, or the currently playing
   627    music, if 'music' is NULL.
   628 */
   629 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   630 {
   631 	Mix_MusicType type = MUS_NONE;
   632 
   633 	if ( music ) {
   634 		type = music->type;
   635 	} else {
   636 		SDL_LockAudio();
   637 		if ( music_playing ) {
   638 			type = music_playing->type;
   639 		}
   640 		SDL_UnlockAudio();
   641 	}
   642 	return(type);
   643 }
   644 
   645 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   646  */
   647 static int music_internal_play(Mix_Music *music, double position)
   648 {
   649 	int retval = 0;
   650 
   651 	/* Note the music we're playing */
   652 	if ( music_playing ) {
   653 		music_internal_halt();
   654 	}
   655 	music_playing = music;
   656 
   657 	/* Set the initial volume */
   658 	if ( music->type != MUS_MOD ) {
   659 		music_internal_initialize_volume();
   660 	}
   661 
   662 	/* Set up for playback */
   663 	switch (music->type) {
   664 #ifdef CMD_MUSIC
   665 	    case MUS_CMD:
   666 		MusicCMD_Start(music->data.cmd);
   667 		break;
   668 #endif
   669 #ifdef WAV_MUSIC
   670 	    case MUS_WAV:
   671 		WAVStream_Start(music->data.wave);
   672 		break;
   673 #endif
   674 #ifdef MOD_MUSIC
   675 	    case MUS_MOD:
   676 		MOD_play(music->data.module);
   677 		/* Player_SetVolume() does nothing before Player_Start() */
   678 		music_internal_initialize_volume();
   679 		break;
   680 #endif
   681 #ifdef MID_MUSIC
   682 	    case MUS_MID:
   683 #ifdef USE_NATIVE_MIDI
   684 		if ( native_midi_ok ) {
   685 			native_midi_start(music->data.nativemidi);
   686 		} MIDI_ELSE
   687 #endif
   688 #ifdef USE_TIMIDITY_MIDI
   689 		if ( timidity_ok ) {
   690 			Timidity_Start(music->data.midi);
   691 		}
   692 #endif
   693 		break;
   694 #endif
   695 #ifdef OGG_MUSIC
   696 	    case MUS_OGG:
   697 		OGG_play(music->data.ogg);
   698 		break;
   699 #endif
   700 #ifdef FLAC_MUSIC
   701 	    case MUS_FLAC:
   702 		FLAC_play(music->data.flac);
   703 		break;
   704 #endif
   705 #ifdef MP3_MUSIC
   706 	    case MUS_MP3:
   707 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
   708 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
   709 		smpeg.SMPEG_play(music_playing->data.mp3);
   710 		break;
   711 #endif
   712 #ifdef MP3_MAD_MUSIC
   713 	    case MUS_MP3_MAD:
   714 		mad_start(music->data.mp3_mad);
   715 		break;
   716 #endif
   717 	    default:
   718 		Mix_SetError("Can't play unknown music type");
   719 		retval = -1;
   720 		break;
   721 	}
   722 
   723 	/* Set the playback position, note any errors if an offset is used */
   724 	if ( retval == 0 ) {
   725 		if ( position > 0.0 ) {
   726 			if ( music_internal_position(position) < 0 ) {
   727 				Mix_SetError("Position not implemented for music type");
   728 				retval = -1;
   729 			}
   730 		} else {
   731 			music_internal_position(0.0);
   732 		}
   733 	}
   734 
   735 	/* If the setup failed, we're not playing any music anymore */
   736 	if ( retval < 0 ) {
   737 		music_playing = NULL;
   738 	}
   739 	return(retval);
   740 }
   741 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   742 {
   743 	int retval;
   744 
   745 	/* Don't play null pointers :-) */
   746 	if ( music == NULL ) {
   747 		Mix_SetError("music parameter was NULL");
   748 		return(-1);
   749 	}
   750 
   751 	/* Setup the data */
   752 	if ( ms ) {
   753 		music->fading = MIX_FADING_IN;
   754 	} else {
   755 		music->fading = MIX_NO_FADING;
   756 	}
   757 	music->fade_step = 0;
   758 	music->fade_steps = ms/ms_per_step;
   759 
   760 	/* Play the puppy */
   761 	SDL_LockAudio();
   762 	/* If the current music is fading out, wait for the fade to complete */
   763 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
   764 		SDL_UnlockAudio();
   765 		SDL_Delay(100);
   766 		SDL_LockAudio();
   767 	}
   768 	music_active = 1;
   769 	music_loops = loops;
   770 	retval = music_internal_play(music, position);
   771 	SDL_UnlockAudio();
   772 
   773 	return(retval);
   774 }
   775 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   776 {
   777 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   778 }
   779 int Mix_PlayMusic(Mix_Music *music, int loops)
   780 {
   781 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   782 }
   783 
   784 /* Set the playing music position */
   785 int music_internal_position(double position)
   786 {
   787 	int retval = 0;
   788 
   789 	switch (music_playing->type) {
   790 #ifdef MOD_MUSIC
   791 	    case MUS_MOD:
   792 		MOD_jump_to_time(music_playing->data.module, position);
   793 		break;
   794 #endif
   795 #ifdef OGG_MUSIC
   796 	    case MUS_OGG:
   797 		OGG_jump_to_time(music_playing->data.ogg, position);
   798 		break;
   799 #endif
   800 #ifdef FLAC_MUSIC
   801 	    case MUS_FLAC:
   802 		FLAC_jump_to_time(music_playing->data.flac, position);
   803 		break;
   804 #endif
   805 #ifdef MP3_MUSIC
   806 	    case MUS_MP3:
   807 		if ( position > 0.0 ) {
   808 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
   809 		} else {
   810 			smpeg.SMPEG_rewind(music_playing->data.mp3);
   811 			smpeg.SMPEG_play(music_playing->data.mp3);
   812 		}
   813 		break;
   814 #endif
   815 #ifdef MP3_MAD_MUSIC
   816 	    case MUS_MP3_MAD:
   817 		mad_seek(music_playing->data.mp3_mad, position);
   818 		break;
   819 #endif
   820 	    default:
   821 		/* TODO: Implement this for other music backends */
   822 		retval = -1;
   823 		break;
   824 	}
   825 	return(retval);
   826 }
   827 int Mix_SetMusicPosition(double position)
   828 {
   829 	int retval;
   830 
   831 	SDL_LockAudio();
   832 	if ( music_playing ) {
   833 		retval = music_internal_position(position);
   834 		if ( retval < 0 ) {
   835 			Mix_SetError("Position not implemented for music type");
   836 		}
   837 	} else {
   838 		Mix_SetError("Music isn't playing");
   839 		retval = -1;
   840 	}
   841 	SDL_UnlockAudio();
   842 
   843 	return(retval);
   844 }
   845 
   846 /* Set the music's initial volume */
   847 static void music_internal_initialize_volume(void)
   848 {
   849 	if ( music_playing->fading == MIX_FADING_IN ) {
   850 		music_internal_volume(0);
   851 	} else {
   852 		music_internal_volume(music_volume);
   853 	}
   854 }
   855 
   856 /* Set the music volume */
   857 static void music_internal_volume(int volume)
   858 {
   859 	switch (music_playing->type) {
   860 #ifdef CMD_MUSIC
   861 	    case MUS_CMD:
   862 		MusicCMD_SetVolume(volume);
   863 		break;
   864 #endif
   865 #ifdef WAV_MUSIC
   866 	    case MUS_WAV:
   867 		WAVStream_SetVolume(volume);
   868 		break;
   869 #endif
   870 #ifdef MOD_MUSIC
   871 	    case MUS_MOD:
   872 		MOD_setvolume(music_playing->data.module, volume);
   873 		break;
   874 #endif
   875 #ifdef MID_MUSIC
   876 	    case MUS_MID:
   877 #ifdef USE_NATIVE_MIDI
   878 		if ( native_midi_ok ) {
   879 			native_midi_setvolume(volume);
   880 		} MIDI_ELSE
   881 #endif
   882 #ifdef USE_TIMIDITY_MIDI
   883 		if ( timidity_ok ) {
   884 			Timidity_SetVolume(volume);
   885 		}
   886 #endif
   887 		break;
   888 #endif
   889 #ifdef OGG_MUSIC
   890 	    case MUS_OGG:
   891 		OGG_setvolume(music_playing->data.ogg, volume);
   892 		break;
   893 #endif
   894 #ifdef FLAC_MUSIC
   895 	    case MUS_FLAC:
   896 		FLAC_setvolume(music_playing->data.flac, volume);
   897 		break;
   898 #endif
   899 #ifdef MP3_MUSIC
   900 	    case MUS_MP3:
   901 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
   902 		break;
   903 #endif
   904 #ifdef MP3_MAD_MUSIC
   905 	    case MUS_MP3_MAD:
   906 		mad_setVolume(music_playing->data.mp3_mad, volume);
   907 		break;
   908 #endif
   909 	    default:
   910 		/* Unknown music type?? */
   911 		break;
   912 	}
   913 }
   914 int Mix_VolumeMusic(int volume)
   915 {
   916 	int prev_volume;
   917 
   918 	prev_volume = music_volume;
   919 	if ( volume < 0 ) {
   920 		return prev_volume;
   921 	}
   922 	if ( volume > SDL_MIX_MAXVOLUME ) {
   923 		volume = SDL_MIX_MAXVOLUME;
   924 	}
   925 	music_volume = volume;
   926 	SDL_LockAudio();
   927 	if ( music_playing ) {
   928 		music_internal_volume(music_volume);
   929 	}
   930 	SDL_UnlockAudio();
   931 	return(prev_volume);
   932 }
   933 
   934 /* Halt playing of music */
   935 static void music_internal_halt(void)
   936 {
   937 	switch (music_playing->type) {
   938 #ifdef CMD_MUSIC
   939 	    case MUS_CMD:
   940 		MusicCMD_Stop(music_playing->data.cmd);
   941 		break;
   942 #endif
   943 #ifdef WAV_MUSIC
   944 	    case MUS_WAV:
   945 		WAVStream_Stop();
   946 		break;
   947 #endif
   948 #ifdef MOD_MUSIC
   949 	    case MUS_MOD:
   950 		MOD_stop(music_playing->data.module);
   951 		break;
   952 #endif
   953 #ifdef MID_MUSIC
   954 	    case MUS_MID:
   955 #ifdef USE_NATIVE_MIDI
   956 		if ( native_midi_ok ) {
   957 			native_midi_stop();
   958 		} MIDI_ELSE
   959 #endif
   960 #ifdef USE_TIMIDITY_MIDI
   961 		if ( timidity_ok ) {
   962 			Timidity_Stop();
   963 		}
   964 #endif
   965 		break;
   966 #endif
   967 #ifdef OGG_MUSIC
   968 	    case MUS_OGG:
   969 		OGG_stop(music_playing->data.ogg);
   970 		break;
   971 #endif
   972 #ifdef FLAC_MUSIC
   973 	    case MUS_FLAC:
   974 		FLAC_stop(music_playing->data.flac);
   975 		break;
   976 #endif
   977 #ifdef MP3_MUSIC
   978 	    case MUS_MP3:
   979 		smpeg.SMPEG_stop(music_playing->data.mp3);
   980 		break;
   981 #endif
   982 #ifdef MP3_MAD_MUSIC
   983 	    case MUS_MP3_MAD:
   984 		mad_stop(music_playing->data.mp3_mad);
   985 		break;
   986 #endif
   987 	    default:
   988 		/* Unknown music type?? */
   989 		return;
   990 	}
   991 	music_playing->fading = MIX_NO_FADING;
   992 	music_playing = NULL;
   993 }
   994 int Mix_HaltMusic(void)
   995 {
   996 	SDL_LockAudio();
   997 	if ( music_playing ) {
   998 		music_internal_halt();
   999 	}
  1000 	SDL_UnlockAudio();
  1001 
  1002 	return(0);
  1003 }
  1004 
  1005 /* Progressively stop the music */
  1006 int Mix_FadeOutMusic(int ms)
  1007 {
  1008 	int retval = 0;
  1009 
  1010 	if (ms <= 0) {  /* just halt immediately. */
  1011 		Mix_HaltMusic();
  1012 		return 1;
  1013 	}
  1014 
  1015 	SDL_LockAudio();
  1016 	if ( music_playing) {
  1017                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1018                 if ( music_playing->fading == MIX_NO_FADING ) {
  1019 	        	music_playing->fade_step = 0;
  1020                 } else {
  1021                         int step;
  1022                         int old_fade_steps = music_playing->fade_steps;
  1023                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1024                                 step = music_playing->fade_step;
  1025                         } else {
  1026                                 step = old_fade_steps
  1027                                         - music_playing->fade_step + 1;
  1028                         }
  1029                         music_playing->fade_step = (step * fade_steps)
  1030                                 / old_fade_steps;
  1031                 }
  1032 		music_playing->fading = MIX_FADING_OUT;
  1033 		music_playing->fade_steps = fade_steps;
  1034 		retval = 1;
  1035 	}
  1036 	SDL_UnlockAudio();
  1037 
  1038 	return(retval);
  1039 }
  1040 
  1041 Mix_Fading Mix_FadingMusic(void)
  1042 {
  1043 	Mix_Fading fading = MIX_NO_FADING;
  1044 
  1045 	SDL_LockAudio();
  1046 	if ( music_playing ) {
  1047 		fading = music_playing->fading;
  1048 	}
  1049 	SDL_UnlockAudio();
  1050 
  1051 	return(fading);
  1052 }
  1053 
  1054 /* Pause/Resume the music stream */
  1055 void Mix_PauseMusic(void)
  1056 {
  1057 	music_active = 0;
  1058 }
  1059 
  1060 void Mix_ResumeMusic(void)
  1061 {
  1062 	music_active = 1;
  1063 }
  1064 
  1065 void Mix_RewindMusic(void)
  1066 {
  1067 	Mix_SetMusicPosition(0.0);
  1068 }
  1069 
  1070 int Mix_PausedMusic(void)
  1071 {
  1072 	return (music_active == 0);
  1073 }
  1074 
  1075 /* Check the status of the music */
  1076 static int music_internal_playing()
  1077 {
  1078 	int playing = 1;
  1079 	switch (music_playing->type) {
  1080 #ifdef CMD_MUSIC
  1081 	    case MUS_CMD:
  1082 		if (!MusicCMD_Active(music_playing->data.cmd)) {
  1083 			playing = 0;
  1084 		}
  1085 		break;
  1086 #endif
  1087 #ifdef WAV_MUSIC
  1088 	    case MUS_WAV:
  1089 		if ( ! WAVStream_Active() ) {
  1090 			playing = 0;
  1091 		}
  1092 		break;
  1093 #endif
  1094 #ifdef MOD_MUSIC
  1095 	    case MUS_MOD:
  1096 		if ( ! MOD_playing(music_playing->data.module) ) {
  1097 			playing = 0;
  1098 		}
  1099 		break;
  1100 #endif
  1101 #ifdef MID_MUSIC
  1102 	    case MUS_MID:
  1103 #ifdef USE_NATIVE_MIDI
  1104 		if ( native_midi_ok ) {
  1105 			if ( ! native_midi_active() )
  1106 				playing = 0;
  1107 		} MIDI_ELSE
  1108 #endif
  1109 #ifdef USE_TIMIDITY_MIDI
  1110 		if ( timidity_ok ) {
  1111 			if ( ! Timidity_Active() )
  1112 				playing = 0;
  1113 		}
  1114 #endif
  1115 		break;
  1116 #endif
  1117 #ifdef OGG_MUSIC
  1118 	    case MUS_OGG:
  1119 		if ( ! OGG_playing(music_playing->data.ogg) ) {
  1120 			playing = 0;
  1121 		}
  1122 		break;
  1123 #endif
  1124 #ifdef FLAC_MUSIC
  1125 	    case MUS_FLAC:
  1126 		if ( ! FLAC_playing(music_playing->data.flac) ) {
  1127 			playing = 0;
  1128 		}
  1129 		break;
  1130 #endif
  1131 #ifdef MP3_MUSIC
  1132 	    case MUS_MP3:
  1133 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1134 			playing = 0;
  1135 		break;
  1136 #endif
  1137 #ifdef MP3_MAD_MUSIC
  1138 	    case MUS_MP3_MAD:
  1139 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1140 			playing = 0;
  1141 		}
  1142 		break;
  1143 #endif
  1144 	    default:
  1145 		playing = 0;
  1146 		break;
  1147 	}
  1148 	return(playing);
  1149 }
  1150 int Mix_PlayingMusic(void)
  1151 {
  1152 	int playing = 0;
  1153 
  1154 	SDL_LockAudio();
  1155 	if ( music_playing ) {
  1156 		playing = music_internal_playing();
  1157 	}
  1158 	SDL_UnlockAudio();
  1159 
  1160 	return(playing);
  1161 }
  1162 
  1163 /* Set the external music playback command */
  1164 int Mix_SetMusicCMD(const char *command)
  1165 {
  1166 	Mix_HaltMusic();
  1167 	if ( music_cmd ) {
  1168 		free(music_cmd);
  1169 		music_cmd = NULL;
  1170 	}
  1171 	if ( command ) {
  1172 		music_cmd = (char *)malloc(strlen(command)+1);
  1173 		if ( music_cmd == NULL ) {
  1174 			return(-1);
  1175 		}
  1176 		strcpy(music_cmd, command);
  1177 	}
  1178 	return(0);
  1179 }
  1180 
  1181 int Mix_SetSynchroValue(int i)
  1182 {
  1183 	/* Not supported by any players at this time */
  1184 	return(-1);
  1185 }
  1186 
  1187 int Mix_GetSynchroValue(void)
  1188 {
  1189 	/* Not supported by any players at this time */
  1190 	return(-1);
  1191 }
  1192 
  1193 
  1194 /* Uninitialize the music players */
  1195 void close_music(void)
  1196 {
  1197 	Mix_HaltMusic();
  1198 #ifdef CMD_MUSIC
  1199 	Mix_SetMusicCMD(NULL);
  1200 #endif
  1201 #ifdef MOD_MUSIC
  1202 	MOD_exit();
  1203 #endif
  1204 #ifdef MID_MUSIC
  1205 # ifdef USE_TIMIDITY_MIDI
  1206 	Timidity_Close();
  1207 # endif
  1208 #endif
  1209 
  1210 	/* rcg06042009 report available decoders at runtime. */
  1211 	free(music_decoders);
  1212 	music_decoders = NULL;
  1213 	num_decoders = 0;
  1214 }
  1215 
  1216 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
  1217 {
  1218 	Uint8 magic[5];	  /*Apparently there is no way to check if the file is really a MOD,*/
  1219 	/*		    or there are too many formats supported by MikMod or MikMod does */
  1220 	/*		    this check by itself. If someone implements other formats (e.g. MP3) */
  1221 	/*		    the check can be uncommented */
  1222 	Uint8 moremagic[9];
  1223 	Mix_Music *music;
  1224 	int start;
  1225 
  1226 	if (!rw) {
  1227 		Mix_SetError("RWops pointer is NULL");
  1228 		return NULL;
  1229 	}
  1230 
  1231 	/* Figure out what kind of file this is */
  1232 	start = SDL_RWtell(rw);
  1233 	if ( SDL_RWread(rw,magic,1,4) != 4 ||
  1234 	     SDL_RWread(rw,moremagic,1,8) != 8 ) {
  1235 		Mix_SetError("Couldn't read from RWops");
  1236 		return NULL;
  1237 	}
  1238 	SDL_RWseek(rw, start, RW_SEEK_SET);
  1239 	magic[4]='\0';
  1240 	moremagic[8] = '\0';
  1241 
  1242 	/* Allocate memory for the music structure */
  1243 	music=(Mix_Music *)malloc(sizeof(Mix_Music));
  1244 	if (music==NULL ) {
  1245 		Mix_SetError("Out of memory");
  1246 		return(NULL);
  1247 	}
  1248 	music->error = 0;
  1249 
  1250 #ifdef WAV_MUSIC
  1251 	/* WAVE files have the magic four bytes "RIFF"
  1252 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
  1253 	 */
  1254 	if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
  1255 	     (strcmp((char *)magic, "FORM") == 0) ) {
  1256 		music->type = MUS_WAV;
  1257 		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
  1258 		if ( music->data.wave == NULL ) {
  1259 			music->error = 1;
  1260 		}
  1261 
  1262 	} else
  1263 #endif
  1264 #ifdef OGG_MUSIC
  1265 	/* Ogg Vorbis files have the magic four bytes "OggS" */
  1266 	if ( strcmp((char *)magic, "OggS") == 0 ) {
  1267 		music->type = MUS_OGG;
  1268 		music->data.ogg = OGG_new_RW(rw);
  1269 		if ( music->data.ogg == NULL ) {
  1270 			music->error = 1;
  1271 		}
  1272 	} else
  1273 #endif
  1274 #ifdef FLAC_MUSIC
  1275 	/* FLAC files have the magic four bytes "fLaC" */
  1276 	if ( strcmp((char *)magic, "fLaC") == 0 ) {
  1277 		music->type = MUS_FLAC;
  1278 		music->data.flac = FLAC_new_RW(rw);
  1279 		if ( music->data.flac == NULL ) {
  1280 			music->error = 1;
  1281 		}
  1282 	} else
  1283 #endif
  1284 #ifdef MP3_MUSIC
  1285 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1286 		if ( Mix_Init(MIX_INIT_MP3) ) {
  1287 			SMPEG_Info info;
  1288 			music->type = MUS_MP3;
  1289 			music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
  1290 			if ( !info.has_audio ) {
  1291 				Mix_SetError("MPEG file does not have any audio stream.");
  1292 				music->error = 1;
  1293 			} else {
  1294 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
  1295 			}
  1296 		} else {
  1297 			music->error = 1;
  1298 		}
  1299 	} else
  1300 #endif
  1301 #ifdef MP3_MAD_MUSIC
  1302 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1303 		music->type = MUS_MP3_MAD;
  1304 		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
  1305 		if (music->data.mp3_mad == 0) {
  1306 			Mix_SetError("Could not initialize MPEG stream.");
  1307 			music->error = 1;
  1308 		}
  1309 	} else
  1310 #endif
  1311 #ifdef MID_MUSIC
  1312 	/* MIDI files have the magic four bytes "MThd" */
  1313 	if ( strcmp((char *)magic, "MThd") == 0 ) {
  1314 		music->type = MUS_MID;
  1315 #ifdef USE_NATIVE_MIDI
  1316 		if ( native_midi_ok ) {
  1317 			music->data.nativemidi = native_midi_loadsong_RW(rw);
  1318 	  		if ( music->data.nativemidi == NULL ) {
  1319 		  		Mix_SetError("%s", native_midi_error());
  1320 			  	music->error = 1;
  1321 			}
  1322 		} MIDI_ELSE
  1323 #endif
  1324 #ifdef USE_TIMIDITY_MIDI
  1325 		if ( timidity_ok ) {
  1326 			music->data.midi = Timidity_LoadSong_RW(rw);
  1327 			if ( music->data.midi == NULL ) {
  1328 				Mix_SetError("%s", Timidity_Error());
  1329 				music->error = 1;
  1330 			}
  1331 		} else {
  1332 			Mix_SetError("%s", Timidity_Error());
  1333 			music->error = 1;
  1334 		}
  1335 #endif
  1336 	} else
  1337 #endif
  1338 #ifdef MOD_MUSIC
  1339 	if (1) {
  1340 		music->type=MUS_MOD;
  1341 		music->data.module = MOD_new_RW(rw);
  1342 		if ( music->data.module == NULL ) {
  1343 			music->error = 1;
  1344 		}
  1345 	} else
  1346 #endif
  1347 	{
  1348 		Mix_SetError("Unrecognized music format");
  1349 		music->error=1;
  1350 	}
  1351 	if (music->error) {
  1352 		free(music);
  1353 		music=NULL;
  1354 	}
  1355 	return(music);
  1356 }