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