diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index be2327e1a..5264a1342 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -41,25 +41,20 @@ const voicePools = {}; // Cycles through the pool attempting to find an inactive voice that hasn't been GC'd export const claimVoice = (key) => { - voicePools[key] ??= {}; + voicePools[key] ??= []; const pool = voicePools[key]; let node; - for (const [id, ref] of Object.entries(pool)) { + while (pool.length && !node) { + const ref = pool.pop(); node = ref?.deref?.(); - delete pool[id]; - if (node !== null) break; } return node; }; // Releases a voice from use and adds to the inactive pool -export const releaseVoice = (key, id, node) => { - voicePools[key] ??= {}; - voicePools[key][id] = new WeakRef(node); -}; - -export const removeVoice = (key, id) => { - delete voicePools[key][id]; +export const releaseVoice = (key, node) => { + voicePools[key] ??= []; + voicePools[key].push(new WeakRef(node)); }; export const getParamADSR = ( diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 4014a8e08..5d114f3d6 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -15,7 +15,6 @@ import { getWorklet, setParams, releaseVoice, - removeVoice, noises, webAudioTimeout, } from './helpers.mjs'; @@ -180,13 +179,11 @@ export function registerSynthSounds() { voices, }; if (o == null) { - console.log('Building'); o = getWorklet(ac, 'supersaw-oscillator', params, { outputChannelCount: [2], processorOptions, }); } else { - console.log('Reusing'); setParams(o, params); o.port.postMessage({ type: 'reset', payload: { processorOptions } }); } @@ -209,14 +206,8 @@ export function registerSynthSounds() { const timeoutNode = webAudioTimeout( ac, () => { - const id = Math.floor(Math.random() * 10000); destroyAudioWorkletNode(o); - releaseVoice('supersaw', id, o); - o.port.onmessage = (e) => { - if (e.data.type === 'finished') { - removeVoice('supersaw', id); - } - }; + releaseVoice('supersaw', o); onended(); fm?.stop(); vibratoOscillator?.stop(); diff --git a/packages/superdough/wavetable.mjs b/packages/superdough/wavetable.mjs index 480453f7f..d3c08e575 100644 --- a/packages/superdough/wavetable.mjs +++ b/packages/superdough/wavetable.mjs @@ -12,7 +12,6 @@ import { getWorklet, setParams, releaseVoice, - removeVoice, webAudioTimeout, destroyAudioWorkletNode, } from './helpers.mjs'; @@ -255,11 +254,6 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) { logger(`[wavetable] still loading sound "${s}:${n}"`, 'highlight'); destroyAudioWorkletNode(source); releaseVoice(voiceKey, source); - source.port.onmessage = (e) => { - if (e.data.type === 'finished') { - removeVoice(voiceKey, id); - } - }; return; } const posADSRParams = [value.wtattack, value.wtdecay, value.wtsustain, value.wtrelease]; @@ -337,13 +331,7 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) { wtPosModulators?.disconnect(); wtWarpModulators?.disconnect(); destroyAudioWorkletNode(source); - const id = Math.floor(Math.random() * 10000); - releaseVoice(voiceKey, id, source); - source.port.onmessage = (e) => { - if (e.data.type === 'finished') { - removeVoice(voiceKey, id); - } - }; + releaseVoice(voiceKey, source); onended(); }, t, diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index d5ba329ba..09262f94a 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -525,14 +525,9 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor { } process(_input, outputs, params) { const started = currentTime >= params.begin[0]; - const end = params.end[0]; - const ended = currentTime >= end + 5; - const inGracePeriod = currentTime >= end && !ended; - if (!started || inGracePeriod) { + const ended = currentTime >= params.end[0]; + if (!started || ended) { return true; - } else if (ended) { - this.port.postMessage({ type: 'finished' }); - return false; } const output = outputs[0]; // fast k-rate paths @@ -1174,25 +1169,10 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { const key = payload.key; this.frameLen = payload.frameLen; if (!tablesCache[key]) { - const tables = [payload.frames]; - let table = tables[0]; - for (let level = 1; level < 6; level++) { - const nextLen = table[0].length >> 1; - const nextTable = table.map((frame) => { - const avg = new Float32Array(nextLen); - for (let i = 0; i < nextLen; i++) { - avg[i] = (frame[2 * i] + frame[2 * i + 1]) / 2; - } - return avg; - }); - tables.push(nextTable); - table = nextTable; - if (nextLen <= 32) break; - } - tablesCache[key] = tables; + tablesCache[key] = payload.frames; } - this.tables = tablesCache[key]; - this.numFrames = this.tables[0].length; + this.table = tablesCache[key]; + this.numFrames = this.table.length; } else if (type === 'reset') { this.reset(payload.processorOptions); } @@ -1352,24 +1332,11 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { return a + (b - a) * frac; } - _chooseMip(dphi) { - const approxHarm = clamp(dphi, 1e-6, 64); - let level = 0; - while (level + 1 < (this.tables?.length || 1) && approxHarm < this.tables[level][0].length / 8) { - level++; - } - return level; - } - process(_inputs, outputs, params) { const started = currentTime >= params.begin[0]; - const end = params.end[0]; - const ended = currentTime >= end + 5; - const inGracePeriod = currentTime >= end && !ended; - if (!this.tables || !started || inGracePeriod) { + const ended = currentTime >= params.end[0]; + if (!started || ended) { return true; - } else if (ended) { - return false; } const outL = outputs[0][0]; const outR = outputs[0][1] || outputs[0][0]; @@ -1409,13 +1376,10 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { for (let n = 0; n < this.voices; n++) { const freqVoice = applyFastDetune(freq, detuner(n)); // voice detune const dPhase = freqVoice * INVSR; - const level = this._chooseMip(dPhase); - const table = this.tables[level]; - // warp phase then sample const ph = this._warpPhase(this.phases[n], warpAmount, warpMode); - const s0 = this._sampleFrame(table[fIdx], ph); - const s1 = this._sampleFrame(table[Math.min(this.numFrames - 1, fIdx + 1)], ph); + const s0 = this._sampleFrame(this.table[fIdx], ph); + const s1 = this._sampleFrame(this.table[Math.min(this.numFrames - 1, fIdx + 1)], ph); let s = lerp(s0, s1, interpT); if (warpMode === WarpMode.FLIP && this.phases[n] < warpAmount) { s = -s; @@ -1426,7 +1390,7 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor { // invert right and left gain const tmp = gainL; gainR = gainL; - gainL = gainR; + gainL = tmp; } } return true;