/
music.c
1402 lines (1312 loc) · 29.6 KB
1
/*
2
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2004 Sam Lantinga
4
5
6
7
8
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
9
10
11
12
13
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19
20
Sam Lantinga
slouken@libsdl.org
21
22
*/
23
/* $Id$ */
24
25
26
#include <stdlib.h>
#include <string.h>
27
#include <ctype.h>
28
29
#include "SDL_endian.h"
#include "SDL_audio.h"
30
#include "SDL_timer.h"
31
32
#include "SDL_mixer.h"
33
34
35
36
37
38
39
40
41
#define SDL_SURROUND
#ifdef SDL_SURROUND
#define MAX_OUTPUT_CHANNELS 6
#else
#define MAX_OUTPUT_CHANNELS 2
#endif
42
43
44
45
46
47
48
49
50
51
52
/* The music command hack is UNIX specific */
#ifndef unix
#undef CMD_MUSIC
#endif
#ifdef CMD_MUSIC
#include "music_cmd.h"
#endif
#ifdef WAV_MUSIC
#include "wavestream.h"
#endif
53
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
54
55
56
57
58
# include "mikmod.h"
# if defined(LIBMIKMOD_VERSION) /* libmikmod 3.1.8 */
# define UNIMOD MODULE
# define MikMod_Init() MikMod_Init(NULL)
# define MikMod_LoadSong(a,b) Player_Load(a,b,0)
59
60
# ifndef LIBMIKMOD_MUSIC
# define MikMod_LoadSongRW(a,b) Player_LoadRW(a,b,0)
61
# endif
62
63
64
65
66
67
# define MikMod_FreeSong Player_Free
extern int MikMod_errno;
# else /* old MikMod 3.0.3 */
# define MikMod_strerror(x) _mm_errmsg[x])
# define MikMod_errno _mm_errno
# endif
68
69
#endif
#ifdef MID_MUSIC
70
71
72
73
74
75
76
77
78
79
80
# ifdef USE_TIMIDITY_MIDI
# include "timidity.h"
# endif
# ifdef USE_NATIVE_MIDI
# include "native_midi.h"
# endif
# if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
# define MIDI_ELSE else
# else
# define MIDI_ELSE
# endif
81
#endif
82
83
84
#ifdef OGG_MUSIC
#include "music_ogg.h"
#endif
85
#ifdef MP3_MUSIC
86
#include "smpeg.h"
87
88
89
90
static SDL_AudioSpec used_mixer;
#endif
91
92
int volatile music_active = 1;
static int volatile music_stopped = 0;
93
94
static int music_loops = 0;
static char *music_cmd = NULL;
95
static Mix_Music * volatile music_playing = NULL;
96
static int music_volume = MIX_MAX_VOLUME;
97
98
static int music_swap8;
static int music_swap16;
99
100
struct _Mix_Music {
101
Mix_MusicType type;
102
103
104
105
106
107
108
union {
#ifdef CMD_MUSIC
MusicCMD *cmd;
#endif
#ifdef WAV_MUSIC
WAVStream *wave;
#endif
109
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
110
111
112
UNIMOD *module;
#endif
#ifdef MID_MUSIC
113
#ifdef USE_TIMIDITY_MIDI
114
MidiSong *midi;
115
#endif
116
117
118
#ifdef USE_NATIVE_MIDI
NativeMidiSong *nativemidi;
#endif
119
#endif
120
121
122
#ifdef OGG_MUSIC
OGG_music *ogg;
#endif
123
124
125
126
#ifdef MP3_MUSIC
SMPEG *mp3;
#endif
} data;
127
Mix_Fading fading;
128
129
int fade_step;
int fade_steps;
130
131
int error;
};
132
#ifdef MID_MUSIC
133
#ifdef USE_TIMIDITY_MIDI
134
static int timidity_ok;
135
static int samplesize;
136
#endif
137
138
139
#ifdef USE_NATIVE_MIDI
static int native_midi_ok;
#endif
140
#endif
141
142
143
144
145
/* Reference for converting mikmod output to 4/6 channels */
static int current_output_channels;
static Uint16 current_output_format;
146
147
148
/* Used to calculate fading steps */
static int ms_per_step;
149
/* Local low-level functions prototypes */
150
static void music_internal_initialize_volume(void);
151
152
153
154
155
static void music_internal_volume(int volume);
static int music_internal_play(Mix_Music *music, double position);
static int music_internal_position(double position);
static int music_internal_playing();
static void music_internal_halt(void);
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Support for hooking when the music has finished */
static void (*music_finished_hook)(void) = NULL;
void Mix_HookMusicFinished(void (*music_finished)(void))
{
SDL_LockAudio();
music_finished_hook = music_finished;
SDL_UnlockAudio();
}
169
170
171
/* Mixing function */
void music_mixer(void *udata, Uint8 *stream, int len)
{
172
if ( music_playing && music_active ) {
173
/* Handle fading */
174
175
if ( music_playing->fading != MIX_NO_FADING ) {
if ( music_playing->fade_step++ < music_playing->fade_steps ) {
176
int volume;
177
178
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
179
180
if ( music_playing->fading == MIX_FADING_OUT ) {
181
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
182
} else { /* Fading in */
183
volume = (music_volume * fade_step) / fade_steps;
184
}
185
music_internal_volume(volume);
186
187
} else {
if ( music_playing->fading == MIX_FADING_OUT ) {
188
189
190
191
music_internal_halt();
if ( music_finished_hook ) {
music_finished_hook();
}
192
return;
193
}
194
music_playing->fading = MIX_NO_FADING;
195
196
}
}
197
/* Restart music if it has to loop */
198
199
if ( !music_internal_playing() ) {
/* Restart music if it has to loop at a high level */
200
if ( music_loops && --music_loops ) {
201
Mix_Fading current_fade = music_playing->fading;
202
music_internal_play(music_playing, 0.0);
203
music_playing->fading = current_fade;
204
205
206
207
} else {
music_internal_halt();
if ( music_finished_hook ) {
music_finished_hook();
208
}
209
return;
210
}
211
}
212
213
214
215
216
217
218
219
switch (music_playing->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
/* The playing is done externally */
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
220
WAVStream_PlaySome(stream, len);
221
222
break;
#endif
223
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
224
case MUS_MOD:
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
if (current_output_channels > 2) {
int small_len = 2 * len / current_output_channels;
int i;
Uint8 *src, *dst;
VC_WriteBytes((SBYTE *)stream, small_len);
/* and extend to len by copying channels */
src = stream + small_len;
dst = stream + len;
switch (current_output_format & 0xFF) {
case 8:
for ( i=small_len/2; i; --i ) {
src -= 2;
dst -= current_output_channels;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[0];
dst[3] = src[1];
if (current_output_channels == 6) {
dst[4] = src[0];
dst[5] = src[1];
}
}
break;
case 16:
for ( i=small_len/4; i; --i ) {
src -= 4;
dst -= 2 * current_output_channels;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[0];
dst[5] = src[1];
dst[6] = src[2];
dst[7] = src[3];
if (current_output_channels == 6) {
dst[8] = src[0];
dst[9] = src[1];
dst[10] = src[2];
dst[11] = src[3];
}
}
break;
}
}
else VC_WriteBytes((SBYTE *)stream, len);
276
277
if ( music_swap8 ) {
Uint8 *dst;
278
int i;
279
280
281
282
283
284
285
286
dst = stream;
for ( i=len; i; --i ) {
*dst++ ^= 0x80;
}
} else
if ( music_swap16 ) {
Uint8 *dst, tmp;
287
int i;
288
289
290
291
292
293
294
295
296
297
298
299
dst = stream;
for ( i=(len/2); i; --i ) {
tmp = dst[0];
dst[0] = dst[1];
dst[1] = tmp;
dst += 2;
}
}
break;
#endif
#ifdef MID_MUSIC
300
#ifdef USE_TIMIDITY_MIDI
301
case MUS_MID:
302
303
304
305
if ( timidity_ok ) {
int samples = len / samplesize;
Timidity_PlaySome(stream, samples);
}
306
307
break;
#endif
308
#endif
309
310
311
312
313
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_playAudio(music_playing->data.ogg, stream, len);
break;
#endif
314
#ifdef MP3_MUSIC
315
316
case MUS_MP3:
SMPEG_playAudio(music_playing->data.mp3, stream, len);
317
318
319
320
321
322
323
324
325
326
327
328
329
break;
#endif
default:
/* Unknown music type?? */
break;
}
}
}
/* Initialize the music players with a certain desired audio format */
int open_music(SDL_AudioSpec *mixer)
{
int music_error;
330
331
332
#ifdef LIBMIKMOD_MUSIC
CHAR *list;
#endif
333
334
335
336
337
338
339
music_error = 0;
#ifdef WAV_MUSIC
if ( WAVStream_Init(mixer) < 0 ) {
++music_error;
}
#endif
340
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/* Set the MikMod music format */
music_swap8 = 0;
music_swap16 = 0;
switch (mixer->format) {
case AUDIO_U8:
case AUDIO_S8: {
if ( mixer->format == AUDIO_S8 ) {
music_swap8 = 1;
}
md_mode = 0;
}
break;
case AUDIO_S16LSB:
case AUDIO_S16MSB: {
/* See if we need to correct MikMod mixing */
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
if ( mixer->format == AUDIO_S16MSB ) {
#else
if ( mixer->format == AUDIO_S16LSB ) {
#endif
music_swap16 = 1;
}
md_mode = DMODE_16BITS;
}
break;
default: {
370
Mix_SetError("Unknown hardware audio format");
371
372
373
++music_error;
}
}
374
375
current_output_channels = mixer->channels;
current_output_format = mixer->format;
376
if ( mixer->channels > 1 ) {
377
if ( mixer->channels > MAX_OUTPUT_CHANNELS ) {
378
Mix_SetError("Hardware uses more channels than mixer");
379
380
381
382
++music_error;
}
md_mode |= DMODE_STEREO;
}
383
384
385
md_mixfreq = mixer->freq;
md_device = 0;
md_volume = 96;
386
387
md_musicvolume = 128;
md_sndfxvolume = 128;
388
389
md_pansep = 128;
md_reverb = 0;
390
391
392
393
#ifdef LIBMIKMOD_MUSIC
md_mode |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;
#endif
#ifdef LIBMIKMOD_MUSIC
394
395
396
397
list = MikMod_InfoDriver();
if ( list )
free(list);
else
398
#endif
399
MikMod_RegisterDriver(&drv_nos);
400
#ifdef LIBMIKMOD_MUSIC
401
402
403
404
list = MikMod_InfoLoader();
if ( list )
free(list);
else
405
406
#endif
MikMod_RegisterAllLoaders();
407
if ( MikMod_Init() ) {
408
Mix_SetError("%s", MikMod_strerror(MikMod_errno));
409
410
411
412
++music_error;
}
#endif
#ifdef MID_MUSIC
413
#ifdef USE_TIMIDITY_MIDI
414
samplesize = mixer->size / mixer->samples;
415
if ( Timidity_Init(mixer->freq, mixer->format,
416
mixer->channels, mixer->samples) == 0 ) {
417
timidity_ok = 1;
418
419
420
} else {
timidity_ok = 0;
}
421
#endif
422
#ifdef USE_NATIVE_MIDI
423
#ifdef USE_TIMIDITY_MIDI
424
native_midi_ok = !timidity_ok;
425
426
if ( native_midi_ok )
#endif
427
native_midi_ok = native_midi_detect();
428
#endif
429
#endif
430
431
432
433
434
#ifdef OGG_MUSIC
if ( OGG_init(mixer) < 0 ) {
++music_error;
}
#endif
435
436
437
438
#ifdef MP3_MUSIC
/* Keep a copy of the mixer */
used_mixer = *mixer;
#endif
439
music_playing = NULL;
440
music_stopped = 0;
441
442
443
444
445
if ( music_error ) {
return(-1);
}
Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
446
/* Calculate the number of ms for each callback */
447
ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
448
449
450
451
return(0);
}
452
453
454
455
456
457
458
459
460
461
462
463
464
/* Portable case-insensitive string compare function */
int MIX_string_equals(const char *str1, const char *str2)
{
while ( *str1 && *str2 ) {
if ( toupper((unsigned char)*str1) !=
toupper((unsigned char)*str2) )
break;
++str1;
++str2;
}
return (!*str1 && !*str2);
}
465
466
467
468
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
FILE *fp;
469
char *ext;
470
Uint8 magic[5], moremagic[9];
471
472
473
474
475
476
477
478
Mix_Music *music;
/* Figure out what kind of file this is */
fp = fopen(file, "rb");
if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
if ( fp != NULL ) {
fclose(fp);
}
479
Mix_SetError("Couldn't read from '%s'", file);
480
481
return(NULL);
}
482
483
484
485
if (!fread(moremagic, 8, 1, fp)) {
Mix_SetError("Couldn't read from '%s'", file);
return(NULL);
}
486
magic[4] = '\0';
487
moremagic[8] = '\0';
488
489
fclose(fp);
490
491
492
493
/* Figure out the file extension, so we can determine the type */
ext = strrchr(file, '.');
if ( ext ) ++ext; /* skip the dot in the extension */
494
495
496
/* Allocate memory for the music structure */
music = (Mix_Music *)malloc(sizeof(Mix_Music));
if ( music == NULL ) {
497
Mix_SetError("Out of memory");
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
return(NULL);
}
music->error = 0;
#ifdef CMD_MUSIC
if ( music_cmd ) {
music->type = MUS_CMD;
music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
if ( music->data.cmd == NULL ) {
music->error = 1;
}
} else
#endif
#ifdef WAV_MUSIC
/* WAVE files have the magic four bytes "RIFF"
AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
*/
515
if ( (ext && MIX_string_equals(ext, "WAV")) ||
516
((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
517
(strcmp((char *)magic, "FORM") == 0) ) {
518
music->type = MUS_WAV;
519
music->data.wave = WAVStream_LoadSong(file, (char *)magic);
520
if ( music->data.wave == NULL ) {
521
Mix_SetError("Unable to load WAV file");
522
523
524
525
526
527
music->error = 1;
}
} else
#endif
#ifdef MID_MUSIC
/* MIDI files have the magic four bytes "MThd" */
528
529
if ( (ext && MIX_string_equals(ext, "MID")) ||
(ext && MIX_string_equals(ext, "MIDI")) ||
530
531
532
strcmp((char *)magic, "MThd") == 0 ||
( strcmp((char *)magic, "RIFF") == 0 &&
strcmp((char *)(moremagic+4), "RMID") == 0 ) ) {
533
music->type = MUS_MID;
534
535
536
537
538
539
540
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
music->data.nativemidi = native_midi_loadsong((char *)file);
if ( music->data.nativemidi == NULL ) {
Mix_SetError("%s", native_midi_error());
music->error = 1;
}
541
} MIDI_ELSE
542
#endif
543
#ifdef USE_TIMIDITY_MIDI
544
545
546
if ( timidity_ok ) {
music->data.midi = Timidity_LoadSong((char *)file);
if ( music->data.midi == NULL ) {
547
Mix_SetError("%s", Timidity_Error());
548
549
music->error = 1;
}
550
} else {
551
Mix_SetError("%s", Timidity_Error());
552
553
music->error = 1;
}
554
#endif
555
556
} else
#endif
557
558
#ifdef OGG_MUSIC
/* Ogg Vorbis files have the magic four bytes "OggS" */
559
if ( (ext && MIX_string_equals(ext, "OGG")) ||
560
strcmp((char *)magic, "OggS") == 0 ) {
561
562
563
564
565
566
567
music->type = MUS_OGG;
music->data.ogg = OGG_new(file);
if ( music->data.ogg == NULL ) {
music->error = 1;
}
} else
#endif
568
#ifdef MP3_MUSIC
569
if ( (ext && MIX_string_equals(ext, "MPG")) ||
570
(ext && MIX_string_equals(ext, "MP3")) ||
571
(ext && MIX_string_equals(ext, "MPEG")) ||
572
(magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ) {
573
574
575
SMPEG_Info info;
music->type = MUS_MP3;
music->data.mp3 = SMPEG_new(file, &info, 0);
576
if ( !info.has_audio ) {
577
Mix_SetError("MPEG file does not have any audio stream.");
578
music->error = 1;
579
} else {
580
581
582
583
SMPEG_actualSpec(music->data.mp3, &used_mixer);
}
} else
#endif
584
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
585
586
587
588
if ( 1 ) {
music->type = MUS_MOD;
music->data.module = MikMod_LoadSong((char *)file, 64);
if ( music->data.module == NULL ) {
589
Mix_SetError("%s", MikMod_strerror(MikMod_errno));
590
music->error = 1;
591
592
593
594
595
596
} else {
/* Stop implicit looping, fade out and other flags. */
music->data.module->extspd = 1;
music->data.module->panflag = 1;
music->data.module->wrap = 0;
music->data.module->loop = 0;
597
598
#if 0 /* Don't set fade out by default - unfortunately there's no real way
to query the status of the song or set trigger actions. Hum. */
599
music->data.module->fadeout = 1;
600
#endif
601
602
603
604
}
} else
#endif
{
605
Mix_SetError("Unrecognized music format");
606
607
608
609
610
611
612
613
614
615
616
617
618
music->error = 1;
}
if ( music->error ) {
free(music);
music = NULL;
}
return(music);
}
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
if ( music ) {
619
620
621
622
623
624
625
626
627
628
629
/* Stop the music if it's currently playing */
SDL_LockAudio();
if ( music == music_playing ) {
/* Wait for any fade out to finish */
while ( music->fading == MIX_FADING_OUT ) {
SDL_UnlockAudio();
SDL_Delay(100);
SDL_LockAudio();
}
if ( music == music_playing ) {
music_internal_halt();
630
}
631
}
632
SDL_UnlockAudio();
633
634
635
636
637
638
639
640
641
642
643
switch (music->type) {
#ifdef CMD_MUSIC
case MUS_CMD:
MusicCMD_FreeSong(music->data.cmd);
break;
#endif
#ifdef WAV_MUSIC
case MUS_WAV:
WAVStream_FreeSong(music->data.wave);
break;
#endif
644
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
645
646
647
648
649
650
case MUS_MOD:
MikMod_FreeSong(music->data.module);
break;
#endif
#ifdef MID_MUSIC
case MUS_MID:
651
652
653
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_freesong(music->data.nativemidi);
654
} MIDI_ELSE
655
#endif
656
#ifdef USE_TIMIDITY_MIDI
657
658
659
if ( timidity_ok ) {
Timidity_FreeSong(music->data.midi);
}
660
#endif
661
662
break;
#endif
663
664
665
666
667
#ifdef OGG_MUSIC
case MUS_OGG:
OGG_delete(music->data.ogg);
break;
#endif
668
#ifdef MP3_MUSIC
669
case MUS_MP3:
670
671
672
673
674
675
676
677
678
679
680
SMPEG_delete(music->data.mp3);
break;
#endif
default:
/* Unknown music type?? */
break;
}
free(music);
}
}
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
/* Find out the music format of a mixer music, or the currently playing
music, if 'music' is NULL.
*/
Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
{
Mix_MusicType type = MUS_NONE;
if ( music ) {
type = music->type;
} else {
SDL_LockAudio();
if ( music_playing ) {
type = music_playing->type;
}
SDL_UnlockAudio();
}
return(type);
}
700
701
702
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
static int music_internal_play(Mix_Music *music, double position)
703
{
704
705
706
707
708
709
710
int retval = 0;
/* Note the music we're playing */
if ( music_playing ) {
music_internal_halt();
}
music_playing = music;
711
712
/* Set the initial volume */
713
714
if ( music->type != MUS_MOD ) {
music_internal_initialize_volume();
715
716
717
}
/* Set up for playback */
718
719
switch (music->type) {
#ifdef CMD_MUSIC
720
721
722
case MUS_CMD:
MusicCMD_Start(music->data.cmd);
break;
723
724
#endif
#ifdef WAV_MUSIC
725
726
727
case MUS_WAV:
WAVStream_Start(music->data.wave);
break;
728
#endif
729
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
730
731
case MUS_MOD:
Player_Start(music->data.module);
732
733
/* Player_SetVolume() does nothing before Player_Start() */
music_internal_initialize_volume();
734
break;
735
736
#endif
#ifdef MID_MUSIC
737
case MUS_MID:
738
#ifdef USE_NATIVE_MIDI
739
740
741
if ( native_midi_ok ) {
native_midi_start(music->data.nativemidi);
} MIDI_ELSE
742
#endif
743
#ifdef USE_TIMIDITY_MIDI
744
745
746
if ( timidity_ok ) {
Timidity_Start(music->data.midi);
}
747
#endif
748
break;
749
#endif
750
#ifdef OGG_MUSIC
751
752
753
case MUS_OGG:
OGG_play(music->data.ogg);
break;
754
#endif
755
#ifdef MP3_MUSIC
756
757
758
case MUS_MP3:
SMPEG_enableaudio(music->data.mp3,1);
SMPEG_enablevideo(music->data.mp3,0);
759
SMPEG_play(music_playing->data.mp3);
760
break;
761
#endif
762
763
764
765
default:
Mix_SetError("Can't play unknown music type");
retval = -1;
break;
766
}
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
/* Set the playback position, note any errors if an offset is used */
if ( retval == 0 ) {
if ( position > 0.0 ) {
if ( music_internal_position(position) < 0 ) {
Mix_SetError("Position not implemented for music type");
retval = -1;
}
} else {
music_internal_position(0.0);
}
}
/* If the setup failed, we're not playing any music anymore */
if ( retval < 0 ) {
music_playing = NULL;
}
return(retval);
}
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
787
{
788
789
int retval;
790
791
/* Don't play null pointers :-) */
if ( music == NULL ) {
792
Mix_SetError("music parameter was NULL");
793
794
return(-1);
}
795
796
797
798
799
800
/* Setup the data */
if ( ms ) {
music->fading = MIX_FADING_IN;
} else {
music->fading = MIX_NO_FADING;
801
}
802
803
music->fade_step = 0;
music->fade_steps = ms/ms_per_step;
804
805
806
807
808
809
810
811
/* Play the puppy */
SDL_LockAudio();
/* If the current music is fading out, wait for the fade to complete */
while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
SDL_UnlockAudio();
SDL_Delay(100);
SDL_LockAudio();
812
}
813
music_active = 1;
814
music_loops = loops;
815
816
817
818
819
820
821
822
823
824
825
826
retval = music_internal_play(music, position);
SDL_UnlockAudio();
return(retval);
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
827
828
}
829
830
/* Set the playing music position */
int music_internal_position(double position)
831
{
832
833
834
int retval = 0;
switch (music_playing->type) {
835
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
836
837
838
case MUS_MOD:
Player_SetPosition((UWORD)position);
break;
839
840
#endif
#ifdef OGG_MUSIC
841
842
843
case MUS_OGG:
OGG_jump_to_time(music_playing->data.ogg, position);
break;
844
845
#endif
#ifdef MP3_MUSIC
846
case MUS_MP3:
847
if ( position > 0.0 ) {
848
SMPEG_skip(music_playing->data.mp3, position);
849
850
851
} else {
SMPEG_rewind(music_playing->data.mp3);
SMPEG_play(music_playing->data.mp3);
852
}
853
854
855
856
857
858
break;
#endif
default:
/* TODO: Implement this for other music backends */
retval = -1;
break;
859
}
860
return(retval);
861
}
862
int Mix_SetMusicPosition(double position)
863
{
864
865
866
867
868
869
870
int retval;
SDL_LockAudio();
if ( music_playing ) {
retval = music_internal_position(position);
if ( retval < 0 ) {
Mix_SetError("Position not implemented for music type");
871
}
872
873
874
} else {
Mix_SetError("Music isn't playing");
retval = -1;
875
}
876
SDL_UnlockAudio();
877
878
return(retval);
879
880
}
881
882
883
884
885
886
887
888
889
890
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
if ( music_playing->fading == MIX_FADING_IN ) {
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
}
891
/* Set the music volume */
892
static void music_internal_volume(int volume)
893
{
894
switch (music_playing->type) {
895
#ifdef CMD_MUSIC
896
897
898
case MUS_CMD:
MusicCMD_SetVolume(volume);
break;
899
900
#endif
#ifdef WAV_MUSIC
901
902
903
case MUS_WAV:
WAVStream_SetVolume(volume);
break;
904
#endif
905
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
906
907
908
case MUS_MOD:
Player_SetVolume((SWORD)volume);
break;
909
910
#endif
#ifdef MID_MUSIC
911
case MUS_MID:
912
#ifdef USE_NATIVE_MIDI
913
914
915
if ( native_midi_ok ) {
native_midi_setvolume(volume);
} MIDI_ELSE
916
#endif
917
#ifdef USE_TIMIDITY_MIDI
918
919
920
if ( timidity_ok ) {
Timidity_SetVolume(volume);
}
921
#endif
922
break;
923
#endif
924
#ifdef OGG_MUSIC
925
926
927
case MUS_OGG:
OGG_setvolume(music_playing->data.ogg, volume);
break;
928
#endif
929
#ifdef MP3_MUSIC
930
931
932
case MUS_MP3:
SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
break;
933
#endif
934
935
936
937
938
939
940
941
942
943
944
945
default:
/* Unknown music type?? */
break;
}
}
int Mix_VolumeMusic(int volume)
{
int prev_volume;
prev_volume = music_volume;
if ( volume < 0 ) {
return prev_volume;
946
}
947
948
949
950
951
952
953
954
955
if ( volume > SDL_MIX_MAXVOLUME ) {
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
SDL_LockAudio();
if ( music_playing ) {
music_internal_volume(music_volume);
}
SDL_UnlockAudio();
956
957
958
return(prev_volume);
}
959
960
/* Halt playing of music */
static void music_internal_halt(void)
961
{
962
switch (music_playing->type) {
963
#ifdef CMD_MUSIC
964
case MUS_CMD:
965
966
MusicCMD_Stop(music_playing->data.cmd);
break;
967
968
#endif
#ifdef WAV_MUSIC
969
case MUS_WAV:
970
971
WAVStream_Stop();
break;
972
#endif
973
#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
974
case MUS_MOD:
975
976
Player_Stop();
break;
977
978
#endif
#ifdef MID_MUSIC
979
case MUS_MID:
980
981
982
#ifdef USE_NATIVE_MIDI
if ( native_midi_ok ) {
native_midi_stop();
983
} MIDI_ELSE
984
#endif
985
#ifdef USE_TIMIDITY_MIDI
986
987
988
if ( timidity_ok ) {
Timidity_Stop();
}
989
#endif
990
break;
991
#endif
992
#ifdef OGG_MUSIC
993
case MUS_OGG:
994
995
996
OGG_stop(music_playing->data.ogg);
break;
#endif
997
#ifdef MP3_MUSIC
998
case MUS_MP3:
999
1000
SMPEG_stop(music_playing->data.mp3);
break;