From 98367868ac0c7c95e44e48d294467c63c1e85dcb Mon Sep 17 00:00:00 2001 From: Aria Date: Mon, 29 Dec 2025 10:22:48 -0600 Subject: [PATCH] Handle min/max when target is LFO; fix vib and tremolo --- packages/superdough/superdough.mjs | 23 +++++++++++++---------- packages/superdough/superdoughdata.mjs | 8 ++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 980f18142..13a4ef68c 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -420,10 +420,10 @@ function _getControlData(control) { return controlTargets[_stripIndex(control)]; } -function _getRangeForParam(paramName, currentValue, control) { - // For our normal oscillators / filters we want to clamp the frequency to a reasonable range - // For LFOs we allow it to be modulated freely - if (paramName === 'frequency' || control?.startsWith?.('lfo')) { +function _getRangeForParam(paramName, currentValue) { + // We clamp the frequency to a reasonable range unless the currentValue + // is low, which indicates this may be an LFO + if (paramName === 'frequency' && currentValue >= 30) { return { min: 20 - currentValue, max: 24000 - currentValue }; } return { min: undefined, max: undefined }; @@ -459,8 +459,9 @@ function connectLFO(idx, params, nodeTracker) { const { rate = 1, sync, cps, cycle, control = 'lfo', subControl, depth = 1, depthabs, ...filteredParams } = params; const { targetParams, paramName } = _getTargetParamsForControl(control, nodeTracker, subControl); if (!targetParams.length) return; - const currentValue = targetParams[0].value; - const { min, max } = _getRangeForParam(paramName, currentValue, control); + let currentValue = targetParams[0].value; + currentValue = currentValue === 0 ? 1 : currentValue; + const { min, max } = _getRangeForParam(paramName, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue; const modParams = { ...filteredParams, @@ -480,8 +481,9 @@ function connectEnvelope(idx, params, nodeTracker) { const { control, subControl, acurve, dcurve, rcurve, depth = 1, depthabs, ...filteredParams } = params; const { targetParams, paramName } = _getTargetParamsForControl(control, nodeTracker, subControl); if (!targetParams.length) return; - const currentValue = targetParams[0].value; - const { min, max } = _getRangeForParam(paramName, currentValue, control); + let currentValue = targetParams[0].value; + currentValue = currentValue === 0 ? 1 : currentValue; + const { min, max } = _getRangeForParam(paramName, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue; const envNode = getEnvelope(getAudioContext(), { ...filteredParams, @@ -507,8 +509,9 @@ function connectBusModulator(params, nodeTracker) { dc.start(params.begin); const shifted = dc.connect(gainNode(1)); signal.connect(shifted); - const currentValue = targetParams[0].value; - const { min, max } = _getRangeForParam(paramName, currentValue, control); + let currentValue = targetParams[0].value; + currentValue = currentValue === 0 ? 1 : currentValue; + const { min, max } = _getRangeForParam(paramName, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue; const maxAbsDepth = Math.min(Math.abs(min), Math.abs(max)); const boundedDepth = Math.min(Math.abs(depthValue), maxAbsDepth) || Math.abs(depthValue); diff --git a/packages/superdough/superdoughdata.mjs b/packages/superdough/superdoughdata.mjs index f9df6ff83..2dac194f1 100644 --- a/packages/superdough/superdoughdata.mjs +++ b/packages/superdough/superdoughdata.mjs @@ -10,8 +10,8 @@ const CONTROL_TARGETS = { gain: { node: 'gain', param: 'gain' }, postgain: { node: 'post', param: 'gain' }, pan: { node: 'pan', param: 'pan' }, - tremolo: { node: 'tremolo', param: 'rate' }, - tremolosync: { node: 'tremolo', param: 'sync' }, + tremolo: { node: 'tremolo', param: 'frequency' }, + tremolosync: { node: 'tremolo', param: 'frequency' }, tremolodepth: { node: 'tremolo_gain', param: 'gain' }, tremoloskew: { node: 'tremolo', param: 'skew' }, tremolophase: { node: 'tremolo', param: 'phase' }, @@ -138,8 +138,8 @@ const CONTROL_TARGETS = { pw: { node: 'source', param: 'pulsewidth' }, pwrate: { node: 'pw_lfo', param: 'frequency' }, pwsweep: { node: 'pw_lfo', param: 'depth' }, - vib: { node: 'vib_gain', param: 'gain' }, - vibmod: { node: 'vib', param: 'frequency' }, + vib: { node: 'vib', param: 'frequency' }, + vibmod: { node: 'vib_gain', param: 'gain' }, byteBeatStartTime: { node: 'source', param: 'byteBeatStartTime' }, spread: { node: 'source', param: 'panspread' }, transient: { node: 'transient', param: 'attack' },