/
music.c
1026 lines (890 loc) · 26.7 KB
2
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2017 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() */
23
#include "SDL_hints.h"
24
#include "SDL_timer.h"
26
#include "SDL_mixer.h"
27
#include "mixer.h"
28
#include "music.h"
29
30
#include "music_cmd.h"
31
32
#include "music_wav.h"
#include "music_mikmod.h"
33
#include "music_modplug.h"
34
35
36
#include "music_nativemidi.h"
#include "music_fluidsynth.h"
#include "music_timidity.h"
37
#include "music_ogg.h"
38
#include "music_mpg123.h"
40
#include "music_smpeg.h"
41
#include "music_flac.h"
42
#include "native_midi/native_midi.h"
45
char *music_cmd = NULL;
46
47
int volatile music_active = 1;
static Mix_Music * volatile music_playing = NULL;
48
49
50
int music_loops = 0;
int music_volume = MIX_MAX_VOLUME;
SDL_AudioSpec music_spec;
52
struct _Mix_Music {
53
54
55
56
Mix_MusicInterface *interface;
void *context;
SDL_bool playing;
57
58
59
60
Mix_Fading fading;
int fade_step;
int fade_steps;
int error;
61
62
};
63
64
65
/* Used to calculate fading steps */
static int ms_per_step;
66
67
68
69
/* rcg06042009 report available decoders at runtime. */
static const char **music_decoders = NULL;
static int num_decoders = 0;
70
71
72
/* Semicolon-separated SoundFont paths */
char* soundfont_paths = NULL;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* 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
#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
#ifdef MUSIC_OGG
&Mix_MusicInterface_OGG,
#endif
#ifdef MUSIC_MP3_MPG123
&Mix_MusicInterface_MPG123,
#endif
#ifdef MUSIC_MP3_MAD
&Mix_MusicInterface_MAD,
#endif
#ifdef MUSIC_MP3_SMPEG
&Mix_MusicInterface_SMPEG,
#endif
#ifdef MUSIC_FLAC
&Mix_MusicInterface_FLAC,
#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];
}
124
int Mix_GetNumMusicDecoders(void)
126
return(num_decoders);
127
128
129
130
}
const char *Mix_GetMusicDecoder(int index)
{
131
132
133
134
if ((index < 0) || (index >= num_decoders)) {
return NULL;
}
return(music_decoders[index]);
135
136
137
138
}
static void add_music_decoder(const char *decoder)
{
139
void *ptr = SDL_realloc((void *)music_decoders, (num_decoders + 1) * sizeof (const char *));
140
141
142
143
144
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
147
/* Local low-level functions prototypes */
148
static void music_internal_initialize_volume(void);
149
150
151
static void music_internal_volume(int volume);
static int music_internal_play(Mix_Music *music, double position);
static int music_internal_position(double position);
152
static SDL_bool music_internal_playing(void);
153
static void music_internal_halt(void);
155
156
157
158
159
160
/* Support for hooking when the music has finished */
static void (*music_finished_hook)(void) = NULL;
void Mix_HookMusicFinished(void (*music_finished)(void))
{
161
Mix_LockAudio();
162
music_finished_hook = music_finished;
163
Mix_UnlockAudio();
167
/* If music isn't playing, halt it if no looping is required, restart it */
168
169
/* otherwise. NOP if the music is playing */
static int music_halt_or_loop(void)
171
172
173
174
175
/* Restart music if it has to loop */
if (!music_internal_playing())
{
/* Native MIDI handles looping internally */
176
if (music_playing->interface->api == MIX_MUSIC_NATIVEMIDI) {
177
178
179
180
181
182
183
music_loops = 0;
}
/* Restart music if it has to loop at a high level */
if (music_loops)
{
Mix_Fading current_fade;
184
185
186
if (music_loops > 0) {
--music_loops;
}
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
current_fade = music_playing->fading;
music_internal_play(music_playing, 0.0);
music_playing->fading = current_fade;
}
else
{
music_internal_halt();
if (music_finished_hook)
music_finished_hook();
return 0;
}
}
return 1;
202
203
204
}
205
206
207
/* Mixing function */
void music_mixer(void *udata, Uint8 *stream, int len)
{
208
if (music_playing && music_active) {
209
/* Handle fading */
210
211
if (music_playing->fading != MIX_NO_FADING) {
if (music_playing->fade_step++ < music_playing->fade_steps) {
212
213
214
215
int volume;
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
216
if (music_playing->fading == MIX_FADING_OUT) {
217
218
219
220
221
222
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
} else { /* Fading in */
volume = (music_volume * fade_step) / fade_steps;
}
music_internal_volume(volume);
} else {
223
if (music_playing->fading == MIX_FADING_OUT) {
224
music_internal_halt();
225
if (music_finished_hook) {
226
227
228
229
230
231
232
233
234
music_finished_hook();
}
return;
}
music_playing->fading = MIX_NO_FADING;
}
}
music_halt_or_loop();
235
if (!music_internal_playing()) {
239
240
241
242
243
if (music_playing->interface->GetAudio) {
int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
if (left > 0) {
music_playing->playing = SDL_FALSE;
}
245
246
247
248
249
250
251
/* Handle seamless music looping */
if (left > 0 && left < len) {
music_halt_or_loop();
if (music_internal_playing()) {
music_mixer(udata, stream+(len-left), left);
}
}
254
255
}
256
257
/* Load the music interface libraries */
int load_music(void)
258
{
259
char hint[128];
261
262
263
264
265
266
int i;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (interface->loaded) {
continue;
}
268
269
270
271
SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
continue;
}
273
274
275
276
277
if (!interface->Load || interface->Load() == 0) {
interface->loaded = SDL_TRUE;
}
}
return 0;
278
279
}
280
281
/* Return SDL_TRUE if the music type is available */
SDL_bool has_music(Mix_MusicType type)
283
284
285
286
287
288
289
290
291
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;
}
293
return SDL_FALSE;
296
297
/* Initialize the music interfaces with a certain desired audio format */
int open_music(const SDL_AudioSpec *spec)
299
300
int i;
SDL_bool use_native_midi = SDL_FALSE;
302
#ifdef MUSIC_MID_NATIVE
303
304
if (SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
use_native_midi = SDL_TRUE;
308
309
310
311
312
313
music_spec = *spec;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->loaded) {
continue;
}
315
316
317
318
319
320
321
322
if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
continue;
}
if (!interface->Open || interface->Open(spec) == 0) {
interface->opened = SDL_TRUE;
add_music_decoder(interface->tag);
}
325
326
327
328
329
330
331
332
if (has_music(MUS_MOD)) {
add_music_decoder("MOD");
}
if (has_music(MUS_MID)) {
add_music_decoder("MIDI");
}
if (has_music(MUS_MP3)) {
add_music_decoder("MP3");
335
336
337
338
339
340
341
342
343
344
Mix_VolumeMusic(MIX_MAX_VOLUME);
/* Calculate the number of ms for each callback */
ms_per_step = (int) (((float)spec->samples * 1000.0) / spec->freq);
return 0;
}
Mix_MusicType detect_music_type_from_magic(const Uint8 *magic)
{
345
/* Ogg Vorbis files have the magic four bytes "OggS" */
346
if (SDL_memcmp(magic, "OggS", 4) == 0) {
347
348
349
350
return MUS_OGG;
}
/* FLAC files have the magic four bytes "fLaC" */
351
if (SDL_memcmp(magic, "fLaC", 4) == 0) {
352
353
354
355
return MUS_FLAC;
}
/* MIDI files have the magic four bytes "MThd" */
356
if (SDL_memcmp(magic, "MThd", 4) == 0) {
357
358
359
return MUS_MID;
}
360
361
if (SDL_memcmp(magic, "ID3", 3) == 0 ||
(magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
362
363
364
365
366
367
368
369
370
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;
373
374
static Mix_MusicType detect_music_type(SDL_RWops *src)
{
375
Uint8 magic[12];
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
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;
}
return detect_music_type_from_magic(magic);
}
393
394
395
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
396
397
398
int i;
void *context;
char *ext;
399
Mix_MusicType type;
400
401
402
403
404
405
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;
407
408
409
410
411
412
413
414
415
416
417
418
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;
422
src = SDL_RWFromFile(file, "rb");
423
if (src == NULL) {
424
425
426
427
428
429
430
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, '.');
432
++ext; /* skip the dot in the extension */
433
if (SDL_strcasecmp(ext, "WAV") == 0) {
434
type = MUS_WAV;
435
436
437
} else if (SDL_strcasecmp(ext, "MID") == 0 ||
SDL_strcasecmp(ext, "MIDI") == 0 ||
SDL_strcasecmp(ext, "KAR") == 0) {
438
type = MUS_MID;
439
} else if (SDL_strcasecmp(ext, "OGG") == 0) {
440
type = MUS_OGG;
441
} else if (SDL_strcasecmp(ext, "FLAC") == 0) {
442
type = MUS_FLAC;
443
444
445
446
} else if (SDL_strcasecmp(ext, "MPG") == 0 ||
SDL_strcasecmp(ext, "MPEG") == 0 ||
SDL_strcasecmp(ext, "MP3") == 0 ||
SDL_strcasecmp(ext, "MAD") == 0) {
447
type = MUS_MP3;
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
} 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;
472
return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
475
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
477
return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
480
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
482
483
int i;
void *context;
487
488
489
Mix_SetError("RWops pointer is NULL");
return NULL;
}
490
start = SDL_RWtell(src);
491
492
493
494
/* If the caller wants auto-detection, figure out what kind of file
* this is. */
if (type == MUS_NONE) {
495
if ((type = detect_music_type(src)) == MUS_NONE) {
496
/* Don't call Mix_SetError() since detect_music_type() does that. */
497
498
499
if (freesrc) {
SDL_RWclose(src);
}
500
501
502
503
return NULL;
}
}
504
Mix_ClearError();
506
507
508
509
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;
510
}
511
512
513
514
515
516
517
518
519
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;
521
522
523
music->interface = interface;
music->context = context;
return music;
525
526
527
528
if (interface->api == MIX_MUSIC_SMPEG) {
/* Uh oh, if SMPEG couldn't create a context, it freed the src */
freesrc = SDL_FALSE;
532
533
534
/* Reset the stream for the next decoder */
SDL_RWseek(src, start, RW_SEEK_SET);
}
536
537
if (!*Mix_GetError()) {
Mix_SetError("Unrecognized audio format");
539
540
541
542
543
544
if (freesrc) {
SDL_RWclose(src);
} else {
SDL_RWseek(src, start, RW_SEEK_SET);
}
return NULL;
545
546
547
548
549
}
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
551
/* Stop the music if it's currently playing */
552
Mix_LockAudio();
553
if (music == music_playing) {
554
/* Wait for any fade out to finish */
555
while (music->fading == MIX_FADING_OUT) {
556
Mix_UnlockAudio();
557
SDL_Delay(100);
558
Mix_LockAudio();
560
if (music == music_playing) {
561
562
563
music_internal_halt();
}
}
564
Mix_UnlockAudio();
566
music->interface->Delete(music->context);
567
568
SDL_free(music);
}
569
570
}
571
572
573
574
575
/* 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)
{
576
577
Mix_MusicType type = MUS_NONE;
578
579
if (music) {
type = music->interface->type;
581
Mix_LockAudio();
582
583
if (music_playing) {
type = music_playing->interface->type;
585
Mix_UnlockAudio();
586
587
}
return(type);
590
591
592
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
static int music_internal_play(Mix_Music *music, double position)
593
{
594
int retval = 0;
596
#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
597
598
599
/* This fixes a bug with native MIDI on Mac OS X, where you
can't really stop and restart MIDI from the audio callback.
*/
600
if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
601
602
603
604
605
606
607
/* Just a seek suffices to restart playing */
music_internal_position(position);
return 0;
}
#endif
/* Note the music we're playing */
608
if (music_playing) {
609
610
611
music_internal_halt();
}
music_playing = music;
612
music_playing->playing = SDL_TRUE;
613
614
/* Set the initial volume */
615
music_internal_initialize_volume();
616
617
/* Set up for playback */
618
retval = music->interface->Play(music->context);
620
/* Set the playback position, note any errors if an offset is used */
621
622
623
if (retval == 0) {
if (position > 0.0) {
if (music_internal_position(position) < 0) {
624
625
626
627
628
629
630
631
632
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 */
633
if (retval < 0) {
634
635
636
music_playing = NULL;
}
return(retval);
639
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
641
642
int retval;
643
if (ms_per_step == 0) {
644
645
646
647
648
SDL_SetError("Audio device hasn't been opened");
return(-1);
}
/* Don't play null pointers :-) */
649
if (music == NULL) {
650
651
652
653
654
Mix_SetError("music parameter was NULL");
return(-1);
}
/* Setup the data */
656
657
658
659
660
661
662
663
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 */
664
Mix_LockAudio();
665
/* If the current music is fading out, wait for the fade to complete */
666
while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
667
Mix_UnlockAudio();
668
SDL_Delay(100);
669
Mix_LockAudio();
670
671
672
673
674
675
676
677
}
music_active = 1;
if (loops == 1) {
/* Loop is the number of times to play the audio */
loops = 0;
}
music_loops = loops;
retval = music_internal_play(music, position);
678
Mix_UnlockAudio();
679
680
return(retval);
681
682
683
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
684
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
685
686
687
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
688
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
691
692
/* Set the playing music position */
int music_internal_position(double position)
694
695
if (music_playing->interface->Seek) {
return music_playing->interface->Seek(music_playing->context, position);
699
int Mix_SetMusicPosition(double position)
701
702
int retval;
703
Mix_LockAudio();
704
if (music_playing) {
705
retval = music_internal_position(position);
706
if (retval < 0) {
707
708
709
710
711
712
Mix_SetError("Position not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
713
Mix_UnlockAudio();
714
715
return(retval);
718
719
720
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
721
if (music_playing->fading == MIX_FADING_IN) {
722
723
724
725
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
728
/* Set the music volume */
729
static void music_internal_volume(int volume)
730
{
731
732
if (music_playing->interface->SetVolume) {
music_playing->interface->SetVolume(music_playing->context, volume);
734
735
736
}
int Mix_VolumeMusic(int volume)
{
737
738
739
int prev_volume;
prev_volume = music_volume;
740
if (volume < 0) {
741
742
return prev_volume;
}
743
if (volume > SDL_MIX_MAXVOLUME) {
744
745
746
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
747
Mix_LockAudio();
748
if (music_playing) {
749
750
music_internal_volume(music_volume);
}
751
Mix_UnlockAudio();
752
return(prev_volume);
753
754
}
755
756
/* Halt playing of music */
static void music_internal_halt(void)
757
{
758
759
if (music_playing->interface->Stop) {
music_playing->interface->Stop(music_playing->context);
762
music_playing->playing = SDL_FALSE;
763
764
music_playing->fading = MIX_NO_FADING;
music_playing = NULL;
765
766
767
}
int Mix_HaltMusic(void)
{
768
Mix_LockAudio();
769
if (music_playing) {
770
music_internal_halt();
771
if (music_finished_hook) {
772
773
774
music_finished_hook();
}
}
775
Mix_UnlockAudio();
776
777
return(0);
778
779
}
780
781
782
/* Progressively stop the music */
int Mix_FadeOutMusic(int ms)
{
783
int retval = 0;
785
if (ms_per_step == 0) {
786
787
788
SDL_SetError("Audio device hasn't been opened");
return 0;
}
790
791
792
793
if (ms <= 0) { /* just halt immediately. */
Mix_HaltMusic();
return 1;
}
795
Mix_LockAudio();
796
797
798
799
800
801
802
803
804
805
806
807
808
809
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;
}
810
811
812
813
music_playing->fading = MIX_FADING_OUT;
music_playing->fade_steps = fade_steps;
retval = 1;
}
814
Mix_UnlockAudio();
816
return(retval);
817
818
819
820
}
Mix_Fading Mix_FadingMusic(void)
{
821
Mix_Fading fading = MIX_NO_FADING;
823
Mix_LockAudio();
824
if (music_playing) {
825
826
fading = music_playing->fading;
}
827
Mix_UnlockAudio();
829
return(fading);
832
833
834
/* Pause/Resume the music stream */
void Mix_PauseMusic(void)
{
835
836
837
838
Mix_LockAudio();
if (music_playing && music_playing->interface->Pause) {
music_playing->interface->Pause(music_playing->context);
}
839
music_active = 0;
840
Mix_UnlockAudio();
841
}
843
844
void Mix_ResumeMusic(void)
{
845
Mix_LockAudio();
846
music_active = 1;
847
848
849
850
if (music_playing && music_playing->interface->Resume) {
music_playing->interface->Resume(music_playing->context);
}
Mix_UnlockAudio();
851
852
853
854
}
void Mix_RewindMusic(void)
{
855
Mix_SetMusicPosition(0.0);
856
857
}
858
859
int Mix_PausedMusic(void)
{
860
return (music_active == 0);
863
/* Check the status of the music */
864
static SDL_bool music_internal_playing(void)
865
{
866
if (music_playing == NULL) {
867
return SDL_FALSE;
870
871
if (music_playing->interface->IsPlaying) {
return music_playing->interface->IsPlaying(music_playing->context);
873
return music_playing->playing;
874
875
876
}
int Mix_PlayingMusic(void)
{
877
int playing = 0;
879
Mix_LockAudio();
880
if (music_playing) {
881
882
playing = music_loops || music_internal_playing();
}
883
Mix_UnlockAudio();
885
return(playing);
886
887
888
889
890
}
/* Set the external music playback command */
int Mix_SetMusicCMD(const char *command)
{
891
Mix_HaltMusic();
892
if (music_cmd) {
893
894
895
SDL_free(music_cmd);
music_cmd = NULL;
}
896
897
898
899
900
if (command) {
size_t length = SDL_strlen(command) + 1;
music_cmd = (char *)SDL_malloc(length);
if (music_cmd == NULL) {
return SDL_OutOfMemory();
902
SDL_memcpy(music_cmd, command, length);
905
906
}
907
908
int Mix_SetSynchroValue(int i)
{
909
910
/* Not supported by any players at this time */
return(-1);
911
912
913
914
}
int Mix_GetSynchroValue(void)
{
915
916
/* Not supported by any players at this time */
return(-1);
920
/* Uninitialize the music interfaces */
921
922
void close_music(void)
{
925
Mix_HaltMusic();
926
927
928
929
930
931
932
933
934
935
936
937
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface || !interface->opened) {
continue;
}
if (interface->Close) {
interface->Close();
}
interface->opened = SDL_FALSE;
}
939
/* rcg06042009 report available decoders at runtime. */
940
SDL_free((void *)music_decoders);
941
942
music_decoders = NULL;
num_decoders = 0;
944
ms_per_step = 0;
945
946
}
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
/* Unload the music interface libraries */
void unload_music(void)
{
int i;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface || !interface->loaded) {
continue;
}
if (interface->Unload) {
interface->Unload();
}
interface->loaded = SDL_FALSE;
}
}
964
965
int Mix_SetSoundFonts(const char *paths)
{
966
967
968
969
970
971
972
973
974
975
976
977
if (soundfont_paths) {
SDL_free(soundfont_paths);
soundfont_paths = NULL;
}
if (paths) {
if (!(soundfont_paths = SDL_strdup(paths))) {
Mix_SetError("Insufficient memory to set SoundFonts");
return 0;
}
}
return 1;
980
const char* Mix_GetSoundFonts(void)
982
983
if (!soundfont_paths || SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE)) {
return SDL_getenv("SDL_SOUNDFONTS");
984
985
986
} else {
return soundfont_paths;
}
987
988
989
990
}
int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
{
991
992
char *context, *path, *paths;
const char* cpaths = Mix_GetSoundFonts();
993
int soundfonts_found = 0;
995
996
997
998
if (!cpaths) {
Mix_SetError("No SoundFonts have been requested");
return 0;
}
1000
if (!(paths = SDL_strdup(cpaths))) {