/
music.c
1058 lines (923 loc) · 27.7 KB
1
/*
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() */
22
23
#include "SDL_hints.h"
24
#include "SDL_timer.h"
25
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"
39
#include "music_mad.h"
40
#include "music_smpeg.h"
41
#include "music_flac.h"
42
#include "native_midi/native_midi.h"
43
45
char *music_cmd = NULL;
46
47
static SDL_bool music_active = SDL_TRUE;
static int music_volume = MIX_MAX_VOLUME;
48
static Mix_Music * volatile music_playing = NULL;
49
SDL_AudioSpec music_spec;
50
51
struct _Mix_Music {
52
53
54
55
Mix_MusicInterface *interface;
void *context;
SDL_bool playing;
56
57
58
Mix_Fading fading;
int fade_step;
int fade_steps;
59
60
};
61
62
63
/* Used to calculate fading steps */
static int ms_per_step;
64
65
66
67
/* rcg06042009 report available decoders at runtime. */
static const char **music_decoders = NULL;
static int num_decoders = 0;
68
/* Semicolon-separated SoundFont paths */
69
static char* soundfont_paths = NULL;
70
71
72
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
/* 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];
}
122
int Mix_GetNumMusicDecoders(void)
123
{
124
return(num_decoders);
125
126
127
128
}
const char *Mix_GetMusicDecoder(int index)
{
129
130
131
132
if ((index < 0) || (index >= num_decoders)) {
return NULL;
}
return(music_decoders[index]);
133
134
135
136
}
static void add_music_decoder(const char *decoder)
{
137
void *ptr = SDL_realloc((void *)music_decoders, (num_decoders + 1) * sizeof (const char *));
138
139
140
141
142
if (ptr == NULL) {
return; /* oh well, go on without it. */
}
music_decoders = (const char **) ptr;
music_decoders[num_decoders++] = decoder;
143
144
}
145
/* Local low-level functions prototypes */
146
static void music_internal_initialize_volume(void);
147
static void music_internal_volume(int volume);
148
static int music_internal_play(Mix_Music *music, int play_count, double position);
149
static int music_internal_position(double position);
150
static SDL_bool music_internal_playing(void);
151
static void music_internal_halt(void);
152
153
154
155
156
157
158
/* Support for hooking when the music has finished */
static void (*music_finished_hook)(void) = NULL;
void Mix_HookMusicFinished(void (*music_finished)(void))
{
159
Mix_LockAudio();
160
music_finished_hook = music_finished;
161
Mix_UnlockAudio();
162
163
}
164
165
166
167
168
/* 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))
169
{
170
171
172
173
Uint8 *snd = (Uint8 *)data;
Uint8 *dst;
int len = bytes;
SDL_bool done = SDL_FALSE;
174
175
176
177
178
179
180
181
182
183
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;
184
185
}
186
187
188
189
190
if (volume == MIX_MAX_VOLUME) {
dst += consumed;
} else {
SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
snd += consumed;
191
}
192
len -= consumed;
193
}
194
195
196
197
if (volume != MIX_MAX_VOLUME) {
SDL_stack_free(dst);
}
return len;
198
199
}
200
201
202
/* Mixing function */
void music_mixer(void *udata, Uint8 *stream, int len)
{
203
while (music_playing && music_active && len > 0) {
204
/* Handle fading */
205
206
if (music_playing->fading != MIX_NO_FADING) {
if (music_playing->fade_step++ < music_playing->fade_steps) {
207
208
209
210
int volume;
int fade_step = music_playing->fade_step;
int fade_steps = music_playing->fade_steps;
211
if (music_playing->fading == MIX_FADING_OUT) {
212
213
214
215
216
217
volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
} else { /* Fading in */
volume = (music_volume * fade_step) / fade_steps;
}
music_internal_volume(volume);
} else {
218
if (music_playing->fading == MIX_FADING_OUT) {
219
music_internal_halt();
220
if (music_finished_hook) {
221
222
223
224
225
226
227
228
music_finished_hook();
}
return;
}
music_playing->fading = MIX_NO_FADING;
}
}
229
230
if (music_playing->interface->GetAudio) {
int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
231
232
if (left != 0) {
/* Either an error or finished playing with data left */
233
234
music_playing->playing = SDL_FALSE;
}
235
236
237
238
239
240
241
242
243
if (left > 0) {
stream += (len - left);
len = left;
} else {
len = 0;
}
} else {
len = 0;
}
244
245
246
247
248
if (!music_internal_playing()) {
music_internal_halt();
if (music_finished_hook) {
music_finished_hook();
249
}
250
251
}
}
252
253
}
254
255
/* Load the music interface libraries */
int load_music(void)
256
{
257
char hint[128];
258
259
260
261
262
263
264
int i;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (interface->loaded) {
continue;
}
265
266
267
268
269
SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
continue;
}
270
271
272
273
274
275
if (!interface->Load || interface->Load() == 0) {
interface->loaded = SDL_TRUE;
}
}
return 0;
276
277
}
278
279
/* Return SDL_TRUE if the music type is available */
SDL_bool has_music(Mix_MusicType type)
280
{
281
282
283
284
285
286
287
288
289
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;
}
290
}
291
return SDL_FALSE;
292
293
}
294
295
/* Initialize the music interfaces with a certain desired audio format */
int open_music(const SDL_AudioSpec *spec)
296
{
297
298
int i;
SDL_bool use_native_midi = SDL_FALSE;
299
300
301
302
303
304
305
306
#ifdef MIX_INIT_SOUNDFONT_PATHS
if (!soundfont_paths) {
soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
}
#endif
307
#ifdef MUSIC_MID_NATIVE
308
309
if (SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
use_native_midi = SDL_TRUE;
310
}
311
#endif
312
313
314
315
316
317
318
music_spec = *spec;
for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
Mix_MusicInterface *interface = s_music_interfaces[i];
if (!interface->loaded) {
continue;
}
319
320
321
322
323
324
325
326
327
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);
}
328
329
}
330
331
332
333
334
335
336
337
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");
338
339
}
340
341
342
343
344
345
346
347
348
349
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)
{
350
/* Ogg Vorbis files have the magic four bytes "OggS" */
351
if (SDL_memcmp(magic, "OggS", 4) == 0) {
352
353
354
355
return MUS_OGG;
}
/* FLAC files have the magic four bytes "fLaC" */
356
if (SDL_memcmp(magic, "fLaC", 4) == 0) {
357
358
359
360
return MUS_FLAC;
}
/* MIDI files have the magic four bytes "MThd" */
361
if (SDL_memcmp(magic, "MThd", 4) == 0) {
362
363
364
return MUS_MID;
}
365
366
if (SDL_memcmp(magic, "ID3", 3) == 0 ||
(magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
367
368
369
370
371
372
373
374
375
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;
376
377
}
378
379
static Mix_MusicType detect_music_type(SDL_RWops *src)
{
380
Uint8 magic[12];
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
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);
}
398
399
400
/* Load a music file */
Mix_Music *Mix_LoadMUS(const char *file)
{
401
402
403
int i;
void *context;
char *ext;
404
Mix_MusicType type;
405
406
407
408
409
410
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;
411
}
412
413
414
415
416
417
418
419
420
421
422
423
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;
424
425
426
}
}
427
src = SDL_RWFromFile(file, "rb");
428
if (src == NULL) {
429
430
431
432
433
434
435
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, '.');
436
if (ext) {
437
++ext; /* skip the dot in the extension */
438
if (SDL_strcasecmp(ext, "WAV") == 0) {
439
type = MUS_WAV;
440
441
442
} else if (SDL_strcasecmp(ext, "MID") == 0 ||
SDL_strcasecmp(ext, "MIDI") == 0 ||
SDL_strcasecmp(ext, "KAR") == 0) {
443
type = MUS_MID;
444
} else if (SDL_strcasecmp(ext, "OGG") == 0) {
445
type = MUS_OGG;
446
} else if (SDL_strcasecmp(ext, "FLAC") == 0) {
447
type = MUS_FLAC;
448
449
450
451
} else if (SDL_strcasecmp(ext, "MPG") == 0 ||
SDL_strcasecmp(ext, "MPEG") == 0 ||
SDL_strcasecmp(ext, "MP3") == 0 ||
SDL_strcasecmp(ext, "MAD") == 0) {
452
type = MUS_MP3;
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
} 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;
475
476
}
}
477
return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
478
479
}
480
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
481
{
482
return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
483
484
}
485
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
486
{
487
488
int i;
void *context;
489
Sint64 start;
490
491
if (!src) {
492
493
494
Mix_SetError("RWops pointer is NULL");
return NULL;
}
495
start = SDL_RWtell(src);
496
497
498
499
/* If the caller wants auto-detection, figure out what kind of file
* this is. */
if (type == MUS_NONE) {
500
if ((type = detect_music_type(src)) == MUS_NONE) {
501
/* Don't call Mix_SetError() since detect_music_type() does that. */
502
503
504
if (freesrc) {
SDL_RWclose(src);
}
505
506
507
508
return NULL;
}
}
509
Mix_ClearError();
510
511
512
513
514
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;
515
}
516
517
518
519
520
521
522
523
524
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;
525
}
526
527
528
music->interface = interface;
music->context = context;
return music;
529
}
530
531
532
533
/* Reset the stream for the next decoder */
SDL_RWseek(src, start, RW_SEEK_SET);
}
534
535
536
if (!*Mix_GetError()) {
Mix_SetError("Unrecognized audio format");
537
}
538
539
540
541
542
543
if (freesrc) {
SDL_RWclose(src);
} else {
SDL_RWseek(src, start, RW_SEEK_SET);
}
return NULL;
544
545
546
547
548
}
/* Free a music chunk previously loaded */
void Mix_FreeMusic(Mix_Music *music)
{
549
if (music) {
550
/* Stop the music if it's currently playing */
551
Mix_LockAudio();
552
if (music == music_playing) {
553
/* Wait for any fade out to finish */
554
while (music->fading == MIX_FADING_OUT) {
555
Mix_UnlockAudio();
556
SDL_Delay(100);
557
Mix_LockAudio();
558
}
559
if (music == music_playing) {
560
561
562
music_internal_halt();
}
}
563
Mix_UnlockAudio();
564
565
music->interface->Delete(music->context);
566
567
SDL_free(music);
}
568
569
}
570
571
572
573
574
/* 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)
{
575
576
Mix_MusicType type = MUS_NONE;
577
578
if (music) {
type = music->interface->type;
579
} else {
580
Mix_LockAudio();
581
582
if (music_playing) {
type = music_playing->interface->type;
583
}
584
Mix_UnlockAudio();
585
586
}
return(type);
587
588
}
589
590
/* Play a music chunk. Returns 0, or -1 if there was an error.
*/
591
static int music_internal_play(Mix_Music *music, int play_count, double position)
592
{
593
int retval = 0;
594
595
#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
596
597
598
/* This fixes a bug with native MIDI on Mac OS X, where you
can't really stop and restart MIDI from the audio callback.
*/
599
if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
600
601
602
603
604
605
606
/* Just a seek suffices to restart playing */
music_internal_position(position);
return 0;
}
#endif
/* Note the music we're playing */
607
if (music_playing) {
608
609
610
music_internal_halt();
}
music_playing = music;
611
music_playing->playing = SDL_TRUE;
612
613
/* Set the initial volume */
614
music_internal_initialize_volume();
615
616
/* Set up for playback */
617
retval = music->interface->Play(music->context, play_count);
618
619
/* Set the playback position, note any errors if an offset is used */
620
621
622
if (retval == 0) {
if (position > 0.0) {
if (music_internal_position(position) < 0) {
623
624
625
626
627
628
629
630
631
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 */
632
if (retval < 0) {
633
music->playing = SDL_FALSE;
634
635
636
music_playing = NULL;
}
return(retval);
637
}
638
639
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
640
{
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 */
655
if (ms) {
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
if (loops == 0) {
672
/* Loop is the number of times to play the audio */
673
loops = 1;
674
}
675
retval = music_internal_play(music, loops, position);
676
Mix_UnlockAudio();
677
678
return(retval);
679
680
681
}
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
{
682
return Mix_FadeInMusicPos(music, loops, ms, 0.0);
683
684
685
}
int Mix_PlayMusic(Mix_Music *music, int loops)
{
686
return Mix_FadeInMusicPos(music, loops, 0, 0.0);
687
688
}
689
690
/* Set the playing music position */
int music_internal_position(double position)
691
{
692
693
if (music_playing->interface->Seek) {
return music_playing->interface->Seek(music_playing->context, position);
694
}
695
return -1;
696
}
697
int Mix_SetMusicPosition(double position)
698
{
699
700
int retval;
701
Mix_LockAudio();
702
if (music_playing) {
703
retval = music_internal_position(position);
704
if (retval < 0) {
705
706
707
708
709
710
Mix_SetError("Position not implemented for music type");
}
} else {
Mix_SetError("Music isn't playing");
retval = -1;
}
711
Mix_UnlockAudio();
712
713
return(retval);
714
715
}
716
717
718
/* Set the music's initial volume */
static void music_internal_initialize_volume(void)
{
719
if (music_playing->fading == MIX_FADING_IN) {
720
721
722
723
music_internal_volume(0);
} else {
music_internal_volume(music_volume);
}
724
725
}
726
/* Set the music volume */
727
static void music_internal_volume(int volume)
728
{
729
730
if (music_playing->interface->SetVolume) {
music_playing->interface->SetVolume(music_playing->context, volume);
731
}
732
733
734
}
int Mix_VolumeMusic(int volume)
{
735
736
737
int prev_volume;
prev_volume = music_volume;
738
if (volume < 0) {
739
740
return prev_volume;
}
741
if (volume > SDL_MIX_MAXVOLUME) {
742
743
744
volume = SDL_MIX_MAXVOLUME;
}
music_volume = volume;
745
Mix_LockAudio();
746
if (music_playing) {
747
748
music_internal_volume(music_volume);
}
749
Mix_UnlockAudio();
750
return(prev_volume);
751
752
}
753
754
/* Halt playing of music */
static void music_internal_halt(void)
755
{
756
757
if (music_playing->interface->Stop) {
music_playing->interface->Stop(music_playing->context);
758
}
759
760
music_playing->playing = SDL_FALSE;
761
762
music_playing->fading = MIX_NO_FADING;
music_playing = NULL;
763
764
765
}
int Mix_HaltMusic(void)
{
766
Mix_LockAudio();
767
if (music_playing) {
768
music_internal_halt();
769
if (music_finished_hook) {
770
771
772
music_finished_hook();
}
}
773
Mix_UnlockAudio();
774
775
return(0);
776
777
}
778
779
780
/* Progressively stop the music */
int Mix_FadeOutMusic(int ms)
{
781
int retval = 0;
782
783
if (ms_per_step == 0) {
784
785
786
SDL_SetError("Audio device hasn't been opened");
return 0;
}
787
788
789
790
791
if (ms <= 0) { /* just halt immediately. */
Mix_HaltMusic();
return 1;
}
792
793
Mix_LockAudio();
794
795
796
797
798
799
800
801
802
803
804
805
806
807
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;
}
808
809
810
811
music_playing->fading = MIX_FADING_OUT;
music_playing->fade_steps = fade_steps;
retval = 1;
}
812
Mix_UnlockAudio();
813
814
return(retval);
815
816
817
818
}
Mix_Fading Mix_FadingMusic(void)
{
819
Mix_Fading fading = MIX_NO_FADING;
820
821
Mix_LockAudio();
822
if (music_playing) {
823
824
fading = music_playing->fading;
}
825
Mix_UnlockAudio();
826
827
return(fading);
828
829
}
830
831
832
/* Pause/Resume the music stream */
void Mix_PauseMusic(void)
{
833
Mix_LockAudio();
834
835
836
837
if (music_playing) {
if (music_playing->interface->Pause) {
music_playing->interface->Pause(music_playing->context);
}
838
}
839
music_active = SDL_FALSE;
840
Mix_UnlockAudio();
841
}
842
843
844
void Mix_ResumeMusic(void)
{
845
Mix_LockAudio();
846
847
848
849
if (music_playing) {
if (music_playing->interface->Resume) {
music_playing->interface->Resume(music_playing->context);
}
850
}
851
music_active = SDL_TRUE;
852
Mix_UnlockAudio();
853
854
855
856
}
void Mix_RewindMusic(void)
{
857
Mix_SetMusicPosition(0.0);
858
859
}
860
861
int Mix_PausedMusic(void)
{
862
return (music_active == SDL_FALSE);
863
864
}
865
/* Check the status of the music */
866
static SDL_bool music_internal_playing(void)
867
{
868
if (!music_playing) {
869
return SDL_FALSE;
870
}
871
872
if (music_playing->interface->IsPlaying) {
873
music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
874
}
875
return music_playing->playing;
876
877
878
}
int Mix_PlayingMusic(void)
{
879
SDL_bool playing;
880
881
Mix_LockAudio();
882
playing = music_internal_playing();
883
Mix_UnlockAudio();
884
885
return playing ? 1 : 0;
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();
901
}
902
SDL_memcpy(music_cmd, command, length);
903
}
904
return 0;
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);
917
918
919
}
920
/* Uninitialize the music interfaces */
921
922
void close_music(void)
{
923
924
int i;
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;
}
938
939
940
941
942
943
if (soundfont_paths) {
SDL_free(soundfont_paths);
soundfont_paths = NULL;
}
944
/* rcg06042009 report available decoders at runtime. */
945
946
947
948
if (music_decoders) {
SDL_free((void *)music_decoders);
music_decoders = NULL;
}
949
num_decoders = 0;
950
951
ms_per_step = 0;
952
953
}
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
/* 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;
}
}
971
972
int Mix_SetSoundFonts(const char *paths)
{
973
974
975
976
977
978
979
980
981
982
983
984
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;
985
986
}
987
const char* Mix_GetSoundFonts(void)
988
{
989
990
991
992
993
994
const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
if (force_env_paths && (!env_paths || !*env_paths)) {
force_env_paths = SDL_FALSE;
}
if (soundfont_paths && *soundfont_paths && !force_env_paths) {
995
996
return soundfont_paths;
}
997
998
999
1000
if (env_paths) {
return env_paths;
}