AtlatestRepositorysigil-audio
sigil-audio / tree / src / caudio.c
1
/*2
* audio.c - Sigil Audio Module3
*4
* Audio playback: a mixer of loaded sounds and one streamed music track over5
* the playback device in miniaudio-impl.c (miniaudio).6
* Uses stb_vorbis for OGG decoding.7
*8
* Sound effects are loaded entirely into memory.9
* Music is streamed from disk via stb_vorbis.10
*/12
#include "sigil/sigil.h"14
#include <stdio.h>15
#include <stdlib.h>16
#include <string.h>17
#include <math.h>19
/* The playback device (miniaudio, in miniaudio-impl.c) */20
#include "audio-device.h"22
/* stb_vorbis for OGG decoding (implementation in stb_impl.c) */23
#include "stb_vorbis.c"25
/* Streaming audio sink (SPSC ring) */26
#include "audio-stream.h"28
/* ============================================================29
* CONSTANTS30
* ============================================================ */32
#define MAX_SOUNDS 6433
#define MAX_PLAYING_SOUNDS 1634
#define STREAM_BUFFER_SAMPLES 409636
/* ============================================================37
* DATA STRUCTURES38
* ============================================================ */40
/* Sound effect - fully loaded into memory */41
typedef struct {42
float *samples; /* Interleaved stereo samples */43
int num_samples; /* Total samples (frames * channels) */44
int sample_rate;45
int channels;46
} StudioSound;48
/* Playing sound instance */49
typedef struct {50
StudioSound *sound;51
int position; /* Current playback position */52
float volume;53
float pan; /* -1.0 left, 0.0 center, 1.0 right */54
bool playing;55
bool loop;56
} PlayingSound;58
/* Music stream - decoded on the fly */59
typedef struct {60
stb_vorbis *vorbis;61
char *filepath; /* For reopening if looping */62
float volume;63
bool playing;64
bool loop;65
bool paused;66
} MusicStream;68
/* ============================================================69
* GLOBAL STATE70
* ============================================================ */72
static PlayingSound g_playing_sounds[MAX_PLAYING_SOUNDS];73
static MusicStream g_music = {0};74
static float g_master_volume = 1.0f;75
static float g_sounds_volume = 1.0f; /* the sounds' own gain (cues), under the master */76
static bool g_muted = false;77
static bool g_audio_initialized = false;79
/* Type tags for foreign objects */80
static Value sound_type_tag = SIGIL_UNDEFINED;82
/* ============================================================83
* AUDIO CALLBACK84
* ============================================================ */86
static void audio_callback(float *buffer, int num_frames, int num_channels)87
{88
/* Clear buffer */89
memset(buffer, 0, num_frames * num_channels * sizeof(float));91
if (g_muted) return;93
float master = g_master_volume;95
/* Mix playing sounds */96
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {97
PlayingSound *ps = &g_playing_sounds[i];98
/* acquire: the slot's fields were written before playing was set */99
if (!__atomic_load_n(&ps->playing, __ATOMIC_ACQUIRE) || !ps->sound) continue;101
StudioSound *snd = ps->sound;102
float vol = ps->volume * master * g_sounds_volume;104
/* Calculate pan gains */105
float pan = ps->pan;106
float left_gain = vol * (pan <= 0 ? 1.0f : 1.0f - pan);107
float right_gain = vol * (pan >= 0 ? 1.0f : 1.0f + pan);109
for (int f = 0; f < num_frames; f++) {110
if (ps->position >= snd->num_samples / snd->channels) {111
if (ps->loop) {112
ps->position = 0;113
} else {114
ps->playing = false;115
break;116
}117
}119
float left, right;120
if (snd->channels == 1) {121
/* Mono */122
left = right = snd->samples[ps->position];123
} else {124
/* Stereo */125
left = snd->samples[ps->position * 2];126
right = snd->samples[ps->position * 2 + 1];127
}129
if (num_channels >= 2) {130
buffer[f * num_channels] += left * left_gain;131
buffer[f * num_channels + 1] += right * right_gain;132
} else {133
buffer[f] += (left + right) * 0.5f * vol;134
}136
ps->position++;137
}138
}140
/* Mix music stream */141
if (g_music.playing && !g_music.paused && g_music.vorbis) {142
float vol = g_music.volume * master;143
float temp[STREAM_BUFFER_SAMPLES * 2];144
int samples_needed = num_frames;145
int offset = 0;147
while (samples_needed > 0) {148
int to_decode = samples_needed < STREAM_BUFFER_SAMPLES ?149
samples_needed : STREAM_BUFFER_SAMPLES;151
int decoded = stb_vorbis_get_samples_float_interleaved(152
g_music.vorbis, 2, temp, to_decode * 2);154
if (decoded == 0) {155
/* End of file */156
if (g_music.loop && g_music.filepath) {157
/* Reopen and continue */158
stb_vorbis_close(g_music.vorbis);159
int error;160
g_music.vorbis = stb_vorbis_open_filename(161
g_music.filepath, &error, NULL);162
if (!g_music.vorbis) {163
g_music.playing = false;164
break;165
}166
continue;167
} else {168
g_music.playing = false;169
break;170
}171
}173
/* Mix decoded samples */174
for (int f = 0; f < decoded; f++) {175
int buf_idx = (offset + f) * num_channels;176
if (num_channels >= 2) {177
buffer[buf_idx] += temp[f * 2] * vol;178
buffer[buf_idx + 1] += temp[f * 2 + 1] * vol;179
} else {180
buffer[buf_idx] += (temp[f * 2] + temp[f * 2 + 1]) * 0.5f * vol;181
}182
}184
samples_needed -= decoded;185
offset += decoded;186
}187
}189
/* Mix streaming sinks (SPSC ring sources). Additive, silence on under-run. */190
sigil_audio_stream_mix_all(buffer, num_frames, num_channels);192
/* Clamp output */193
for (int i = 0; i < num_frames * num_channels; i++) {194
if (buffer[i] > 1.0f) buffer[i] = 1.0f;195
if (buffer[i] < -1.0f) buffer[i] = -1.0f;196
}197
}199
/* ============================================================200
* HELPER FUNCTIONS201
* ============================================================ */203
static void ensure_sound_type(SigilVM *vm)204
{205
if (sigil_is_undefined(sound_type_tag)) {206
sound_type_tag = sigil_intern_symbol(vm, "sigil-audio-sound", 17);207
}208
}210
static StudioSound *get_sound(SigilVM *vm, Value v)211
{212
if (!sigil_is_foreign(v)) return NULL;213
ensure_sound_type(vm);214
if (sigil_foreign_type(v) != sound_type_tag) return NULL;215
return (StudioSound *)sigil_foreign_data(v);216
}218
static void sound_destructor(void *data)219
{220
StudioSound *snd = (StudioSound *)data;221
if (snd) {222
free(snd->samples);223
free(snd);224
}225
}227
static PlayingSound *find_free_slot(void)228
{229
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {230
if (!g_playing_sounds[i].playing) {231
return &g_playing_sounds[i];232
}233
}234
return NULL;235
}237
/* ============================================================238
* NATIVE FUNCTIONS - SETUP239
* ============================================================ */241
/*242
* (audio-setup) - Initialize audio subsystem243
*/244
static Value native_audio_setup(SigilVM *vm, int argc, Value *args)245
{246
(void)vm; (void)argc; (void)args;248
if (g_audio_initialized) {249
return SIGIL_NIL;250
}252
/* No device (a headless runner, no sound server, no ALSA card) is not253
* an error, as it was not under sokol_audio: the mixer runs with no254
* output, every play is a no-op, and (audio-initialized?) is still255
* #t. miniaudio-impl.c has already said why on stderr. */256
if (sigil_audio_device_open(SIGIL_AUDIO_DEVICE_RATE, 2, 2048, audio_callback) != 0) {257
fprintf(stderr, "sigil-audio: continuing without an audio device\n");258
}260
/* Clear playing sounds */261
memset(g_playing_sounds, 0, sizeof(g_playing_sounds));263
/* Clear music */264
memset(&g_music, 0, sizeof(g_music));265
g_music.volume = 1.0f;267
g_master_volume = 1.0f;268
g_muted = false;269
g_audio_initialized = true;271
return SIGIL_NIL;272
}274
/*275
* (audio-shutdown) - Shutdown audio subsystem276
*/277
static Value native_audio_shutdown(SigilVM *vm, int argc, Value *args)278
{279
(void)vm; (void)argc; (void)args;281
if (g_audio_initialized) {282
/* Detach any active streaming sinks before tearing down the device */283
sigil_audio_stream_shutdown_all();285
/* Stop music */286
if (g_music.vorbis) {287
stb_vorbis_close(g_music.vorbis);288
g_music.vorbis = NULL;289
}290
free(g_music.filepath);291
g_music.filepath = NULL;293
sigil_audio_device_close();294
g_audio_initialized = false;295
}297
return SIGIL_NIL;298
}300
/*301
* (audio-initialized?) -> boolean302
*/303
static Value native_audio_initialized(SigilVM *vm, int argc, Value *args)304
{305
(void)vm; (void)argc; (void)args;306
return g_audio_initialized ? SIGIL_TRUE : SIGIL_FALSE;307
}309
/*310
* (audio-backend) -> symbol or #f311
*312
* The backend the device runs on: 'pulseaudio (also on a PipeWire desktop,313
* through pipewire-pulse), 'alsa, 'jack, 'wasapi, 'dsound, 'winmm,314
* 'coreaudio, or 'null when no backend library or server was usable and315
* frames are consumed in silence; #f before audio-setup.316
*/317
static Value native_audio_backend(SigilVM *vm, int argc, Value *args)318
{319
(void)argc; (void)args;320
const char *name = sigil_audio_device_backend_symbol();321
if (!name) return SIGIL_FALSE;322
return sigil_intern_symbol(vm, name, strlen(name));323
}325
/*326
* (audio-device?) -> boolean327
*328
* #t when sound can reach a listener: a device is open on a real backend.329
* (audio-initialized?) stays #t after audio-setup whatever the backend,330
* because the mixer and the streams work either way (as under sokol_audio,331
* where an invalid device was silent but initialized); this predicate332
* names the new fact a game may want: whether to bother with sound.333
*/334
static Value native_audio_device(SigilVM *vm, int argc, Value *args)335
{336
(void)vm; (void)argc; (void)args;337
return sigil_audio_device_real() ? SIGIL_TRUE : SIGIL_FALSE;338
}340
/* ============================================================341
* NATIVE FUNCTIONS - SOUNDS342
* ============================================================ */344
/*345
* (load-sound path) -> <sound> or #f346
*347
* Load an OGG file entirely into memory.348
*/349
static Value native_load_sound(SigilVM *vm, int argc, Value *args)350
{351
if (argc < 1 || !sigil_is_string(args[0])) {352
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "load-sound: expected string path");353
return SIGIL_FALSE;354
}356
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);357
const char *path = path_str->data;359
int channels, sample_rate;360
short *raw_samples;361
int num_samples = stb_vorbis_decode_filename(path, &channels, &sample_rate,362
&raw_samples);363
if (num_samples < 0) {364
return SIGIL_FALSE;365
}367
/* Convert to float */368
int total_samples = num_samples * channels;369
float *samples = malloc(total_samples * sizeof(float));370
if (!samples) {371
free(raw_samples);372
return SIGIL_FALSE;373
}375
for (int i = 0; i < total_samples; i++) {376
samples[i] = raw_samples[i] / 32768.0f;377
}378
free(raw_samples);380
StudioSound *snd = malloc(sizeof(StudioSound));381
if (!snd) {382
free(samples);383
return SIGIL_FALSE;384
}386
snd->samples = samples;387
snd->num_samples = total_samples;388
snd->sample_rate = sample_rate;389
snd->channels = channels;391
ensure_sound_type(vm);392
return sigil_make_foreign(vm, sound_type_tag, snd, sound_destructor,393
sizeof(StudioSound) + total_samples * sizeof(float));394
}396
/*397
* (sound? obj) -> boolean398
*/399
static Value native_sound_p(SigilVM *vm, int argc, Value *args)400
{401
(void)argc;402
return get_sound(vm, args[0]) ? SIGIL_TRUE : SIGIL_FALSE;403
}405
/*406
* (play-sound sound [volume] [pan] [loop?]) -> boolean407
*408
* Play a sound effect. Returns #t if started, #f if no slots available.409
*/410
static Value native_play_sound(SigilVM *vm, int argc, Value *args)411
{412
if (argc < 1) {413
sigil__vm_set_error(vm, SIGIL_ERR_ARITY, "play-sound: requires sound argument");414
return SIGIL_FALSE;415
}417
StudioSound *snd = get_sound(vm, args[0]);418
if (!snd) {419
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "play-sound: expected sound");420
return SIGIL_FALSE;421
}423
PlayingSound *ps = find_free_slot();424
if (!ps) {425
return SIGIL_FALSE; /* No slots available */426
}428
ps->sound = snd;429
ps->position = 0;430
ps->volume = argc > 1 ? (float)sigil_as_flonum(args[1]) : 1.0f;431
ps->pan = argc > 2 ? (float)sigil_as_flonum(args[2]) : 0.0f;432
ps->loop = argc > 3 ? sigil_is_true(args[3]) : false;433
/* release: the audio thread sees the fields above once it sees playing */434
__atomic_store_n(&ps->playing, true, __ATOMIC_RELEASE);436
return SIGIL_TRUE;437
}439
/*440
* (%sound-from-buffer bv channels) -> sound | #f441
*442
* A sound from interleaved float32 PCM in memory (channels 1 or 2) at the443
* device's rate, copied: the cues of (sigil audio sink) on native. play-sound444
* mixes it in the device callback, so it is heard one device period after445
* the call, whatever any stream's ring holds.446
*/447
static Value native_sound_from_buffer(SigilVM *vm, int argc, Value *args)448
{449
if (argc < 2 || !sigil_is_bytevector(args[0]) || !sigil_is_fixnum(args[1])) {450
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "%sound-from-buffer: bytevector channels");451
return SIGIL_FALSE;452
}453
int channels = sigil_as_fixnum(args[1]) == 1 ? 1 : 2;454
size_t bytes = sigil_bytevector_length(args[0]);455
int frames = (int)(bytes / (sizeof(float) * (size_t)channels));456
if (frames <= 0) return SIGIL_FALSE;457
int total = frames * channels;458
float *samples = malloc((size_t)total * sizeof(float));459
if (!samples) return SIGIL_FALSE;460
memcpy(samples, sigil_bytevector_data(args[0]), (size_t)total * sizeof(float));461
StudioSound *snd = malloc(sizeof(StudioSound));462
if (!snd) {463
free(samples);464
return SIGIL_FALSE;465
}466
snd->samples = samples;467
snd->num_samples = total;468
snd->sample_rate = SIGIL_AUDIO_DEVICE_RATE;469
snd->channels = channels;470
ensure_sound_type(vm);471
return sigil_make_foreign(vm, sound_type_tag, snd, sound_destructor,472
sizeof(StudioSound) + (size_t)total * sizeof(float));473
}475
/*476
* (%set-sounds-volume volume) - the gain of every play-sound sound, under477
* the master volume (the cues' volume on native)478
*/479
static Value native_set_sounds_volume(SigilVM *vm, int argc, Value *args)480
{481
(void)vm; (void)argc;482
float v = 1.0f;483
if (sigil_is_flonum(args[0])) v = (float)sigil_as_flonum(args[0]);484
else if (sigil_is_fixnum(args[0])) v = (float)sigil_as_fixnum(args[0]);485
if (v < 0.0f) v = 0.0f;486
if (v > 1.0f) v = 1.0f;487
g_sounds_volume = v;488
return SIGIL_NIL;489
}491
/*492
* (stop-all-sounds) - Stop all playing sound effects493
*/494
static Value native_stop_all_sounds(SigilVM *vm, int argc, Value *args)495
{496
(void)vm; (void)argc; (void)args;498
for (int i = 0; i < MAX_PLAYING_SOUNDS; i++) {499
g_playing_sounds[i].playing = false;500
}502
return SIGIL_NIL;503
}505
/* ============================================================506
* NATIVE FUNCTIONS - MUSIC507
* ============================================================ */509
/*510
* (play-music path [loop?]) -> boolean511
*512
* Start streaming music from an OGG file.513
*/514
static Value native_play_music(SigilVM *vm, int argc, Value *args)515
{516
if (argc < 1 || !sigil_is_string(args[0])) {517
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "play-music: expected string path");518
return SIGIL_FALSE;519
}521
/* Stop any existing music */522
if (g_music.vorbis) {523
stb_vorbis_close(g_music.vorbis);524
g_music.vorbis = NULL;525
}526
free(g_music.filepath);527
g_music.filepath = NULL;529
SigilString *path_str = (SigilString *)sigil_as_ptr(args[0]);530
const char *path = path_str->data;532
int error;533
g_music.vorbis = stb_vorbis_open_filename(path, &error, NULL);534
if (!g_music.vorbis) {535
return SIGIL_FALSE;536
}538
g_music.filepath = strdup(path);539
g_music.loop = argc > 1 ? sigil_is_true(args[1]) : true;540
g_music.playing = true;541
g_music.paused = false;543
return SIGIL_TRUE;544
}546
/*547
* (stop-music) - Stop music playback548
*/549
static Value native_stop_music(SigilVM *vm, int argc, Value *args)550
{551
(void)vm; (void)argc; (void)args;553
if (g_music.vorbis) {554
stb_vorbis_close(g_music.vorbis);555
g_music.vorbis = NULL;556
}557
free(g_music.filepath);558
g_music.filepath = NULL;559
g_music.playing = false;561
return SIGIL_NIL;562
}564
/*565
* (pause-music) - Pause music playback566
*/567
static Value native_pause_music(SigilVM *vm, int argc, Value *args)568
{569
(void)vm; (void)argc; (void)args;570
g_music.paused = true;571
return SIGIL_NIL;572
}574
/*575
* (resume-music) - Resume music playback576
*/577
static Value native_resume_music(SigilVM *vm, int argc, Value *args)578
{579
(void)vm; (void)argc; (void)args;580
g_music.paused = false;581
return SIGIL_NIL;582
}584
/*585
* (music-playing?) -> boolean586
*/587
static Value native_music_playing(SigilVM *vm, int argc, Value *args)588
{589
(void)vm; (void)argc; (void)args;590
return (g_music.playing && !g_music.paused) ? SIGIL_TRUE : SIGIL_FALSE;591
}593
/*594
* (set-music-volume volume) - Set music volume (0.0 to 1.0)595
*/596
static Value native_set_music_volume(SigilVM *vm, int argc, Value *args)597
{598
if (argc < 1) {599
sigil__vm_set_error(vm, SIGIL_ERR_ARITY, "set-music-volume: requires volume");600
return SIGIL_NIL;601
}603
float vol = (float)sigil_as_flonum(args[0]);604
if (vol < 0.0f) vol = 0.0f;605
if (vol > 1.0f) vol = 1.0f;606
g_music.volume = vol;608
return SIGIL_NIL;609
}611
/* ============================================================612
* NATIVE FUNCTIONS - GLOBAL CONTROL613
* ============================================================ */615
/*616
* (set-master-volume volume) - Set master volume (0.0 to 1.0)617
*/618
static Value native_set_master_volume(SigilVM *vm, int argc, Value *args)619
{620
if (argc < 1) {621
sigil__vm_set_error(vm, SIGIL_ERR_ARITY, "set-master-volume: requires volume");622
return SIGIL_NIL;623
}625
float vol = (float)sigil_as_flonum(args[0]);626
if (vol < 0.0f) vol = 0.0f;627
if (vol > 1.0f) vol = 1.0f;628
g_master_volume = vol;630
return SIGIL_NIL;631
}633
/*634
* (mute-audio) - Mute all audio635
*/636
static Value native_mute_audio(SigilVM *vm, int argc, Value *args)637
{638
(void)vm; (void)argc; (void)args;639
g_muted = true;640
return SIGIL_NIL;641
}643
/*644
* (unmute-audio) - Unmute audio645
*/646
static Value native_unmute_audio(SigilVM *vm, int argc, Value *args)647
{648
(void)vm; (void)argc; (void)args;649
g_muted = false;650
return SIGIL_NIL;651
}653
/*654
* (audio-muted?) -> boolean655
*/656
static Value native_audio_muted(SigilVM *vm, int argc, Value *args)657
{658
(void)vm; (void)argc; (void)args;659
return g_muted ? SIGIL_TRUE : SIGIL_FALSE;660
}662
/* ============================================================663
* MODULE INITIALIZATION664
* ============================================================ */666
/* OGG encoding (ogg-encode.c) */667
extern void sigil__register_ogg_encode(SigilVM *vm);669
void sigil__init_sigil_audio_module(SigilVM *vm)670
{671
SigilModule *module = sigil_begin_module(vm, "(sigil audio)");672
if (!module) return;674
/* Setup/shutdown */675
sigil_module_register_native(vm, "audio-setup", native_audio_setup,676
SIGIL_ARITY_EXACT(0), "Initialize audio");677
sigil_module_register_native(vm, "audio-shutdown", native_audio_shutdown,678
SIGIL_ARITY_EXACT(0), "Shutdown audio");679
sigil_module_register_native(vm, "audio-backend", native_audio_backend,680
SIGIL_ARITY_EXACT(0), "The audio backend in use, as a symbol, or #f");681
sigil_module_register_native(vm, "audio-device?", native_audio_device,682
SIGIL_ARITY_EXACT(0), "Is a real (non-null) audio device open?");683
sigil_module_register_native(vm, "audio-initialized?", native_audio_initialized,684
SIGIL_ARITY_EXACT(0), "Is audio initialized?");686
/* Sound effects */687
sigil_module_register_native(vm, "load-sound", native_load_sound,688
SIGIL_ARITY_EXACT(1), "Load OGG sound into memory");689
sigil_module_register_native(vm, "sound?", native_sound_p,690
SIGIL_ARITY_EXACT(1), "Check if object is a sound");691
sigil_module_register_native(vm, "play-sound", native_play_sound,692
SIGIL_ARITY_RANGE(1, 4), "Play sound effect");693
sigil_module_register_native(vm, "stop-all-sounds", native_stop_all_sounds,694
SIGIL_ARITY_EXACT(0), "Stop all sound effects");695
sigil_module_register_native(vm, "%sound-from-buffer", native_sound_from_buffer,696
SIGIL_ARITY_EXACT(2), "A sound from float32 PCM in memory (internal)");697
sigil_module_register_native(vm, "%set-sounds-volume", native_set_sounds_volume,698
SIGIL_ARITY_EXACT(1), "The gain of play-sound sounds (internal)");700
/* Music streaming */701
sigil_module_register_native(vm, "play-music", native_play_music,702
SIGIL_ARITY_RANGE(1, 2), "Stream music from file");703
sigil_module_register_native(vm, "stop-music", native_stop_music,704
SIGIL_ARITY_EXACT(0), "Stop music");705
sigil_module_register_native(vm, "pause-music", native_pause_music,706
SIGIL_ARITY_EXACT(0), "Pause music");707
sigil_module_register_native(vm, "resume-music", native_resume_music,708
SIGIL_ARITY_EXACT(0), "Resume music");709
sigil_module_register_native(vm, "music-playing?", native_music_playing,710
SIGIL_ARITY_EXACT(0), "Is music playing?");711
sigil_module_register_native(vm, "set-music-volume", native_set_music_volume,712
SIGIL_ARITY_EXACT(1), "Set music volume");714
/* Global control */715
sigil_module_register_native(vm, "set-master-volume", native_set_master_volume,716
SIGIL_ARITY_EXACT(1), "Set master volume");717
sigil_module_register_native(vm, "mute-audio", native_mute_audio,718
SIGIL_ARITY_EXACT(0), "Mute all audio");719
sigil_module_register_native(vm, "unmute-audio", native_unmute_audio,720
SIGIL_ARITY_EXACT(0), "Unmute audio");721
sigil_module_register_native(vm, "audio-muted?", native_audio_muted,722
SIGIL_ARITY_EXACT(0), "Is audio muted?");724
/* Export all */725
sigil_module_export(vm, "audio-setup");726
sigil_module_export(vm, "audio-shutdown");727
sigil_module_export(vm, "audio-initialized?");728
sigil_module_export(vm, "audio-backend");729
sigil_module_export(vm, "audio-device?");730
sigil_module_export(vm, "load-sound");731
sigil_module_export(vm, "sound?");732
sigil_module_export(vm, "play-sound");733
sigil_module_export(vm, "stop-all-sounds");734
sigil_module_export(vm, "%sound-from-buffer");735
sigil_module_export(vm, "%set-sounds-volume");736
sigil_module_export(vm, "play-music");737
sigil_module_export(vm, "stop-music");738
sigil_module_export(vm, "pause-music");739
sigil_module_export(vm, "resume-music");740
sigil_module_export(vm, "music-playing?");741
sigil_module_export(vm, "set-music-volume");742
sigil_module_export(vm, "set-master-volume");743
sigil_module_export(vm, "mute-audio");744
sigil_module_export(vm, "unmute-audio");745
sigil_module_export(vm, "audio-muted?");747
/* OGG encoding */748
sigil__register_ogg_encode(vm);750
/* Streaming sink */751
sigil__register_audio_stream(vm);753
sigil_end_module(vm);754
}