fix sound destruction

This commit is contained in:
2025-07-18 14:20:33 -05:00
parent f49d4180ed
commit 7fb0d9e80a
2 changed files with 54 additions and 53 deletions

View File

@@ -1,48 +1,45 @@
var soloud = use('soloud') var soloud = use('soloud')
var tween = use('tween') var tween = use('tween')
var io = use('io') var io = use('io')
var res = use('resources') var res = use('resources')
var doc = use('doc') var doc = use('doc')
soloud.init(); soloud.init()
var audio = {}; var audio = {}
audio[doc.sym] = `Audio docs.` var pcms = {}
var pcms = {}; // keep every live voice here so GC cant collect it prematurely
var voices = []
audio.pcm = function pcm(file) // load-and-cache WAVs
{ audio.pcm = function pcm(file) {
file = res.find_sound(file); file = res.find_sound(file); if (!file) return
if (!file) return//throw new Error(`Could not findfile ${file}`); if (pcms[file]) return pcms[file]
if (pcms[file]) return pcms[file]; var buf = io.slurpbytes(file)
var bytes = io.slurpbytes(file) return pcms[file] = soloud.load_wav_mem(buf)
var newpcm = soloud.load_wav_mem(io.slurpbytes(file));
pcms[file] = newpcm;
return newpcm;
} }
function cleanup() {
voices = voices.filter(v => v.is_valid())
}
// play a oneshot; returns the voice for volume/stop control
audio.play = function play(file) { audio.play = function play(file) {
var pcm = audio.pcm(file); var pcm = audio.pcm(file); if (!pcm) return
if (!pcm) return; var voice = soloud.play(pcm)
return soloud.play(pcm); voices.push(voice)
}; return voice
audio.play[doc.sym] = `Given a file path, plays a sound. Returns a sound object.` }
// cry is just a play+stop closure
audio.cry = function cry(file) { audio.cry = function cry(file) {
var voice = audio.play(file); var v = audio.play(file); if (!v) return
if (!voice) return; return function() { v.stop(); v = null }
return function() { }
voice.stop();
voice = null;
}
};
audio.cry[doc.sym] =
`Given a file path, plays a sound. Invoke the returned object to stop it.`
var song; // music with optional crossfade
var song
// Play 'file' for new song, cross fade for seconds
audio.music = function music(file, fade = 0.5) { audio.music = function music(file, fade = 0.5) {
if (!file) { if (!file) {
if (song) song.volume = 0; if (song) song.volume = 0;
@@ -71,33 +68,30 @@ audio.music = function music(file, fade = 0.5) {
// tween.tween(temp2, 'volume', 0, fade); // tween.tween(temp2, 'volume', 0, fade);
song = temp; song = temp;
song.loop = true; song.loop = true;
temp2.stop()
}; };
audio.music[doc.sym] = `Play the given music file, with an optional cross fade. The song will loop. When this is invoked again, the previous music is replaced.`
var ss = use('sdl_audio')
var feeder = ss.open_stream("playback")
feeder.set_format({format:"f32", channels:2,samplerate:44100})
//
// pump + periodic cleanup
//
var ss = use('sdl_audio')
var feeder = ss.open_stream("playback")
feeder.set_format({format:"f32", channels:2, samplerate:44100})
feeder.resume() feeder.resume()
var FRAMES = 1024 var FRAMES = 1024
var CHANNELS = 2 var CHANNELS = 2
var BYTES_PER_F = 4 var BYTES_PER_F = 4
var SAMPLES = FRAMES * CHANNELS var CHUNK_BYTES = FRAMES * CHANNELS * BYTES_PER_F
var CHUNK_BYTES = FRAMES * CHANNELS * BYTES_PER_F
function pump() function pump() {
{
if (feeder.queued() < CHUNK_BYTES*3) { if (feeder.queued() < CHUNK_BYTES*3) {
var mm = soloud.mix(FRAMES) feeder.put(soloud.mix(FRAMES))
feeder.put(mm) cleanup()
} }
$_.delay(pump, 1/240) $_.delay(pump, 1/240)
} }
//pump() pump()
return audio; return audio

View File

@@ -177,6 +177,12 @@ static JSValue js_voice_setInaudibleBehavior(JSContext *js, JSValueConst self, i
return JS_NULL; return JS_NULL;
} }
static JSValue js_voice_valid(JSContext *js, JSValueConst self, int argc, JSValue *argv)
{
unsigned int voice = *js2voice(js, self);
return JS_NewBool(js, Soloud_isValidVoiceHandle(soloud, voice));
}
SOLOUD_GETSET(Volume, number); SOLOUD_GETSET(Volume, number);
SOLOUD_GETSET(Pan, number) SOLOUD_GETSET(Pan, number)
SOLOUD_GETSET(Samplerate, number) SOLOUD_GETSET(Samplerate, number)
@@ -197,6 +203,7 @@ static const JSCFunctionListEntry js_voice_funcs[] = {
JS_CGETSET_DEF("loop", js_voice_get_Looping, js_voice_set_Looping), JS_CGETSET_DEF("loop", js_voice_get_Looping, js_voice_set_Looping),
JS_CGETSET_DEF("autoStop", js_voice_get_AutoStop, js_voice_set_AutoStop), JS_CGETSET_DEF("autoStop", js_voice_get_AutoStop, js_voice_set_AutoStop),
JS_CGETSET_DEF("protect", js_voice_get_ProtectVoice, js_voice_set_ProtectVoice), JS_CGETSET_DEF("protect", js_voice_get_ProtectVoice, js_voice_set_ProtectVoice),
JS_CFUNC_DEF("is_valid", 0, js_voice_valid),
}; };
static const JSCFunctionListEntry *js_Bus_funcs; static const JSCFunctionListEntry *js_Bus_funcs;