diff --git a/packages/superdough/nodePools.mjs b/packages/superdough/nodePools.mjs index ae59a2ce9..08ec9ce51 100644 --- a/packages/superdough/nodePools.mjs +++ b/packages/superdough/nodePools.mjs @@ -38,6 +38,10 @@ export const releaseNodeToPool = (node) => { // not reusable return; } + if (node[IS_WORKLET_DEAD]) { + // Worklet already terminated, don't pool it + return; + } // Fallback to a type-based key if the node was not created via getNodeFromPool const key = node[POOL_KEY]; if (key == null) return; diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 87b25ff22..b10136abf 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -181,8 +181,9 @@ export function registerSynthSounds() { } }); o.port.postMessage({ type: 'initialize' }); - o.port.onMessage = (e) => { + o.port.onmessage = (e) => { if (e.data.type === 'died') markWorkletAsDead(o); + o.port.onmessage = null; }; const gainAdjustment = 1 / Math.sqrt(voices); getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend); diff --git a/packages/superdough/wavetable.mjs b/packages/superdough/wavetable.mjs index 9545fa1bb..a74b3747c 100644 --- a/packages/superdough/wavetable.mjs +++ b/packages/superdough/wavetable.mjs @@ -244,8 +244,9 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) { } }); source.port.postMessage({ type: 'initialize', payload }); - source.port.onMessage = (e) => { + source.port.onmessage = (e) => { if (e.data.type === 'died') markWorkletAsDead(source); + source.port.onmessage = null; }; if (ac.currentTime > t) { logger(`[wavetable] still loading sound "${s}:${n}"`, 'highlight'); diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index 2a07e56ce..73fbe9456 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -458,6 +458,7 @@ registerProcessor('distort-processor', DistortProcessor); class SuperSawOscillatorProcessor extends AudioWorkletProcessor { constructor() { super(); + this.isAlive = true; // used internally to prevent multiple death messages this.port.onmessage = (e) => { const { type, payload } = e.data || {}; if (type === 'initialize') { @@ -519,6 +520,10 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor { process(_input, outputs, params) { if (currentTime >= params.end[0]) { // should terminate + if (this.isAlive) { + this.port.postMessage({ type: 'died' }); + this.isAlive = false; + } return false; } if (currentTime <= params.begin[0]) { @@ -1144,6 +1149,7 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { constructor(options) { super(options); + this.isAlive = true; // used internally to prevent multiple death messages this.port.onmessage = (e) => { const { type, payload } = e.data || {}; if (type === 'initialize') { @@ -1153,8 +1159,9 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { this.initialize(); } initialize(options) { - this.frameLen = 0; - this.numFrames = 0; + this.table = null; + this.frameLen = null; + this.numFrames = null; this.phase = []; if (options?.frames) { const key = options.key; @@ -1311,6 +1318,10 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { process(_inputs, outputs, parameters) { if (currentTime >= parameters.end[0]) { + if (this.isAlive) { + this.port.postMessage({ type: 'died' }); + this.isAlive = false; + } return false; } if (currentTime <= parameters.begin[0]) { @@ -1318,7 +1329,7 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { } const outL = outputs[0][0]; const outR = outputs[0][1] || outputs[0][0]; - if (!this.tables) { + if (!this.table) { outL.fill(0); if (outR !== outL) outR.set(outL); return true;