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