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

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

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

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

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

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

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