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