music.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 15 Jun 2011 03:41:31 -0400
changeset 509 777497efacaa
parent 508 de8e7a4f5936
child 510 3a4c352a9a00
permissions -rw-r--r--
Let the music-finished hook start a new track without a skip in the audio.

Previously, there'd be no more music mixed until the next SDL audio callback
fired. Now if the hook (re)starts a track, it'll start mixing right away,
into whatever space is left in the callback where the hook was called.

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