From b0bbd58f6687b9bcd25e6b01b5c27fe651317b8b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Dec 2023 21:36:32 +0100 Subject: [PATCH 1/2] fix: finally repair envelopes --- packages/soundfonts/fontloader.mjs | 4 ++-- packages/superdough/helpers.mjs | 17 +++++++++++++---- packages/superdough/sampler.mjs | 4 ++-- packages/superdough/synth.mjs | 5 ++--- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 5c6759f5c..017ba763c 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -139,8 +139,8 @@ export function registerSoundfonts() { const { node: envelope, stop: releaseEnvelope } = getEnvelope(attack, decay, sustain, release, 0.3, time); bufferSource.connect(envelope); const stop = (releaseTime) => { - bufferSource.stop(releaseTime + release); - releaseEnvelope(releaseTime); + const silentAt = releaseEnvelope(releaseTime); + bufferSource.stop(silentAt); }; bufferSource.onended = () => { bufferSource.disconnect(); diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index d87ea94dc..9833a90f0 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -10,21 +10,30 @@ export function gainNode(value) { // alternative to getADSR returning the gain node and a stop handle to trigger the release anytime in the future export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => { const gainNode = getAudioContext().createGain(); + let phase = begin; gainNode.gain.setValueAtTime(0, begin); - gainNode.gain.linearRampToValueAtTime(velocity, begin + attack); // attack - gainNode.gain.linearRampToValueAtTime(sustain * velocity, begin + attack + decay); // sustain start + phase += attack; + gainNode.gain.linearRampToValueAtTime(velocity, phase); // attack + phase += decay; + let sustainLevel = sustain * velocity; + gainNode.gain.linearRampToValueAtTime(sustainLevel, phase); // decay / sustain // sustain end return { node: gainNode, stop: (t) => { + // to make sure the release won't begin before sustain is reached + //phase = Math.max(t, phase + 0.001); + phase = Math.max(t, phase); + // see https://github.com/tidalcycles/strudel/issues/522 //if (typeof gainNode.gain.cancelAndHoldAtTime === 'function') { // gainNode.gain.cancelAndHoldAtTime(t); // this seems to release instantly.... // see https://discord.com/channels/779427371270275082/937365093082079272/1086053607360712735 //} else { // firefox: this will glitch when the sustain has not been reached yet at the time of release - gainNode.gain.setValueAtTime(sustain * velocity, t); + gainNode.gain.setValueAtTime(sustainLevel, phase); //} - gainNode.gain.linearRampToValueAtTime(0, t + release); + gainNode.gain.linearRampToValueAtTime(0, phase + release); // release + return phase + release; }, }; }; diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 6df5a6b68..39e5b5484 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -312,8 +312,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { const bufferDuration = bufferSource.buffer.duration / bufferSource.playbackRate.value; releaseTime = t + (end - begin) * bufferDuration; } - bufferSource.stop(releaseTime + release); - releaseEnvelope(releaseTime); + const silentAt = releaseEnvelope(releaseTime); + bufferSource.stop(silentAt); }; const handle = { node: out, bufferSource, stop }; diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index edc3c01e1..13c8b93b9 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -56,10 +56,9 @@ export function registerSynthSounds() { return { node: o.connect(g).connect(envelope), stop: (releaseTime) => { - releaseEnvelope(releaseTime); + const silentAt = releaseEnvelope(releaseTime); triggerRelease?.(releaseTime); - let end = releaseTime + release; - stop(end); + stop(silentAt); }, }; }, From f38d1c272e8c7991d5dbba5dd0020028fb9be991 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Dec 2023 21:46:52 +0100 Subject: [PATCH 2/2] cleanup --- packages/superdough/helpers.mjs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 9833a90f0..9194e2bb0 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -22,18 +22,12 @@ export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => node: gainNode, stop: (t) => { // to make sure the release won't begin before sustain is reached - //phase = Math.max(t, phase + 0.001); phase = Math.max(t, phase); // see https://github.com/tidalcycles/strudel/issues/522 - //if (typeof gainNode.gain.cancelAndHoldAtTime === 'function') { - // gainNode.gain.cancelAndHoldAtTime(t); // this seems to release instantly.... - // see https://discord.com/channels/779427371270275082/937365093082079272/1086053607360712735 - //} else { - // firefox: this will glitch when the sustain has not been reached yet at the time of release gainNode.gain.setValueAtTime(sustainLevel, phase); - //} - gainNode.gain.linearRampToValueAtTime(0, phase + release); // release - return phase + release; + phase += release; + gainNode.gain.linearRampToValueAtTime(0, phase); // release + return phase; }, }; };