/
music.c
1133 lines (994 loc) · 30.4 KB
1
/*
2
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_hints.h"
22
#include "SDL_log.h"
23
#include "SDL_timer.h"
24
25
#include "SDL_mixer.h"
26
#include "mixer.h"
27
#include "music.h"
28
29
#include "music_cmd.h"
30
31
#include "music_wav.h"
#include "music_mikmod.h"
32
#include "music_modplug.h"
33
34
35
#include "music_nativemidi.h"
#include "music_fluidsynth.h"
#include "music_timidity.h"
36
#include "music_ogg.h"
37
#include "music_opus.h"
38
#include "music_mpg123.h"
39
#include "music_mad.h"
40
#include "music_flac.h"
41
#include "native_midi/native_midi.h"
42
43
44
#include "compat.h"
45
46
47
48
49
/* Check to make sure we are building with a new enough SDL */
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 7)
#error You need SDL 2.0.7 or newer from http://www.libsdl.org
#endif
50
51
52
/* Set this hint to true if you want verbose logging of music interfaces */
#define SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES \
"SDL_MIXER_DEBUG_MUSIC_INTERFACES"
54
char *music_cmd = NULL;
55
56
static SDL_bool music_active = SDL_TRUE;
static int music_volume = MIX_MAX_VOLUME;
57
static Mix_Music * volatile music_playing = NULL;
58
SDL_AudioSpec music_spec;
59
60
struct _Mix_Music {
61
62
63
64
Mix_MusicInterface *interface;
void *context;
SDL_bool playing;
65
66
67
Mix_Fading fading;
int fade_step;
int fade_steps;
68
69
};
70
71
72
/* Used to calculate fading steps */
static int ms_per_step;
73
74
75
76
/* rcg06042009 report available decoders at runtime. */
static const char **music_decoders = NULL;
static int num_decoders = 0;
77
/* Semicolon-separated SoundFont paths */
78
static char* soundfont_paths = NULL;
79
80
81
82
83
84
85
86
87
88
/* Interfaces for the various music interfaces, ordered by priority */
static Mix_MusicInterface *s_music_interfaces[] =
{
#ifdef MUSIC_CMD
&Mix_MusicInterface_CMD,
#endif
#ifdef MUSIC_WAV
&Mix_MusicInterface_WAV,
#endif
89
90
91
92
93
94
#ifdef MUSIC_FLAC
&Mix_MusicInterface_FLAC,
#endif
#ifdef MUSIC_OGG
&Mix_MusicInterface_OGG,
#endif
95
96
97
#ifdef MUSIC_OPUS
&Mix_MusicInterface_Opus,
#endif
98
99
100
101
102
103
#ifdef MUSIC_MP3_MPG123
&Mix_MusicInterface_MPG123,
#endif
#ifdef MUSIC_MP3_MAD
&Mix_MusicInterface_MAD,
#endif
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifdef MUSIC_MOD_MODPLUG
&Mix_MusicInterface_MODPLUG,
#endif
#ifdef MUSIC_MOD_MIKMOD
&Mix_MusicInterface_MIKMOD,
#endif
#ifdef MUSIC_MID_FLUIDSYNTH
&Mix_MusicInterface_FLUIDSYNTH,
#endif
#ifdef MUSIC_MID_TIMIDITY
&Mix_MusicInterface_TIMIDITY,
#endif
#ifdef MUSIC_MID_NATIVE
&Mix_MusicInterface_NATIVEMIDI,
#endif
};
int get_num_music_interfaces(void)
{
return SDL_arraysize(s_music_interfaces);
}
Mix_MusicInterface *get_music_interface(int index)
{
return s_music_interfaces[index];
}
131
int Mix_GetNumMusicDecoders(void)
132
{
133
return(num_decoders);
134
135
136
137
}
const char *Mix_GetMusicDecoder(int index)
{
138
139
140
141
if ((index < 0) || (index >= num_decoders)) {
return NULL;
}
return(music_decoders[index]);
142
143
144
145
}
static void add_music_decoder(const char *decoder)
{
146
147
148
149
150
151
152
153
154
155
156
void *ptr;
int i;
/* Check to see if we already have this decoder */
for (i = 0; i < num_decoders; ++i) {
if (SDL_strcmp(music_decoders[i], decoder) == 0) {
return;
}
}
ptr = SDL_realloc((void *)music_decoders, (num_decoders + 1) * sizeof (const char *));
157
158
159
160
161
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
162
163
}
164
/* Local low-level functions prototypes */
165
static void music_internal_initialize_volume(void);
166
static void music_internal_volume(int volume);
167
static int music_internal_play(Mix_Music *music, int play_count, double position);
168
static int music_internal_position(double position);
169
static SDL_bool music_internal_playing(void);
170
static void music_internal_halt(void);
171
172
173
/* Support for hooking when the music has finished */
174
static void (SDLCALL *music_finished_hook)(void) = NULL;
175
176
void Mix_HookMusicFinished(void (SDLCALL *music_finished)(void))
177
{
178
Mix_LockAudio();
179
music_finished_hook = music_finished;
180
Mix_UnlockAudio();
181
182
}
183
184
185
186
187
/* Convenience function to fill audio and mix at the specified volume
This is called from many music player's GetAudio callback.
*/
int music_pcm_getaudio(void *context, void *data, int bytes, int volume,
int (*GetSome)(void *context, void *data, int bytes, SDL_bool *done))
188
{
189
190
191
192
Uint8 *snd = (Uint8 *)data;
Uint8 *dst;
int len = bytes;
SDL_bool done = SDL_FALSE;
193
194
195
196
197
198
199
200
201
202
if (volume == MIX_MAX_VOLUME) {
dst = snd;
} else {
dst = SDL_stack_alloc(Uint8, bytes);
}
while (len > 0 && !done) {
int consumed = GetSome(context, dst, len, &done);
if (consumed < 0) {
break;
203
204
}
205
206
207
208
209
if (volume == MIX_MAX_VOLUME) {
dst += consumed;
} else {
SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
snd += consumed;
210
}
211
len -= consumed;
212
}
213
214
215
216
if (volume != MIX_MAX_VOLUME) {
SDL_stack_free(dst);
}
return len;
217
218
}
219
/* Mixing function */
220
void SDLCALL music_mixer(void *udata, Uint8 *stream, int len)
221
{
222
223
(void)udata;
224
while (music_playing && music_active && len > 0) {
225
/* Handle fading */
226
227
if (music_playing->fading != MIX_NO_FADING) {
if (music_playing->fade_step++ < music_playing->fade_steps) {
228
229
230
231
int volume;
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
232
if (music_playing->fading == MIX_FADING_OUT) {
233
234
235
236
237
238
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
} else { /* Fading in */
volume = (music_volume * fade_step) / fade_steps;
}
music_internal_volume(volume);
} else {
239
if (music_playing->fading == MIX_FADING_OUT) {
240
music_internal_halt();
241
if (music_finished_hook) {
242
243
244
245
246
247
248
249
music_finished_hook();
}
return;
}
music_playing->fading = MIX_NO_FADING;
}
}
250
251
if (music_playing->interface->GetAudio) {
int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
252
253
if (left != 0) {
/* Either an error or finished playing with data left */
254
255
music_playing->playing = SDL_FALSE;
}
256
257
258
259
260
261
262
263
264
if (left > 0) {
stream += (len - left);
len = left;
} else {
len = 0;
}
} else {
len = 0;
}
265
266
267
268
269
if (!music_internal_playing()) {
music_internal_halt();
if (music_finished_hook) {
music_finished_hook();
270
}
271
272
}
}
273
274
}
275
276
/* Load the music interface libraries for a given music type */
SDL_bool load_music_type(Mix_MusicType type)
277
{
278
279
size_t i;
int loaded = 0;
280
281
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
282
if (interface->type != type) {
283
284
continue;
}
285
286
287
288
289
290
if (!interface->loaded) {
char hint[64];
SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
continue;
}
291
292
293
294
295
296
297
if (interface->Load && interface->Load() < 0) {
if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
SDL_Log("Couldn't load %s: %s\n", interface->tag, Mix_GetError());
}
continue;
}
298
299
interface->loaded = SDL_TRUE;
}
300
++loaded;
301
}
302
return (loaded > 0) ? SDL_TRUE : SDL_FALSE;
303
304
}
305
306
/* Open the music interfaces for a given music type */
SDL_bool open_music_type(Mix_MusicType type)
307
{
308
309
size_t i;
int opened = 0;
310
SDL_bool use_native_midi = SDL_FALSE;
311
312
313
314
if (!music_spec.format) {
/* Music isn't opened yet */
return SDL_FALSE;
315
316
}
317
#ifdef MUSIC_MID_NATIVE
318
if (type == MUS_MID && SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
319
use_native_midi = SDL_TRUE;
320
}
321
#endif
322
323
324
325
326
327
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->loaded) {
continue;
}
328
329
330
if (type != MUS_NONE && interface->type != type) {
continue;
}
331
332
333
334
335
if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
continue;
}
336
337
338
339
340
341
342
if (!interface->opened) {
if (interface->Open && interface->Open(&music_spec) < 0) {
if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
SDL_Log("Couldn't open %s: %s\n", interface->tag, Mix_GetError());
}
continue;
}
343
344
345
interface->opened = SDL_TRUE;
add_music_decoder(interface->tag);
}
346
++opened;
347
348
}
349
350
if (has_music(MUS_MOD)) {
add_music_decoder("MOD");
351
add_chunk_decoder("MOD");
352
353
354
}
if (has_music(MUS_MID)) {
add_music_decoder("MIDI");
355
356
357
358
359
add_chunk_decoder("MID");
}
if (has_music(MUS_OGG)) {
add_music_decoder("OGG");
add_chunk_decoder("OGG");
360
}
361
362
363
364
if (has_music(MUS_OPUS)) {
add_music_decoder("OPUS");
add_chunk_decoder("OPUS");
}
365
366
if (has_music(MUS_MP3)) {
add_music_decoder("MP3");
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
add_chunk_decoder("MP3");
}
if (has_music(MUS_FLAC)) {
add_music_decoder("FLAC");
add_chunk_decoder("FLAC");
}
return (opened > 0) ? SDL_TRUE : SDL_FALSE;
}
/* Initialize the music interfaces with a certain desired audio format */
void open_music(const SDL_AudioSpec *spec)
{
#ifdef MIX_INIT_SOUNDFONT_PATHS
if (!soundfont_paths) {
soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
383
}
384
385
386
387
388
389
390
391
392
#endif
/* Load the music interfaces that don't have explicit initialization */
load_music_type(MUS_CMD);
load_music_type(MUS_WAV);
/* Open all the interfaces that are loaded */
music_spec = *spec;
open_music_type(MUS_NONE);
393
394
395
396
397
Mix_VolumeMusic(MIX_MAX_VOLUME);
/* Calculate the number of ms for each callback */
ms_per_step = (int) (((float)spec->samples * 1000.0) / spec->freq);
398
}
399
400
401
402
/* Return SDL_TRUE if the music type is available */
SDL_bool has_music(Mix_MusicType type)
{
403
size_t i;
404
405
406
407
408
409
410
411
412
413
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (interface->type != type) {
continue;
}
if (interface->opened) {
return SDL_TRUE;
}
}
return SDL_FALSE;
414
415
}
416
Mix_MusicType detect_music_type(SDL_RWops *src)
417
{
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
Uint8 magic[12];
if (SDL_RWread(src, magic, 1, 12) != 12) {
Mix_SetError("Couldn't read first 12 bytes of audio data");
return MUS_NONE;
}
SDL_RWseek(src, -12, RW_SEEK_CUR);
/* WAVE files have the magic four bytes "RIFF"
AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
if (((SDL_memcmp(magic, "RIFF", 4) == 0) && (SDL_memcmp((magic+8), "WAVE", 4) == 0)) ||
(SDL_memcmp(magic, "FORM", 4) == 0)) {
return MUS_WAV;
}
433
/* Ogg Vorbis files have the magic four bytes "OggS" */
434
if (SDL_memcmp(magic, "OggS", 4) == 0) {
435
436
SDL_RWseek(src, 28, RW_SEEK_CUR);
SDL_RWread(src, magic, 1, 8);
437
SDL_RWseek(src,-36, RW_SEEK_CUR);
438
439
440
if (SDL_memcmp(magic, "OpusHead", 8) == 0) {
return MUS_OPUS;
}
441
442
443
444
return MUS_OGG;
}
/* FLAC files have the magic four bytes "fLaC" */
445
if (SDL_memcmp(magic, "fLaC", 4) == 0) {
446
447
448
449
return MUS_FLAC;
}
/* MIDI files have the magic four bytes "MThd" */
450
if (SDL_memcmp(magic, "MThd", 4) == 0) {
451
452
453
return MUS_MID;
}
454
455
if (SDL_memcmp(magic, "ID3", 3) == 0 ||
(magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
456
457
458
459
460
461
462
463
464
return MUS_MP3;
}
/* Assume MOD format.
*
* Apparently there is no way to check if the file is really a MOD,
* or there are too many formats supported by MikMod/ModPlug, or
* MikMod/ModPlug does this check by itself. */
return MUS_MOD;
465
466
}
467
468
469
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
470
size_t i;
471
472
void *context;
char *ext;
473
Mix_MusicType type;
474
475
476
477
478
479
SDL_RWops *src;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->opened || !interface->CreateFromFile) {
continue;
480
}
481
482
483
484
485
486
487
488
489
490
491
492
context = interface->CreateFromFile(file);
if (context) {
/* Allocate memory for the music structure */
Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
if (music == NULL) {
Mix_SetError("Out of memory");
return NULL;
}
music->interface = interface;
music->context = context;
return music;
493
494
495
}
}
496
src = SDL_RWFromFile(file, "rb");
497
if (src == NULL) {
498
499
500
501
502
503
504
Mix_SetError("Couldn't open '%s'", file);
return NULL;
}
/* Use the extension as a first guess on the file type */
type = MUS_NONE;
ext = strrchr(file, '.');
505
if (ext) {
506
++ext; /* skip the dot in the extension */
507
if (SDL_strcasecmp(ext, "WAV") == 0) {
508
type = MUS_WAV;
509
510
511
} else if (SDL_strcasecmp(ext, "MID") == 0 ||
SDL_strcasecmp(ext, "MIDI") == 0 ||
SDL_strcasecmp(ext, "KAR") == 0) {
512
type = MUS_MID;
513
} else if (SDL_strcasecmp(ext, "OGG") == 0) {
514
type = MUS_OGG;
515
516
} else if (SDL_strcasecmp(ext, "OPUS") == 0) {
type = MUS_OPUS;
517
} else if (SDL_strcasecmp(ext, "FLAC") == 0) {
518
type = MUS_FLAC;
519
520
521
522
} else if (SDL_strcasecmp(ext, "MPG") == 0 ||
SDL_strcasecmp(ext, "MPEG") == 0 ||
SDL_strcasecmp(ext, "MP3") == 0 ||
SDL_strcasecmp(ext, "MAD") == 0) {
523
type = MUS_MP3;
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
} else if (SDL_strcasecmp(ext, "669") == 0 ||
SDL_strcasecmp(ext, "AMF") == 0 ||
SDL_strcasecmp(ext, "AMS") == 0 ||
SDL_strcasecmp(ext, "DBM") == 0 ||
SDL_strcasecmp(ext, "DSM") == 0 ||
SDL_strcasecmp(ext, "FAR") == 0 ||
SDL_strcasecmp(ext, "IT") == 0 ||
SDL_strcasecmp(ext, "MED") == 0 ||
SDL_strcasecmp(ext, "MDL") == 0 ||
SDL_strcasecmp(ext, "MOD") == 0 ||
SDL_strcasecmp(ext, "MOL") == 0 ||
SDL_strcasecmp(ext, "MTM") == 0 ||
SDL_strcasecmp(ext, "NST") == 0 ||
SDL_strcasecmp(ext, "OKT") == 0 ||
SDL_strcasecmp(ext, "PTM") == 0 ||
SDL_strcasecmp(ext, "S3M") == 0 ||
SDL_strcasecmp(ext, "STM") == 0 ||
SDL_strcasecmp(ext, "ULT") == 0 ||
SDL_strcasecmp(ext, "UMX") == 0 ||
SDL_strcasecmp(ext, "WOW") == 0 ||
SDL_strcasecmp(ext, "XM") == 0) {
type = MUS_MOD;
546
547
}
}
548
return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
549
550
}
551
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
552
{
553
return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
554
555
}
556
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
557
{
558
size_t i;
559
void *context;
560
Sint64 start;
561
562
if (!src) {
563
564
565
Mix_SetError("RWops pointer is NULL");
return NULL;
}
566
start = SDL_RWtell(src);
567
568
569
570
/* If the caller wants auto-detection, figure out what kind of file
* this is. */
if (type == MUS_NONE) {
571
if ((type = detect_music_type(src)) == MUS_NONE) {
572
/* Don't call Mix_SetError() since detect_music_type() does that. */
573
574
575
if (freesrc) {
SDL_RWclose(src);
}
576
577
578
579
return NULL;
}
}
580
Mix_ClearError();
581
582
583
584
585
586
587
if (load_music_type(type) && open_music_type(type)) {
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->opened || type != interface->type || !interface->CreateFromRW) {
continue;
}
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
context = interface->CreateFromRW(src, freesrc);
if (context) {
/* Allocate memory for the music structure */
Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
if (music == NULL) {
interface->Delete(context);
Mix_SetError("Out of memory");
return NULL;
}
music->interface = interface;
music->context = context;
if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
SDL_Log("Loaded music with %s\n", interface->tag);
}
return music;
605
}
606
607
608
609
/* Reset the stream for the next decoder */
SDL_RWseek(src, start, RW_SEEK_SET);
}
610
}
611
612
613
if (!*Mix_GetError()) {
Mix_SetError("Unrecognized audio format");
614
}
615
616
617
618
619
620
if (freesrc) {
SDL_RWclose(src);
} else {
SDL_RWseek(src, start, RW_SEEK_SET);
}
return NULL;
621
622
623
624
625
}
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
626
if (music) {
627
/* Stop the music if it's currently playing */
628
Mix_LockAudio();
629
if (music == music_playing) {
630
/* Wait for any fade out to finish */
631
while (music->fading == MIX_FADING_OUT) {
632
Mix_UnlockAudio();
633
SDL_Delay(100);
634
Mix_LockAudio();
635
}
636
if (music == music_playing) {
637
638
639
music_internal_halt();
}
}
640
Mix_UnlockAudio();
641
642
music->interface->Delete(music->context);
643
644
SDL_free(music);
}
645
646
}
647
648
649
650
651
/* 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)
{
652
653
Mix_MusicType type = MUS_NONE;
654
655
if (music) {
type = music->interface->type;
656
} else {
657
Mix_LockAudio();
658
659
if (music_playing) {
type = music_playing->interface->type;
660
}
661
Mix_UnlockAudio();
662
663
}
return(type);
664
665
}
666
667
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
668
static int music_internal_play(Mix_Music *music, int play_count, double position)
669
{
670
int retval = 0;
671
672
#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
673
674
675
/* This fixes a bug with native MIDI on Mac OS X, where you
can't really stop and restart MIDI from the audio callback.
*/
676
if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
677
678
679
680
681
682
683
/* Just a seek suffices to restart playing */
music_internal_position(position);
return 0;
}
#endif
/* Note the music we're playing */
684
if (music_playing) {
685
686
687
music_internal_halt();
}
music_playing = music;
688
music_playing->playing = SDL_TRUE;
689
690
/* Set the initial volume */
691
music_internal_initialize_volume();
692
693
/* Set up for playback */
694
retval = music->interface->Play(music->context, play_count);
695
696
/* Set the playback position, note any errors if an offset is used */
697
698
699
if (retval == 0) {
if (position > 0.0) {
if (music_internal_position(position) < 0) {
700
701
702
703
704
705
706
707
708
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 */
709
if (retval < 0) {
710
music->playing = SDL_FALSE;
711
712
713
music_playing = NULL;
}
return(retval);
714
}
715
716
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
717
{
718
719
int retval;
720
if (ms_per_step == 0) {
721
722
723
724
725
SDL_SetError("Audio device hasn't been opened");
return(-1);
}
/* Don't play null pointers :-) */
726
if (music == NULL) {
727
728
729
730
731
Mix_SetError("music parameter was NULL");
return(-1);
}
/* Setup the data */
732
if (ms) {
733
734
735
736
737
738
739
740
music->fading = MIX_FADING_IN;
} else {
music->fading = MIX_NO_FADING;
}
music->fade_step = 0;
music->fade_steps = ms/ms_per_step;
/* Play the puppy */
741
Mix_LockAudio();
742
/* If the current music is fading out, wait for the fade to complete */
743
while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
744
Mix_UnlockAudio();
745
SDL_Delay(100);
746
Mix_LockAudio();
747
}
748
if (loops == 0) {
749
/* Loop is the number of times to play the audio */
750
loops = 1;
751
}
752
retval = music_internal_play(music, loops, position);
753
/* Set music as active */
754
music_active = (retval == 0);
755
Mix_UnlockAudio();
756
757
return(retval);
758
759
760
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
761
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
762
763
764
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
765
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
766
767
}
768
769
/* Set the playing music position */
int music_internal_position(double position)
770
{
771
772
if (music_playing->interface->Seek) {
return music_playing->interface->Seek(music_playing->context, position);
773
}
774
return -1;
775
}
776
int Mix_SetMusicPosition(double position)
777
{
778
779
int retval;
780
Mix_LockAudio();
781
if (music_playing) {
782
retval = music_internal_position(position);
783
if (retval < 0) {
784
785
786
787
788
789
Mix_SetError("Position not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
790
Mix_UnlockAudio();
791
792
return(retval);
793
794
}
795
796
797
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
798
if (music_playing->fading == MIX_FADING_IN) {
799
800
801
802
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
803
804
}
805
/* Set the music volume */
806
static void music_internal_volume(int volume)
807
{
808
809
if (music_playing->interface->SetVolume) {
music_playing->interface->SetVolume(music_playing->context, volume);
810
}
811
812
813
}
int Mix_VolumeMusic(int volume)
{
814
815
816
int prev_volume;
prev_volume = music_volume;
817
if (volume < 0) {
818
819
return prev_volume;
}
820
if (volume > SDL_MIX_MAXVOLUME) {
821
822
823
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
824
Mix_LockAudio();
825
if (music_playing) {
826
827
music_internal_volume(music_volume);
}
828
Mix_UnlockAudio();
829
return(prev_volume);
830
831
}
832
833
/* Halt playing of music */
static void music_internal_halt(void)
834
{
835
836
if (music_playing->interface->Stop) {
music_playing->interface->Stop(music_playing->context);
837
}
838
839
music_playing->playing = SDL_FALSE;
840
841
music_playing->fading = MIX_NO_FADING;
music_playing = NULL;
842
843
844
}
int Mix_HaltMusic(void)
{
845
Mix_LockAudio();
846
if (music_playing) {
847
music_internal_halt();
848
if (music_finished_hook) {
849
850
851
music_finished_hook();
}
}
852
Mix_UnlockAudio();
853
854
return(0);
855
856
}
857
858
859
/* Progressively stop the music */
int Mix_FadeOutMusic(int ms)
{
860
int retval = 0;
861
862
if (ms_per_step == 0) {
863
864
865
SDL_SetError("Audio device hasn't been opened");
return 0;
}
866
867
868
869
870
if (ms <= 0) { /* just halt immediately. */
Mix_HaltMusic();
return 1;
}
871
872
Mix_LockAudio();
873
874
875
876
877
878
879
880
881
882
883
884
885
886
if (music_playing) {
int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
if (music_playing->fading == MIX_NO_FADING) {
music_playing->fade_step = 0;
} else {
int step;
int old_fade_steps = music_playing->fade_steps;
if (music_playing->fading == MIX_FADING_OUT) {
step = music_playing->fade_step;
} else {
step = old_fade_steps - music_playing->fade_step + 1;
}
music_playing->fade_step = (step * fade_steps) / old_fade_steps;
}
887
888
889
890
music_playing->fading = MIX_FADING_OUT;
music_playing->fade_steps = fade_steps;
retval = 1;
}
891
Mix_UnlockAudio();
892
893
return(retval);
894
895
896
897
}
Mix_Fading Mix_FadingMusic(void)
{
898
Mix_Fading fading = MIX_NO_FADING;
899
900
Mix_LockAudio();
901
if (music_playing) {
902
903
fading = music_playing->fading;
}
904
Mix_UnlockAudio();
905
906
return(fading);
907
908
}
909
910
911
/* Pause/Resume the music stream */
void Mix_PauseMusic(void)
{
912
Mix_LockAudio();
913
914
915
916
if (music_playing) {
if (music_playing->interface->Pause) {
music_playing->interface->Pause(music_playing->context);
}
917
}
918
music_active = SDL_FALSE;
919
Mix_UnlockAudio();
920
}
921
922
923
void Mix_ResumeMusic(void)
{
924
Mix_LockAudio();
925
926
927
928
if (music_playing) {
if (music_playing->interface->Resume) {
music_playing->interface->Resume(music_playing->context);
}
929
}
930
music_active = SDL_TRUE;
931
Mix_UnlockAudio();
932
933
934
935
}
void Mix_RewindMusic(void)
{
936
Mix_SetMusicPosition(0.0);
937
938
}
939
940
int Mix_PausedMusic(void)
{
941
return (music_active == SDL_FALSE);
942
943
}
944
/* Check the status of the music */
945
static SDL_bool music_internal_playing(void)
946
{
947
if (!music_playing) {
948
return SDL_FALSE;
949
}
950
951
if (music_playing->interface->IsPlaying) {
952
music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
953
}
954
return music_playing->playing;
955
956
957
}
int Mix_PlayingMusic(void)
{
958
SDL_bool playing;
959
960
Mix_LockAudio();
961
playing = music_internal_playing();
962
Mix_UnlockAudio();
963
964
return playing ? 1 : 0;
965
966
967
968
969
}
/* Set the external music playback command */
int Mix_SetMusicCMD(const char *command)
{
970
Mix_HaltMusic();
971
if (music_cmd) {
972
973
974
SDL_free(music_cmd);
music_cmd = NULL;
}
975
976
977
978
979
if (command) {
size_t length = SDL_strlen(command) + 1;
music_cmd = (char *)SDL_malloc(length);
if (music_cmd == NULL) {
return SDL_OutOfMemory();
980
}
981
SDL_memcpy(music_cmd, command, length);
982
}
983
return 0;
984
985
}
986
987
int Mix_SetSynchroValue(int i)
{
988
989
/* Not supported by any players at this time */
return(-1);
990
991
992
993
}
int Mix_GetSynchroValue(void)
{
994
995
/* Not supported by any players at this time */
return(-1);
996
997
998
}
999
/* Uninitialize the music interfaces */
1000
void close_music(void)