music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 29 Jan 2006 06:47:14 +0000
changeset 285 9274a084491d
parent 281 33730d0864d8
child 310 77e72cff08e7
permissions -rw-r--r--
Date: Fri, 24 Dec 2004 16:11:30 +0100
From: Gaetan de Menten
Subject: Re: [SDL] SDL_mixer and implicit looping of module music files

Maybe it will be clearer with this information copy-pasted from
Mikmod's documentation:

BOOL wrap
If nonzero, module wraps to its restart position when it is
finished, to play continuously. Default value is zero (play only
once).

BOOL loop
If nonzero, all in-module loops are processed; otherwise, backward
loops which decrease the current position are not processed (i.e. only
forward loops, and backward loops in the same pattern, are processed).
This ensures that the module never loops endlessly. The default value
is 1 (all loops are processed).

and this is from SDL_mixer's code:

music->data.module->wrap = 0;
music->data.module->loop = 0;

What I don't like is the loop = 0 (note it is not the default value in
mikmod) and that there is no way to change it, the wrap = 0 is fine
with me.

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