music.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Feb 2008 07:31:03 +0000
changeset 382 50501e45c57b
parent 381 2064088ea781
child 386 695494546b3c
permissions -rw-r--r--
Austen Dicken - Tue Feb 26 23:28:27 PST 2008

Ok, here is the patch I made for FLAC support.

I have tested it relatively thoroughly and currently the patch allows:
1. Pre-loading FLAC files and playing them via LoadWAV
2. The patch allows for FLAC support in the LoadMUS setting as well as:
* Pause / Resume
* Volume control
* Seeking

I also did a little benchmarking by comparing memory/cpu usage of playmus to
that of mplayer, and the results were very good. playmus typically took about
half the RAM as mplayer, though that may be attributed to mplayer being a more
"bulky" program. As such I would say that the two are probably about equal in
efficiency.

Also, it is important to note that, similar to the OGG support currently
built-in, my FLAC patch only supports 16 bit stereo-encoded sound. Also, it
is only for Native FLAC (standard) and not the derivative, Ogg-FLAC.

I have tried to find a simple way to detect Ogg-FLAC files, as the only
difference between Ogg-FLAC and Native FLAC support is changing the init_
function call, but after digging a little deeper it seems that Ogg-FLAC is
basically FLAC wrapped in an Ogg transport layer, so it would be better to have
a way to read the Ogg transport layer which then reads the inner audio files
according to the proper codec.

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