From fd946107df157ef51821921b6047b14b4dc9bea1 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Thu, 14 Mar 2024 20:35:56 -0400 Subject: [PATCH] use lerp --- packages/core/controls.mjs | 2 +- packages/superdough/synth.mjs | 4 ++-- packages/superdough/worklets.mjs | 23 +++++++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 213839e1..b75d7606 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -890,7 +890,7 @@ export const { lock } = registerControl('lock'); * @param {number | Pattern} amount * @synonyms det * @example - * note("d f a a# a d3").fast(2).s("supersaw").detune("<.4 1 3 200>") + * note("d f a a# a d3").fast(2).s("supersaw").detune("<.1 .2 .5 24.1>") * */ export const { detune, det } = registerControl('detune', 'det'); diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 0734b581..0df098e1 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -64,8 +64,8 @@ export function registerSynthSounds() { 'supersaw', (begin, value, onended) => { const ac = getAudioContext(); - let { duration, n, unison = 6, spread = 0.3, detune } = value; - detune = detune ?? n ?? 2; + let { duration, n, unison = 5, spread = 0.6, detune } = value; + detune = detune ?? n ?? 0.18; const frequency = getFrequencyFromValue(value); const [attack, decay, sustain, release] = getADSRValues( diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index ea9eb9ed..744ca301 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -161,10 +161,21 @@ const saw = (phase, dt) => { return v - polyBlep(phase, dt); }; +function lerp(a, b, n) { + return n * (b - a) + a; +} + +function getUnisonDetune(unison, detune, voiceIndex) { + if (unison < 2) { + return 0; + } + return lerp(-detune, detune, voiceIndex / (unison - 1)); +} class SuperSawOscillatorProcessor extends AudioWorkletProcessor { constructor() { super(); this.phase = []; + this.logged = 0; } static get parameterDescriptors() { return [ @@ -207,7 +218,7 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor { { name: 'voices', - defaultValue: 6, + defaultValue: 5, min: 1, }, ]; @@ -233,13 +244,13 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor { const gain2 = Math.sqrt(panspread); for (let n = 0; n < voices; n++) { - let adj = 0; const isOdd = (n & 1) == 1; - //adjust the detune amount for each voice - if (n > 0) { - adj = isOdd ? n * freqspread : -((n - 1) * freqspread); + + if (this.logged < 10) { + this.logged += 1; } - const freq = Math.min(16744, Math.max(1, frequency + adj * 0.01 * frequency)); + //applies unison "spread" detune in semitones + const freq = frequency * Math.pow(2, getUnisonDetune(voices, freqspread, n) / 1.2); let gainL = gain1; let gainR = gain2; // invert right and left gain