mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 14:26:58 -04:00
Huge overhaul for config part 1
This commit is contained in:
@@ -1886,301 +1886,6 @@ export const { panorient } = registerControl('panorient');
|
||||
// ['pitch3'],
|
||||
// ['portamento'],
|
||||
|
||||
/**
|
||||
* Sets the target destination for the LFO modulation. Names are typically related
|
||||
* to existing controls ("source", "lpf", "vibrato", etc.). You can try a value
|
||||
* and if it fails, the console will print the available options.
|
||||
*
|
||||
* @name lfoTarget
|
||||
* @synonyms lfot, lfotarget
|
||||
* @param {string | Pattern} target Target identifier for modulation.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoDepth(3000)
|
||||
* .lfoRate(0.25)
|
||||
* .lfoSynced(1)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
*/
|
||||
export const { lfoTarget, lfot, lfotarget } = registerControl('lfoTarget', 'lfot', 'lfotarget');
|
||||
|
||||
/**
|
||||
* Chooses which parameter the LFO will modulate on the target. Parameter values
|
||||
* are things like "frequency", "Q", "detune", etc. You can try a value
|
||||
* and if it fails, the console will print the available options.
|
||||
*
|
||||
* @name lfoParam
|
||||
* @synonyms lfop, lfoparam
|
||||
* @param {string | Pattern} param Parameter name
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoDepth(3000)
|
||||
* .lfoRate(0.25)
|
||||
* .lfoSynced(1)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
*/
|
||||
export const { lfoParam, lfop, lfoparam } = registerControl('lfoParam', 'lfop', 'lfoparam');
|
||||
|
||||
/**
|
||||
* Controls the speed of the LFO.
|
||||
*
|
||||
* @name lfoRate
|
||||
* @synonyms lfor, lforate
|
||||
* @param {number | Pattern} rate Frequency or tempo-relative value.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(3000)
|
||||
* .lfoRate(0.25)
|
||||
*/
|
||||
export const { lfoRate, lfor, lforate } = registerControl('lfoRate', 'lfor', 'lforate');
|
||||
|
||||
/**
|
||||
* Sets the modulation depth of the LFO.
|
||||
*
|
||||
* @name lfoDepth
|
||||
* @synonyms lfod, lfodepth
|
||||
* @param {number | Pattern} depth Modulation depth amount.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoSynced(1)
|
||||
* .lfoDepth(5000)
|
||||
*/
|
||||
export const { lfoDepth, lfod, lfodepth } = registerControl('lfoDepth', 'lfod', 'lfodepth');
|
||||
|
||||
/**
|
||||
* Applies a DC offset to the LFO signal. Normally the LFO varies from
|
||||
* 0 to 1 (i.e. unipolar). By using an offset of -0.5, one can achieve
|
||||
* a bipolar LFO.
|
||||
*
|
||||
* @name lfoDCOffset
|
||||
* @synonyms lfodc, lfodcoffset
|
||||
* @param {number | Pattern} offset Offset amount.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(2000)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(1000)
|
||||
* .lfoRate(4)
|
||||
* .lfoSynced(1)
|
||||
* .lfoDCOffset(-0.5)
|
||||
*/
|
||||
export const { lfoDCOffset, lfodc, lfodcoffset } = registerControl('lfoDCOffset', 'lfodc', 'lfodcoffset');
|
||||
|
||||
/**
|
||||
* Selects the waveform shape of the LFO. Current options are
|
||||
* triangle, square, sine, saw, ramp (corresponding to 0 through 4,
|
||||
* respectively).
|
||||
*
|
||||
* @name lfoShape
|
||||
* @synonyms lfosh, lfoshape
|
||||
* @param {number | Pattern} shape Waveform type identifier.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(1000)
|
||||
* .lfoRate(4)
|
||||
* .lfoSynced(1)
|
||||
* .lfoShape(3)
|
||||
*/
|
||||
export const { lfoShape, lfosh, lfoshape } = registerControl('lfoShape', 'lfosh', 'lfoshape');
|
||||
|
||||
/**
|
||||
* Skews the LFO waveform.
|
||||
*
|
||||
* @name lfoSkew
|
||||
* @synonyms lfosk, lfoskew
|
||||
* @param {number | Pattern} skew Skew amount (between 0 and 1).
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(1000)
|
||||
* .lfoRate(4)
|
||||
* .lfoSynced(1)
|
||||
* .lfoSkew(0.75)
|
||||
*/
|
||||
export const { lfoSkew, lfosk, lfoskew } = registerControl('lfoSkew', 'lfosk', 'lfoskew');
|
||||
|
||||
/**
|
||||
* Adjusts the (exponential) curvature of the LFO waveform.
|
||||
*
|
||||
* @name lfoCurve
|
||||
* @synonyms lfoc, lfocurve
|
||||
* @param {number | Pattern} curve Curve shaping amount.
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(1000)
|
||||
* .lfoShape(3).lfoRate(4)
|
||||
* .lfoSynced(1)
|
||||
* .lfoCurve(0.95)
|
||||
*/
|
||||
export const { lfoCurve, lfoc, lfocurve } = registerControl('lfoCurve', 'lfoc', 'lfocurve');
|
||||
|
||||
/**
|
||||
* Sets the tempo-synced rate of the LFO
|
||||
*
|
||||
* @name lfoSync
|
||||
* @synonyms lfos, lfosync
|
||||
* @param {number | Pattern} rate Rate to be multiplied by cycles per second
|
||||
* note("F2").sound("supersaw")
|
||||
* .lpf(100)
|
||||
* .lfoTarget("lpf")
|
||||
* .lfoParam("frequency")
|
||||
* .lfoDepth(1000)
|
||||
* .lfoShape(3).lfoSync(2)
|
||||
*/
|
||||
export const { lfoSync, lfos, lfosync } = registerControl('lfoSync', 'lfos', 'lfosync');
|
||||
|
||||
/**
|
||||
* Sets the target destination for the envelope modulation. Names are typically related
|
||||
* to existing controls ("source", "lpf", "vibrato", etc.). You can try a value
|
||||
* and if it fails, the console will print the available options.
|
||||
*
|
||||
* @name envTarget
|
||||
* @synonyms envt, envtarget
|
||||
* @param {number | Pattern} envTarget Target identifier for modulation.
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
*/
|
||||
export const { envTarget, envt, envtarget } = registerControl('envTarget', 'envt', 'envtarget');
|
||||
|
||||
/**
|
||||
* Chooses which parameter the LFO will modulate on the target. Parameter values
|
||||
* are things like "frequency", "Q", "detune", etc. You can try a value
|
||||
* and if it fails, the console will print the available options.
|
||||
*
|
||||
* @name envParam
|
||||
* @synonyms envp, envparam
|
||||
* @param {number | Pattern} envParam Parameter index or identifier.
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
*/
|
||||
export const { envParam, envp, envparam } = registerControl('envParam', 'envp', 'envparam');
|
||||
|
||||
/**
|
||||
* Controls the attack time of the envelope.
|
||||
*
|
||||
* @name envAttack
|
||||
* @synonyms envatt, envattack
|
||||
* @param {number | Pattern} envAttack Duration of attack phase.
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(500)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
* .envAttack(0.5)
|
||||
*/
|
||||
export const { envAttack, envatt, envattack } = registerControl('envAttack', 'envatt', 'envattack');
|
||||
|
||||
/**
|
||||
* Controls the decay time of the envelope.
|
||||
*
|
||||
* @name envDecay
|
||||
* @synonyms envdec, envdecay
|
||||
* @param {number | Pattern} envDecay Duration of decay phase.
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
* .envDecay("0.03:0.15")
|
||||
* .envDCurve(-0.4)
|
||||
*/
|
||||
export const { envDecay, envdec, envdecay } = registerControl('envDecay', 'envdec', 'envdecay');
|
||||
|
||||
/**
|
||||
* Sets the sustain level of the envelope.
|
||||
*
|
||||
* @name envSustain
|
||||
* @synonyms envs, envsustain
|
||||
* @param {number | Pattern} envSustain Sustain amplitude level.
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
* .envACurve(0.6).envDCurve(-0.2)
|
||||
* .envSustain(0.2)
|
||||
*/
|
||||
export const { envSustain, envs, envsustain } = registerControl('envSustain', 'envs', 'envsustain');
|
||||
|
||||
/**
|
||||
* Controls the release time of the envelope.
|
||||
*
|
||||
* @name envRelease
|
||||
* @synonyms envr, envrelease
|
||||
* @param {number | Pattern} envRelease Duration of release phase.
|
||||
* @example
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100).release(3)
|
||||
* .envDepth("4800:400")
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
* .envDecay("0.03:0.15").envRCurve(0.5)
|
||||
* .envSustain(0.5)
|
||||
* .envRelease(3)
|
||||
*/
|
||||
export const { envRelease, envr, envrelease } = registerControl('envRelease', 'envr', 'envrelease');
|
||||
|
||||
/**
|
||||
* Sets the modulation depth of the envelope.
|
||||
*
|
||||
* @name envDepth
|
||||
* @synonyms envd, envdepth
|
||||
* @param {number | Pattern} envDepth Modulation depth amount.
|
||||
* @example
|
||||
* n(irand(12).seg(8)).scale("F#3:minor").room(1)
|
||||
* .lpf(100)
|
||||
* .envTarget("source:lpf")
|
||||
* .envParam("detune:frequency")
|
||||
* .envDepth("4800:400")
|
||||
*/
|
||||
export const { envDepth, envd, envdepth } = registerControl('envDepth', 'envd', 'envdepth');
|
||||
|
||||
/**
|
||||
* Adjusts the curvature of the attack portion of the envelope. Positive values are snappy,
|
||||
* negative values are slow
|
||||
*
|
||||
* @name envACurve
|
||||
* @synonyms envac, envacurve
|
||||
* @param {number | Pattern} envACurve Curvature amount (between -1 and 1).
|
||||
*/
|
||||
export const { envACurve, envac, envacurve } = registerControl('envACurve', 'envac', 'envacurve');
|
||||
|
||||
/**
|
||||
* Adjusts the curvature of the decay portion of the envelope. Positive values are snappy,
|
||||
* negative values are slow
|
||||
*
|
||||
* @name envDCurve
|
||||
* @synonyms envdc, envdcurve
|
||||
* @param {number | Pattern} envDCurve Curvature amount (between -1 and 1).
|
||||
*/
|
||||
export const { envDCurve, envdc, envdcurve } = registerControl('envDCurve', 'envdc', 'envdcurve');
|
||||
|
||||
/**
|
||||
* Adjusts the curvature of the release portion of the envelope. Positive values are snappy,
|
||||
* negative values are slow
|
||||
*
|
||||
* @name envRCurve
|
||||
* @synonyms envrc, envrcurve
|
||||
* @param {number | Pattern} envRCurve Curvature amount (between -1 and 1).
|
||||
*/
|
||||
export const { envRCurve, envrc, envrcurve } = registerControl('envRCurve', 'envrc', 'envrcurve');
|
||||
|
||||
// TODO: slide param for certain synths
|
||||
export const { slide } = registerControl('slide');
|
||||
// TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare
|
||||
|
||||
+105
-35
@@ -3706,50 +3706,120 @@ const resolveConfigKey = (funcName, key) => {
|
||||
return aliasMap.get(normalized) ?? key;
|
||||
};
|
||||
|
||||
addConfigAlias('lfo', 'lfoTarget', 'lfot', 'lfotarget', 'target', 't');
|
||||
addConfigAlias('lfo', 'lfoParam', 'lfop', 'lfoparam', 'param', 'parameter', 'p');
|
||||
addConfigAlias('lfo', 'lfoRate', 'lfor', 'lforate', 'rate', 'r');
|
||||
addConfigAlias('lfo', 'lfoDepth', 'lfod', 'lfodepth', 'depth', 'd');
|
||||
addConfigAlias('lfo', 'lfoDCOffset', 'lfodc', 'lfodcoffset', 'dcoffset', 'offset', 'dc');
|
||||
addConfigAlias('lfo', 'lfoShape', 'lfosh', 'lfoshape', 'shape', 'sh');
|
||||
addConfigAlias('lfo', 'lfoSkew', 'lfosk', 'lfoskew', 'skew', 'sk');
|
||||
addConfigAlias('lfo', 'lfoCurve', 'lfoc', 'lfocurve', 'curve', 'c');
|
||||
addConfigAlias('lfo', 'lfoSync', 'lfos', 'lfosync', 'sync', 'synced', 's');
|
||||
addConfigAlias('env', 'envTarget', 'envt', 'envtarget');
|
||||
addConfigAlias('env', 'envParam', 'envp', 'envparam');
|
||||
addConfigAlias('env', 'envAttack', 'envatt', 'envattack');
|
||||
addConfigAlias('env', 'envDecay', 'envdec', 'envdecay');
|
||||
addConfigAlias('env', 'envSustain', 'envs', 'envsustain');
|
||||
addConfigAlias('env', 'envRelease', 'envr', 'envrelease');
|
||||
addConfigAlias('env', 'envDepth', 'envd', 'envdepth');
|
||||
addConfigAlias('env', 'envACurve', 'envac', 'envacurve');
|
||||
addConfigAlias('env', 'envDCurve', 'envdc', 'envdcurve');
|
||||
addConfigAlias('env', 'envRCurve', 'envrc', 'envrcurve');
|
||||
addConfigAlias('lfo', 'target', 't');
|
||||
addConfigAlias('lfo', 'param', 'p');
|
||||
addConfigAlias('lfo', 'rate', 'r');
|
||||
addConfigAlias('lfo', 'depth', 'dep', 'dp', 'd');
|
||||
addConfigAlias('lfo', 'dc');
|
||||
addConfigAlias('lfo', 'shape', 'sh');
|
||||
addConfigAlias('lfo', 'skew', 'sk');
|
||||
addConfigAlias('lfo', 'curve', 'c');
|
||||
addConfigAlias('lfo', 'sync', 's');
|
||||
addConfigAlias('env', 'target', 't');
|
||||
addConfigAlias('env', 'attack', 'att', 'a');
|
||||
addConfigAlias('env', 'decay', 'dec', 'd');
|
||||
addConfigAlias('env', 'sustain', 'sus', 's');
|
||||
addConfigAlias('env', 'release', 'rel', 'r');
|
||||
addConfigAlias('env', 'depth', 'dep', 'dp');
|
||||
addConfigAlias('env', 'acurve', 'ac');
|
||||
addConfigAlias('env', 'dcurve', 'dc');
|
||||
addConfigAlias('env', 'rcurve', 'rc');
|
||||
addConfigAlias('send', 'id');
|
||||
addConfigAlias('send', 'target', 't');
|
||||
addConfigAlias('send', 'depth', 'dep', 'dp', 'd');
|
||||
addConfigAlias('send', 'dc');
|
||||
addConfigAlias('send', 'offset', 'off', 'o');
|
||||
|
||||
/**
|
||||
* Establishes a signal chain. Can be called in sequence like pat.chain(...).chain(...) and so forth
|
||||
* and/or in a single .chain(..., ..., etc) call. The arguments to `chain` are _patterns_ which each act like
|
||||
* a self-contained pattern and follow the normal [signal chain](https://strudel.cc/learn/effects/).
|
||||
*
|
||||
* If multiple sound generators are present within the chain, they will be mixed in at the location where
|
||||
* they are declared.
|
||||
*
|
||||
* @name chain
|
||||
* @memberof Pattern
|
||||
* @param {Pattern | Pattern[]} patterns Patterns to combine into a single chain
|
||||
* @returns Pattern
|
||||
*/
|
||||
Pattern.prototype.lfo = function (config) {
|
||||
Pattern.prototype.mod = function (type, config, idx) {
|
||||
if (config == null || typeof config !== 'object') {
|
||||
return this;
|
||||
}
|
||||
if (!['lfo', 'send', 'env'].includes(type)) {
|
||||
logger(`[core] Modulation type ${type} not found. Please use one of 'lfo', 'env', 'send'`);
|
||||
return this;
|
||||
}
|
||||
let output = this;
|
||||
for (const [rawKey, value] of Object.entries(config)) {
|
||||
const key = resolveConfigKey('lfo', rawKey);
|
||||
const key = resolveConfigKey(type, rawKey);
|
||||
const pat = reify(value);
|
||||
output = output.set(pat.as(key));
|
||||
output = output
|
||||
.fmap((v) => (c) => {
|
||||
v[type] ??= [];
|
||||
const t = v[type];
|
||||
idx ??= t.length;
|
||||
t[idx] ??= {};
|
||||
t[idx][key] = c;
|
||||
return v;
|
||||
})
|
||||
.appLeft(pat);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures an LFO. Can be called in sequence like pat.lfo(...).lfo(...) to set up multiple LFOs
|
||||
*
|
||||
*
|
||||
* @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: target, t
|
||||
* @param {number | Pattern} [config.rate] Modulation rate. Aliases: rate, r
|
||||
* @param {number | Pattern} [config.depth] Modulation depth. Aliases: dep, dp, d
|
||||
* @param {number | Pattern} [config.dc] DC offset / bias for the waveform
|
||||
* @param {number | Pattern} [config.shape] Waveform shape index. Aliases: sh
|
||||
* @param {number | Pattern} [config.skew] Waveform skew amount. Aliases: sk
|
||||
* @param {number | Pattern} [config.curve] Exponential curve amount. Aliases: c
|
||||
* @param {number | Pattern} [config.sync] Tempo-synced modulation rate. Aliases: s
|
||||
* @param {number | null} idx Index of the LFO slot to overwrite. Omit to append a new LFO
|
||||
* @returns Pattern
|
||||
*/
|
||||
Pattern.prototype.lfo = function (config, idx) {
|
||||
return this.mod('lfo', config, idx);
|
||||
};
|
||||
export const lfo = (config) => pure({}).lfo(config);
|
||||
|
||||
/**
|
||||
* Configures an envelope. Can be called in sequence like pat.env(...).env(...) to set up multiple envelopes
|
||||
*
|
||||
*
|
||||
* @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: target, t
|
||||
* @param {number | Pattern} [config.depth] Modulation depth. Aliases: dep, dp
|
||||
* @param {number | Pattern} [config.attack] Time to reach depth. Aliases: att, a
|
||||
* @param {number | Pattern} [config.decay] Time to reach sustain. Aliases: dec, d
|
||||
* @param {number | Pattern} [config.sustain] Sustain depth. Aliases: sus, s
|
||||
* @param {number | Pattern} [config.release] Time to return to nominal value. Aliases: rel, r
|
||||
* @param {number | Pattern} [config.acurve] Snappiness of attack curve (-1 = relaxed, 1 = snappy). Aliases: ac
|
||||
* @param {number | Pattern} [config.dcurve] Snappiness of decay curve (-1 = relaxed, 1 = snappy). Aliases: dc
|
||||
* @param {number | Pattern} [config.rcurve] Snappiness of release curve (-1 = relaxed, 1 = snappy). Aliases: rc
|
||||
* @param {number | null} idx Index of the envelope slot to overwrite. Omit to append a new envelope
|
||||
* @returns Pattern
|
||||
*/
|
||||
Pattern.prototype.env = function (config, idx) {
|
||||
return this.mod('env', config, idx);
|
||||
};
|
||||
export const env = (config) => pure({}).env(config);
|
||||
|
||||
/**
|
||||
* Sends the output of this pattern to a parameter on another pattern.
|
||||
* Can be called in sequence like pat.send(...).send(...) to send to multiple parameters
|
||||
*
|
||||
*
|
||||
* @name send
|
||||
* @memberof Pattern
|
||||
* @param {Object} config Send configuration.
|
||||
* @param {string | Pattern} [config.id] Pattern id to modulate
|
||||
* @param {string | Pattern} [config.target] Node (and parameter if specified like `lpf.frequency`) to modulate. Aliases: target, t
|
||||
* @param {number | Pattern} [config.depth] Modulation depth. Aliases:dep, dp, d
|
||||
* @param {number | Pattern} [config.dc] DC offset prior to application
|
||||
* @param {number | Pattern} [config.offset] Offset to apply to the parameter. Aliases: off, o
|
||||
* @param {number | null} idx Index of the send slot to overwrite. Omit to append a new send
|
||||
* @returns Pattern
|
||||
*/
|
||||
Pattern.prototype.send = function (config, idx) {
|
||||
return this.mod('send', config, idx);
|
||||
};
|
||||
export const send = (config) => pure({}).send(config);
|
||||
|
||||
Reference in New Issue
Block a user