Use currentTime for exact scheduling

This commit is contained in:
Aria 2025-09-06 10:09:44 -05:00
parent 9c108862ef
commit 798eb22d9a
3 changed files with 47 additions and 46 deletions

View file

@ -590,12 +590,12 @@ export const { duckdepth } = registerControl('duckdepth');
* @param {number | Pattern} time The onset time in seconds
* @example
* // Clicks
* sound: n(run(8)).scale("c:minor").s("sawtooth").lpf(200).delay(.7).orbit(2)
* duckerWithClick: s("bd*4").duckorbit(2).duckonset(0).postgain(0)
* sound: freq("63.2388").s("sine").orbit(2).gain(4)
* duckerWithClick: s("bd*4").duckorbit(2).duckattack(0.3).duckonset(0).postgain(0)
* @example
* // No clicks
* sound: n(run(8)).scale("c:minor").s("sawtooth").lpf(200).delay(.7).orbit(2)
* duckerWithoutClick: s("bd*4").duckorbit(2).duckonset(0.003).postgain(0)
* sound: freq("63.2388").s("sine").orbit(2).gain(4)
* duckerWithoutClick: s("bd*4").duckorbit(2).duckattack(0.3).duckonset(0.01).postgain(0)
* @example
* // Rhythmic
* noise: s("pink").distort("2:1").orbit(4) // used rhythmically with 0.3 onset below

View file

@ -420,7 +420,7 @@ function setOrbit(audioContext, orbit, channels) {
}
}
function duckOrbit(audioContext, targetOrbit, t, onsettime = 0.003, attacktime = 0.1, duckdepth = 1) {
function duckOrbit(audioContext, targetOrbit, t, onsettime = 0, attacktime = 0.1, duckdepth = 1) {
const targetArr = [targetOrbit].flat();
const onsetArr = [onsettime].flat();
const attackArr = [attacktime].flat();
@ -438,17 +438,18 @@ function duckOrbit(audioContext, targetOrbit, t, onsettime = 0.003, attacktime =
webAudioTimeout(
audioContext,
() => {
gainParam.cancelScheduledValues(t);
const now = audioContext.currentTime;
// cancelScheduledValues and setValueAtTime together emulate cancelAndHoldAtTime
// on browsers which lack that method
const currVal = gainParam.value;
gainParam.cancelScheduledValues(now);
gainParam.setValueAtTime(currVal, now);
const t0 = Math.max(t, now); // guard against now > t
const duckedVal = clamp(1 - Math.sqrt(depth), 0.01, currVal);
// Guarantees the value is set to currVal at time t. This in conjunction with
// cancelScheduledValues above emulates cancelAndHoldAtTime on browsers which lack
// that method
gainParam.setValueAtTime(currVal, t);
gainParam.exponentialRampToValueAtTime(duckedVal, t + onset);
gainParam.exponentialRampToValueAtTime(1, t + onset + attack);
gainParam.exponentialRampToValueAtTime(duckedVal, t0 + onset);
gainParam.exponentialRampToValueAtTime(1, t0 + onset + attack);
},
0,
t - 0.01,