From 4169b764c3ce68fc638d945dc918cd77ae36d6a6 Mon Sep 17 00:00:00 2001 From: Aria Date: Thu, 11 Dec 2025 15:28:48 -0600 Subject: [PATCH] Simpler control handling --- packages/core/pattern.mjs | 31 +++++++++++++++++++----------- packages/superdough/superdough.mjs | 22 ++++++++++----------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 7d0e46138..04328ccf7 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -3724,8 +3724,8 @@ const resolveConfigKey = (funcName, key) => { return aliasMap.get(normalized) ?? key; }; -addConfigAlias('lfo', 'target', 't'); -addConfigAlias('lfo', 'param', 'p'); +addConfigAlias('lfo', 'control', 'c'); +addConfigAlias('lfo', 'subControl', 'sc'); addConfigAlias('lfo', 'rate', 'r'); addConfigAlias('lfo', 'depth', 'dep', 'dr'); addConfigAlias('lfo', 'depthabs', 'da'); @@ -3734,7 +3734,8 @@ addConfigAlias('lfo', 'shape', 'sh'); addConfigAlias('lfo', 'skew', 'sk'); addConfigAlias('lfo', 'curve', 'c'); addConfigAlias('lfo', 'sync', 's'); -addConfigAlias('env', 'target', 't'); +addConfigAlias('env', 'control', 'c'); +addConfigAlias('env', 'subControl', 'sc'); addConfigAlias('env', 'attack', 'att', 'a'); addConfigAlias('env', 'decay', 'dec', 'd'); addConfigAlias('env', 'sustain', 'sus', 's'); @@ -3745,7 +3746,8 @@ addConfigAlias('env', 'acurve', 'ac'); addConfigAlias('env', 'dcurve', 'dc'); addConfigAlias('env', 'rcurve', 'rc'); addConfigAlias('bmod', 'orbit', 'o'); -addConfigAlias('bmod', 'target', 't'); +addConfigAlias('bmod', 'control', 'c'); +addConfigAlias('bmod', 'subControl', 'sc'); addConfigAlias('bmod', 'depth', 'dep', 'dr'); addConfigAlias('bmod', 'depthabs', 'da'); addConfigAlias('bmod', 'dc'); @@ -3761,27 +3763,31 @@ Pattern.prototype.modulate = function (type, config, idx) { } let output = this; let defaultValue = {}; - let defaultSet = 'target' in config; + let defaultSet = 'control' in config; for (const [rawKey, value] of Object.entries(config)) { const key = resolveConfigKey(type, rawKey); const valuePat = reify(value); output = output .fmap((v) => (c) => { if (!defaultSet) { - // default target to the control set just before this in the chain + // default control to the control set just before this in the chain // e.g. pat.gain(0.5).lfo({..}) will be a gain-LFO let control = getControlName(Object.keys(v).at(-1)); if (modulatorKeys.includes(control)) { control = `${control}${v[type].length - 1}`; } - defaultValue = { target: control }; + defaultValue = { control }; defaultSet = true; } v[type] ??= []; const t = v[type]; idx ??= t.length; t[idx] ??= defaultValue; - t[idx][key] = key === 'target' ? getControlName(c) : c; + if (key === 'control' || key === 'subControl') { + t[idx][key] = getControlName(c); + } else { + t[idx][key] = c; + } return v; }) .appLeft(valuePat); @@ -3795,7 +3801,8 @@ Pattern.prototype.modulate = function (type, config, idx) { * @name lfo * @memberof Pattern * @param {Object} config LFO configuration. - * @param {string | Pattern} [config.target] Node (and parameter if specified like `lpf.frequency`) to modulate. Aliases: t + * @param {string | Pattern} [config.control] Node to modulate. Aliases: t + * @param {string | Pattern} [config.subControl] Sub-control name to append to the control key. Aliases: sc, p * @param {number | Pattern} [config.rate] Modulation rate. Aliases: rate, r * @param {number | Pattern} [config.depth] Relative modulation depth. Aliases: dep, dr * @param {number | Pattern} [config.depthabs] Absolute modulation depth. Aliases: da @@ -3817,7 +3824,8 @@ export const lfo = (config) => pure({}).lfo(config); * @name env * @memberof Pattern * @param {Object} config Envelope configuration. - * @param {string | Pattern} [config.target] Node (and parameter if specified like `lpf.frequency`) to modulate. Aliases: t + * @param {string | Pattern} [config.control] Node to modulate. Aliases: t + * @param {string | Pattern} [config.subControl] Sub-control name to append to the control key. Aliases: sc, p * @param {number | Pattern} [config.depth] Relative modulation depth. Aliases: dep, dr * @param {number | Pattern} [config.depthabs] Absolute modulation depth. Aliases: da * @param {number | Pattern} [config.attack] Time to reach depth. Aliases: att, a @@ -3844,7 +3852,8 @@ export const env = (config) => pure({}).env(config); * @memberof Pattern * @param {Object} config Bus modulation configuration. * @param {string | Pattern} [config.bus] Bus to get modulation signal from - * @param {string | Pattern} [config.target] Node (and parameter if specified like `lpf.frequency`) to modulate. Aliases: t + * @param {string | Pattern} [config.control] Node to modulate. Aliases: t + * @param {string | Pattern} [config.subControl] Sub-control name to append to the control key. Aliases: sc, p * @param {number | Pattern} [config.depth] Relative modulation depth. Aliases: dep, dr * @param {number | Pattern} [config.depthabs] Absolute modulation depth. Aliases: da * @param {number | Pattern} [config.ratio] Modulation ratio. Aliases: rat diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 7cbc58b98..9efc5b3ef 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -411,14 +411,15 @@ function _getRangeForParam(paramName, targetParams, currentValue) { return { min: undefined, max: undefined }; } -function _getTargetParamsForControl(control, nodes, paramOverride) { - const targetInfo = _getControlData(control); +function _getTargetParamsForControl(control, nodes, subControl) { + const lookupKey = subControl ? `${control}_${subControl}` : control; + const targetInfo = _getControlData(lookupKey) ?? _getControlData(control); if (!targetInfo) { errorLogger(`Could not find control data for target '${control}'`, 'superdough'); return { targetParams: [], paramName: control }; } - const paramName = paramOverride ?? targetInfo.param; - const nodeKey = nodes[control] ? control : targetInfo.node; + const paramName = targetInfo.param; + const nodeKey = nodes[targetInfo.node] ? targetInfo.node : control; const targetNodes = nodes[nodeKey]; if (!targetNodes) { const keys = Object.keys(nodes); @@ -445,9 +446,8 @@ function _getTargetParamsForControl(control, nodes, paramOverride) { } function connectLFO(idx, params, nodeTracker, value) { - const { rate = 1, sync, cps, cycle, target = 'lfo', depth = 1, depthabs, param, p, ...filteredParams } = params; - const targetParam = param ?? p; - const { targetParams, paramName } = _getTargetParamsForControl(target, nodeTracker, targetParam); + const { rate = 1, sync, cps, cycle, control = 'lfo', subControl, depth = 1, depthabs, ...filteredParams } = params; + const { targetParams, paramName } = _getTargetParamsForControl(control, nodeTracker, subControl); const currentValue = targetParams[0].value; const { min, max } = _getRangeForParam(paramName, targetParams, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue; @@ -466,8 +466,8 @@ function connectLFO(idx, params, nodeTracker, value) { } function connectEnvelope(idx, params, nodeTracker, value) { - const { target, acurve, dcurve, rcurve, depth = 1, depthabs, ...filteredParams } = params; - const { targetParams, paramName } = _getTargetParamsForControl(target, nodeTracker); + const { control, subControl, acurve, dcurve, rcurve, depth = 1, depthabs, ...filteredParams } = params; + const { targetParams, paramName } = _getTargetParamsForControl(control, nodeTracker, subControl); const currentValue = targetParams[0].value; const { min, max } = _getRangeForParam(paramName, targetParams, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue; @@ -487,13 +487,13 @@ function connectEnvelope(idx, params, nodeTracker, value) { function connectBusModulator(params, nodeTracker, value) { const ac = getAudioContext(); - const { target, depth = 1, depthabs } = params; + const { control, subControl, depth = 1, depthabs } = params; const signal = controller.getBus(params.bus); const dc = new ConstantSourceNode(ac, { offset: params.dc ?? 0 }); dc.start(params.begin); const shifted = dc.connect(gainNode(1)); signal.connect(shifted); - const { targetParams, paramName } = _getTargetParamsForControl(target, nodeTracker); + const { targetParams, paramName } = _getTargetParamsForControl(control, nodeTracker, subControl); const currentValue = targetParams[0].value; const { min, max } = _getRangeForParam(paramName, targetParams, currentValue); const depthValue = depthabs != null ? depthabs : depth * currentValue;