/
music.c
1132 lines (994 loc) · 30.5 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 <string.h> /* for strtok() and strtok_s() */
22
23
#include "SDL_hints.h"
24
#include "SDL_log.h"
25
#include "SDL_timer.h"
26
27
#include "SDL_mixer.h"
28
#include "mixer.h"
29
#include "music.h"
30
31
#include "music_cmd.h"
32
33
#include "music_wav.h"
#include "music_mikmod.h"
34
#include "music_modplug.h"
35
36
37
#include "music_nativemidi.h"
#include "music_fluidsynth.h"
#include "music_timidity.h"
38
#include "music_ogg.h"
39
#include "music_opus.h"
40
#include "music_mpg123.h"
41
#include "music_mad.h"
42
#include "music_flac.h"
43
#include "native_midi/native_midi.h"
44
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
while (music_playing && music_active && len > 0) {
223
/* Handle fading */
224
225
if (music_playing->fading != MIX_NO_FADING) {
if (music_playing->fade_step++ < music_playing->fade_steps) {
226
227
228
229
int volume;
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
230
if (music_playing->fading == MIX_FADING_OUT) {
231
232
233
234
235
236
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
} else { /* Fading in */
volume = (music_volume * fade_step) / fade_steps;
}
music_internal_volume(volume);
} else {
237
if (music_playing->fading == MIX_FADING_OUT) {
238
music_internal_halt();
239
if (music_finished_hook) {
240
241
242
243
244
245
246
247
music_finished_hook();
}
return;
}
music_playing->fading = MIX_NO_FADING;
}
}
248
249
if (music_playing->interface->GetAudio) {
int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
250
251
if (left != 0) {
/* Either an error or finished playing with data left */
252
253
music_playing->playing = SDL_FALSE;
}
254
255
256
257
258
259
260
261
262
if (left > 0) {
stream += (len - left);
len = left;
} else {
len = 0;
}
} else {
len = 0;
}
263
264
265
266
267
if (!music_internal_playing()) {
music_internal_halt();
if (music_finished_hook) {
music_finished_hook();
268
}
269
270
}
}
271
272
}
273
274
/* Load the music interface libraries for a given music type */
SDL_bool load_music_type(Mix_MusicType type)
275
{
276
int i, loaded = 0;
277
278
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
279
if (interface->type != type) {
280
281
continue;
}
282
283
284
285
286
287
if (!interface->loaded) {
char hint[64];
SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
continue;
}
288
289
290
291
292
293
294
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;
}
295
296
interface->loaded = SDL_TRUE;
}
297
++loaded;
298
}
299
return (loaded > 0) ? SDL_TRUE : SDL_FALSE;
300
301
}
302
303
/* Open the music interfaces for a given music type */
SDL_bool open_music_type(Mix_MusicType type)
304
{
305
int i, opened = 0;
306
SDL_bool use_native_midi = SDL_FALSE;
307
308
309
310
if (!music_spec.format) {
/* Music isn't opened yet */
return SDL_FALSE;
311
312
}
313
#ifdef MUSIC_MID_NATIVE
314
if (type == MUS_MID && SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
315
use_native_midi = SDL_TRUE;
316
}
317
#endif
318
319
320
321
322
323
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->loaded) {
continue;
}
324
325
326
if (type != MUS_NONE && interface->type != type) {
continue;
}
327
328
329
330
331
if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
continue;
}
332
333
334
335
336
337
338
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;
}
339
340
341
interface->opened = SDL_TRUE;
add_music_decoder(interface->tag);
}
342
++opened;
343
344
}
345
346
if (has_music(MUS_MOD)) {
add_music_decoder("MOD");
347
add_chunk_decoder("MOD");
348
349
350
}
if (has_music(MUS_MID)) {
add_music_decoder("MIDI");
351
352
353
354
355
add_chunk_decoder("MID");
}
if (has_music(MUS_OGG)) {
add_music_decoder("OGG");
add_chunk_decoder("OGG");
356
}
357
358
359
360
if (has_music(MUS_OPUS)) {
add_music_decoder("OPUS");
add_chunk_decoder("OPUS");
}
361
362
if (has_music(MUS_MP3)) {
add_music_decoder("MP3");
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
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);
379
}
380
381
382
383
384
385
386
387
388
#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);
389
390
391
392
393
Mix_VolumeMusic(MIX_MAX_VOLUME);
/* Calculate the number of ms for each callback */
ms_per_step = (int) (((float)spec->samples * 1000.0) / spec->freq);
394
}
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/* Return SDL_TRUE if the music type is available */
SDL_bool has_music(Mix_MusicType type)
{
int i;
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;
410
411
}
412
Mix_MusicType detect_music_type(SDL_RWops *src)
413
{
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
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;
}
429
/* Ogg Vorbis files have the magic four bytes "OggS" */
430
if (SDL_memcmp(magic, "OggS", 4) == 0) {
431
432
SDL_RWseek(src, 28, RW_SEEK_CUR);
SDL_RWread(src, magic, 1, 8);
433
SDL_RWseek(src,-36, RW_SEEK_CUR);
434
435
436
if (SDL_memcmp(magic, "OpusHead", 8) == 0) {
return MUS_OPUS;
}
437
438
439
440
return MUS_OGG;
}
/* FLAC files have the magic four bytes "fLaC" */
441
if (SDL_memcmp(magic, "fLaC", 4) == 0) {
442
443
444
445
return MUS_FLAC;
}
/* MIDI files have the magic four bytes "MThd" */
446
if (SDL_memcmp(magic, "MThd", 4) == 0) {
447
448
449
return MUS_MID;
}
450
451
if (SDL_memcmp(magic, "ID3", 3) == 0 ||
(magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
452
453
454
455
456
457
458
459
460
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;
461
462
}
463
464
465
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
466
467
468
int i;
void *context;
char *ext;
469
Mix_MusicType type;
470
471
472
473
474
475
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;
476
}
477
478
479
480
481
482
483
484
485
486
487
488
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;
489
490
491
}
}
492
src = SDL_RWFromFile(file, "rb");
493
if (src == NULL) {
494
495
496
497
498
499
500
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, '.');
501
if (ext) {
502
++ext; /* skip the dot in the extension */
503
if (SDL_strcasecmp(ext, "WAV") == 0) {
504
type = MUS_WAV;
505
506
507
} else if (SDL_strcasecmp(ext, "MID") == 0 ||
SDL_strcasecmp(ext, "MIDI") == 0 ||
SDL_strcasecmp(ext, "KAR") == 0) {
508
type = MUS_MID;
509
} else if (SDL_strcasecmp(ext, "OGG") == 0) {
510
type = MUS_OGG;
511
512
} else if (SDL_strcasecmp(ext, "OPUS") == 0) {
type = MUS_OPUS;
513
} else if (SDL_strcasecmp(ext, "FLAC") == 0) {
514
type = MUS_FLAC;
515
516
517
518
} else if (SDL_strcasecmp(ext, "MPG") == 0 ||
SDL_strcasecmp(ext, "MPEG") == 0 ||
SDL_strcasecmp(ext, "MP3") == 0 ||
SDL_strcasecmp(ext, "MAD") == 0) {
519
type = MUS_MP3;
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
} 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;
542
543
}
}
544
return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
545
546
}
547
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
548
{
549
return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
550
551
}
552
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
553
{
554
555
int i;
void *context;
556
Sint64 start;
557
558
if (!src) {
559
560
561
Mix_SetError("RWops pointer is NULL");
return NULL;
}
562
start = SDL_RWtell(src);
563
564
565
566
/* If the caller wants auto-detection, figure out what kind of file
* this is. */
if (type == MUS_NONE) {
567
if ((type = detect_music_type(src)) == MUS_NONE) {
568
/* Don't call Mix_SetError() since detect_music_type() does that. */
569
570
571
if (freesrc) {
SDL_RWclose(src);
}
572
573
574
575
return NULL;
}
}
576
Mix_ClearError();
577
578
579
580
581
582
583
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;
}
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
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;
601
}
602
603
604
605
/* Reset the stream for the next decoder */
SDL_RWseek(src, start, RW_SEEK_SET);
}
606
}
607
608
609
if (!*Mix_GetError()) {
Mix_SetError("Unrecognized audio format");
610
}
611
612
613
614
615
616
if (freesrc) {
SDL_RWclose(src);
} else {
SDL_RWseek(src, start, RW_SEEK_SET);
}
return NULL;
617
618
619
620
621
}
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
622
if (music) {
623
/* Stop the music if it's currently playing */
624
Mix_LockAudio();
625
if (music == music_playing) {
626
/* Wait for any fade out to finish */
627
while (music->fading == MIX_FADING_OUT) {
628
Mix_UnlockAudio();
629
SDL_Delay(100);
630
Mix_LockAudio();
631
}
632
if (music == music_playing) {
633
634
635
music_internal_halt();
}
}
636
Mix_UnlockAudio();
637
638
music->interface->Delete(music->context);
639
640
SDL_free(music);
}
641
642
}
643
644
645
646
647
/* 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)
{
648
649
Mix_MusicType type = MUS_NONE;
650
651
if (music) {
type = music->interface->type;
652
} else {
653
Mix_LockAudio();
654
655
if (music_playing) {
type = music_playing->interface->type;
656
}
657
Mix_UnlockAudio();
658
659
}
return(type);
660
661
}
662
663
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
664
static int music_internal_play(Mix_Music *music, int play_count, double position)
665
{
666
int retval = 0;
667
668
#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
669
670
671
/* This fixes a bug with native MIDI on Mac OS X, where you
can't really stop and restart MIDI from the audio callback.
*/
672
if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
673
674
675
676
677
678
679
/* Just a seek suffices to restart playing */
music_internal_position(position);
return 0;
}
#endif
/* Note the music we're playing */
680
if (music_playing) {
681
682
683
music_internal_halt();
}
music_playing = music;
684
music_playing->playing = SDL_TRUE;
685
686
/* Set the initial volume */
687
music_internal_initialize_volume();
688
689
/* Set up for playback */
690
retval = music->interface->Play(music->context, play_count);
691
692
/* Set the playback position, note any errors if an offset is used */
693
694
695
if (retval == 0) {
if (position > 0.0) {
if (music_internal_position(position) < 0) {
696
697
698
699
700
701
702
703
704
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 */
705
if (retval < 0) {
706
music->playing = SDL_FALSE;
707
708
709
music_playing = NULL;
}
return(retval);
710
}
711
712
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
713
{
714
715
int retval;
716
if (ms_per_step == 0) {
717
718
719
720
721
SDL_SetError("Audio device hasn't been opened");
return(-1);
}
/* Don't play null pointers :-) */
722
if (music == NULL) {
723
724
725
726
727
Mix_SetError("music parameter was NULL");
return(-1);
}
/* Setup the data */
728
if (ms) {
729
730
731
732
733
734
735
736
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 */
737
Mix_LockAudio();
738
/* If the current music is fading out, wait for the fade to complete */
739
while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
740
Mix_UnlockAudio();
741
SDL_Delay(100);
742
Mix_LockAudio();
743
}
744
if (loops == 0) {
745
/* Loop is the number of times to play the audio */
746
loops = 1;
747
}
748
retval = music_internal_play(music, loops, position);
749
music_active = (retval == 0);
750
Mix_UnlockAudio();
751
752
return(retval);
753
754
755
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
756
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
757
758
759
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
760
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
761
762
}
763
764
/* Set the playing music position */
int music_internal_position(double position)
765
{
766
767
if (music_playing->interface->Seek) {
return music_playing->interface->Seek(music_playing->context, position);
768
}
769
return -1;
770
}
771
int Mix_SetMusicPosition(double position)
772
{
773
774
int retval;
775
Mix_LockAudio();
776
if (music_playing) {
777
retval = music_internal_position(position);
778
if (retval < 0) {
779
780
781
782
783
784
Mix_SetError("Position not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
785
Mix_UnlockAudio();
786
787
return(retval);
788
789
}
790
791
792
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
793
if (music_playing->fading == MIX_FADING_IN) {
794
795
796
797
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
798
799
}
800
/* Set the music volume */
801
static void music_internal_volume(int volume)
802
{
803
804
if (music_playing->interface->SetVolume) {
music_playing->interface->SetVolume(music_playing->context, volume);
805
}
806
807
808
}
int Mix_VolumeMusic(int volume)
{
809
810
811
int prev_volume;
prev_volume = music_volume;
812
if (volume < 0) {
813
814
return prev_volume;
}
815
if (volume > SDL_MIX_MAXVOLUME) {
816
817
818
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
819
Mix_LockAudio();
820
if (music_playing) {
821
822
music_internal_volume(music_volume);
}
823
Mix_UnlockAudio();
824
return(prev_volume);
825
826
}
827
828
/* Halt playing of music */
static void music_internal_halt(void)
829
{
830
831
if (music_playing->interface->Stop) {
music_playing->interface->Stop(music_playing->context);
832
}
833
834
music_playing->playing = SDL_FALSE;
835
836
music_playing->fading = MIX_NO_FADING;
music_playing = NULL;
837
838
839
}
int Mix_HaltMusic(void)
{
840
Mix_LockAudio();
841
if (music_playing) {
842
music_internal_halt();
843
if (music_finished_hook) {
844
845
846
music_finished_hook();
}
}
847
Mix_UnlockAudio();
848
849
return(0);
850
851
}
852
853
854
/* Progressively stop the music */
int Mix_FadeOutMusic(int ms)
{
855
int retval = 0;
856
857
if (ms_per_step == 0) {
858
859
860
SDL_SetError("Audio device hasn't been opened");
return 0;
}
861
862
863
864
865
if (ms <= 0) { /* just halt immediately. */
Mix_HaltMusic();
return 1;
}
866
867
Mix_LockAudio();
868
869
870
871
872
873
874
875
876
877
878
879
880
881
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;
}
882
883
884
885
music_playing->fading = MIX_FADING_OUT;
music_playing->fade_steps = fade_steps;
retval = 1;
}
886
Mix_UnlockAudio();
887
888
return(retval);
889
890
891
892
}
Mix_Fading Mix_FadingMusic(void)
{
893
Mix_Fading fading = MIX_NO_FADING;
894
895
Mix_LockAudio();
896
if (music_playing) {
897
898
fading = music_playing->fading;
}
899
Mix_UnlockAudio();
900
901
return(fading);
902
903
}
904
905
906
/* Pause/Resume the music stream */
void Mix_PauseMusic(void)
{
907
Mix_LockAudio();
908
909
910
911
if (music_playing) {
if (music_playing->interface->Pause) {
music_playing->interface->Pause(music_playing->context);
}
912
}
913
music_active = SDL_FALSE;
914
Mix_UnlockAudio();
915
}
916
917
918
void Mix_ResumeMusic(void)
{
919
Mix_LockAudio();
920
921
922
923
if (music_playing) {
if (music_playing->interface->Resume) {
music_playing->interface->Resume(music_playing->context);
}
924
}
925
music_active = SDL_TRUE;
926
Mix_UnlockAudio();
927
928
929
930
}
void Mix_RewindMusic(void)
{
931
Mix_SetMusicPosition(0.0);
932
933
}
934
935
int Mix_PausedMusic(void)
{
936
return (music_active == SDL_FALSE);
937
938
}
939
/* Check the status of the music */
940
static SDL_bool music_internal_playing(void)
941
{
942
if (!music_playing) {
943
return SDL_FALSE;
944
}
945
946
if (music_playing->interface->IsPlaying) {
947
music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
948
}
949
return music_playing->playing;
950
951
952
}
int Mix_PlayingMusic(void)
{
953
SDL_bool playing;
954
955
Mix_LockAudio();
956
playing = music_internal_playing();
957
Mix_UnlockAudio();
958
959
return playing ? 1 : 0;
960
961
962
963
964
}
/* Set the external music playback command */
int Mix_SetMusicCMD(const char *command)
{
965
Mix_HaltMusic();
966
if (music_cmd) {
967
968
969
SDL_free(music_cmd);
music_cmd = NULL;
}
970
971
972
973
974
if (command) {
size_t length = SDL_strlen(command) + 1;
music_cmd = (char *)SDL_malloc(length);
if (music_cmd == NULL) {
return SDL_OutOfMemory();
975
}
976
SDL_memcpy(music_cmd, command, length);
977
}
978
return 0;
979
980
}
981
982
int Mix_SetSynchroValue(int i)
{
983
984
/* Not supported by any players at this time */
return(-1);
985
986
987
988
}
int Mix_GetSynchroValue(void)
{
989
990
/* Not supported by any players at this time */
return(-1);
991
992
993
}
994
/* Uninitialize the music interfaces */
995
996
void close_music(void)
{
997
998
int i;
999
Mix_HaltMusic();
1000