From 7f103e77e3a28ba325b2c94a12e795b17b6077c7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 28 Jul 2025 04:05:21 +0200 Subject: [PATCH 01/15] prefix "S" for solo --- packages/core/repl.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 47231af4d..47489054e 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -138,9 +138,9 @@ export function repl({ // allows muting a pattern x with x_ or _x return silence; } - if (id === '$') { + if (id.includes('$')) { // allows adding anonymous patterns with $: - id = `$${anonymousIndex}`; + id = `${id}${anonymousIndex}`; anonymousIndex++; } pPatterns[id] = this; @@ -201,6 +201,13 @@ export function repl({ let { pattern, meta } = await _evaluate(code, transpiler, transpilerOptions); if (Object.keys(pPatterns).length) { let patterns = Object.values(pPatterns); + + // if there are solo patterns, only use those + const soloPatterns = Object.entries(pPatterns).filter(([key]) => key.length > 1 && key.startsWith('S')); + if (soloPatterns.length) { + patterns = Object.values(Object.fromEntries(soloPatterns)); + } + if (eachTransform) { // Explicit lambda so only element (not index and array) are passed patterns = patterns.map((x) => eachTransform(x)); From 47c85f8540386d36c42c5bc64f952bde12ac79d5 Mon Sep 17 00:00:00 2001 From: jeromew Date: Thu, 16 Oct 2025 14:06:33 +0200 Subject: [PATCH 02/15] fix interoperability of `all` with hydra Hydra add methods on Array.prototype which breaks the Array enumeration with for...in. Use for...of instead cf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#difference_between_for...of_and_for...in for details on the issue without this fix, it is impossible to use both `await initHydra()` and `all` in the same strudel code. Strudel errors with "Error: got "undefined" instead of pattern." example code: https://strudel.cc/#YXdhaXQgaW5pdEh5ZHJhKCkKCmFsbChwaWFub3JvbGwpCgokOiBzKCJiZCIp --- packages/core/repl.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 171697eb9..064ef1eb8 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -227,8 +227,8 @@ export function repl({ pattern = eachTransform(pattern); } if (allTransforms.length) { - for (let i in allTransforms) { - pattern = allTransforms[i](pattern); + for (const transform of allTransforms) { + pattern = transform(pattern); } } From 907f03f3bfe35bc4b6695490030e6f4822747629 Mon Sep 17 00:00:00 2001 From: jeromew Date: Thu, 20 Nov 2025 17:40:51 +0000 Subject: [PATCH 03/15] [perf] fix `connect-leak` in fm modulation --- packages/superdough/helpers.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index de64df0e8..58c4aa35e 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -362,9 +362,9 @@ const mod = (freq, range = 1, type = 'sine') => { } osc.start(); - const g = new GainNode(ctx, { gain: range }); + const g = gainNode(range); osc.connect(g); // -range, range - return { node: g, stop: (t) => osc.stop(t) }; + return { node: g, stop: (t) => osc.stop(t), osc: osc }; }; const fm = (frequencyparam, harmonicityRatio, modulationIndex, wave = 'sine') => { const carrfreq = frequencyparam.value; @@ -416,6 +416,11 @@ export function applyFM(param, value, begin) { modulator.connect(envGain); envGain.connect(param); } + fmmod.osc.onended = () => { + envGain.disconnect(); + modulator.disconnect(); + fmmod.osc.disconnect(); + }; } return { stop }; } From f637b8b0dd0c3bbe29c53d128a943b9e6260be9b Mon Sep 17 00:00:00 2001 From: jeromew Date: Thu, 20 Nov 2025 17:40:51 +0000 Subject: [PATCH 04/15] [perf] fix `connect-leak` in fm modulation --- packages/superdough/helpers.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index de64df0e8..58c4aa35e 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -362,9 +362,9 @@ const mod = (freq, range = 1, type = 'sine') => { } osc.start(); - const g = new GainNode(ctx, { gain: range }); + const g = gainNode(range); osc.connect(g); // -range, range - return { node: g, stop: (t) => osc.stop(t) }; + return { node: g, stop: (t) => osc.stop(t), osc: osc }; }; const fm = (frequencyparam, harmonicityRatio, modulationIndex, wave = 'sine') => { const carrfreq = frequencyparam.value; @@ -416,6 +416,11 @@ export function applyFM(param, value, begin) { modulator.connect(envGain); envGain.connect(param); } + fmmod.osc.onended = () => { + envGain.disconnect(); + modulator.disconnect(); + fmmod.osc.disconnect(); + }; } return { stop }; } From e72e26eb81a62bcb9a96dedfa05fb82fac857cca Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 17:11:17 -0500 Subject: [PATCH 05/15] add comment --- packages/core/repl.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 6e3d97c92..bcb70eec9 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -217,6 +217,7 @@ export function repl({ let patterns = []; let soloActive = false; for (const [key, value] of Object.entries(pPatterns)) { + // handle soloed patterns ex: S$: s("bd!4") const isSolod = key.length > 1 && key.startsWith('S'); if (isSolod && soloActive === false) { // first time we see a soloed pattern, clear existing patterns From 19fd0fc649ba8b92271facd3ae9e9e5ac01ebd2c Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 17:17:41 -0500 Subject: [PATCH 06/15] rm unessecary file --- packages/draw/text.mjs | 144 ----------------------------------------- 1 file changed, 144 deletions(-) delete mode 100644 packages/draw/text.mjs diff --git a/packages/draw/text.mjs b/packages/draw/text.mjs deleted file mode 100644 index ba76df079..000000000 --- a/packages/draw/text.mjs +++ /dev/null @@ -1,144 +0,0 @@ -import { Pattern, midiToFreq, getFrequency } from '@strudel/core'; -import { getTheme, getDrawContext } from './draw.mjs'; - -const c = midiToFreq(36); - -const circlePos = (cx, cy, radius, angle) => { - angle = angle * Math.PI * 2; - const x = Math.sin(angle) * radius + cx; - const y = Math.cos(angle) * radius + cy; - return [x, y]; -}; - -const freq2angle = (freq, root) => { - return 0.5 - (Math.log2(freq / root) % 1); -}; - -export function pitchwheel({ - haps, - ctx, - id, - hapcircles = 1, - circle = 0, - edo = 12, - root = c, - thickness = 3, - hapRadius = 6, - mode = 'flake', - margin = 10, -} = {}) { - const connectdots = mode === 'polygon'; - const centerlines = mode === 'flake'; - const w = ctx.canvas.width; - const h = ctx.canvas.height; - ctx.clearRect(0, 0, w, h); - const color = getTheme().foreground; - - const size = Math.min(w, h); - const radius = size / 2 - thickness / 2 - hapRadius - margin; - const centerX = w / 2; - const centerY = h / 2; - - if (id) { - haps = haps.filter((hap) => hap.hasTag(id)); - } - ctx.strokeStyle = color; - ctx.fillStyle = color; - ctx.globalAlpha = 1; - ctx.lineWidth = thickness; - - if (circle) { - ctx.beginPath(); - ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI); - ctx.stroke(); - } - - if (edo) { - Array.from({ length: edo }, (_, i) => { - const angle = freq2angle(root * Math.pow(2, i / edo), root); - const [x, y] = circlePos(centerX, centerY, radius, angle); - ctx.beginPath(); - ctx.arc(x, y, hapRadius, 0, 2 * Math.PI); - ctx.fill(); - }); - ctx.stroke(); - } - - let shape = []; - ctx.lineWidth = hapRadius; - haps.forEach((hap) => { - let freq; - try { - freq = getFrequency(hap); - } catch (err) { - return; - } - const angle = freq2angle(freq, root); - const [x, y] = circlePos(centerX, centerY, radius, angle); - const hapColor = hap.value.color || color; - ctx.strokeStyle = hapColor; - ctx.fillStyle = hapColor; - const { velocity = 1, gain = 1 } = hap.value || {}; - const alpha = velocity * gain; - ctx.globalAlpha = alpha; - shape.push([x, y, angle, hapColor, alpha]); - ctx.beginPath(); - if (hapcircles) { - ctx.moveTo(x + hapRadius, y); - ctx.arc(x, y, hapRadius, 0, 2 * Math.PI); - ctx.fill(); - } - if (centerlines) { - ctx.moveTo(centerX, centerY); - ctx.lineTo(x, y); - } - ctx.stroke(); - }); - - ctx.strokeStyle = color; - ctx.globalAlpha = 1; - if (connectdots && shape.length) { - shape = shape.sort((a, b) => a[2] - b[2]); - ctx.beginPath(); - ctx.moveTo(shape[0][0], shape[0][1]); - shape.forEach(([x, y, _, color, alpha]) => { - ctx.strokeStyle = color; - ctx.globalAlpha = alpha; - ctx.lineTo(x, y); - }); - ctx.lineTo(shape[0][0], shape[0][1]); - ctx.stroke(); - } - - return; -} - -/** - * Renders a pitch circle to visualize frequencies within one octave - * @name pitchwheel - * @param {number} hapcircles - * @param {number} circle - * @param {number} edo - * @param {string} root - * @param {number} thickness - * @param {number} hapRadius - * @param {string} mode - * @param {number} margin - * @example - * n("0 .. 12").scale("C:chromatic") - * .s("sawtooth") - * .lpf(500) - * ._pitchwheel() - */ -Pattern.prototype.pitchwheel = function (options = {}) { - let { ctx = getDrawContext(), id = 1 } = options; - return this.tag(id).onPaint((_, time, haps) => - pitchwheel({ - ...options, - time, - ctx, - haps: haps.filter((hap) => hap.isActive(time)), - id, - }), - ); -}; From 2efd56e33155096dd4454f9fe68e6b5f43bdc1e1 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 18:10:28 -0500 Subject: [PATCH 07/15] add synonym --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 9a2be7f44..8297746dc 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1840,7 +1840,7 @@ export const { octave } = registerControl('octave'); * s("~ sd ~ sd").delay(.5).delaytime(.125).orbit(2) * ) */ -export const { orbit } = registerControl('orbit'); +export const { orbit } = registerControl('orbit', 'o'); // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that export const { overgain } = registerControl('overgain'); // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1 From 1d5f3a4f30c415b53ea1b0a5d88d31d318725631 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 18:21:24 -0500 Subject: [PATCH 08/15] prevent filter modulation pops --- packages/superdough/helpers.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index de64df0e8..8e45f7bca 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -238,7 +238,7 @@ export function createFilter(context, start, end, params, cps) { if (sync != null) { rate = cps * sync; } - const lfoValues = { depth, dcoffset, skew, shape, frequency: rate }; + const lfoValues = { depth, dcoffset, skew, shape, frequency: rate, min: 10, max: 20000 }; getParamLfo(context, frequencyParam, start, end, lfoValues); return filter; } From adc3a9ac6cb780c653c843c5c296c5fbb8f106b0 Mon Sep 17 00:00:00 2001 From: Aria Date: Sat, 22 Nov 2025 20:51:30 -0600 Subject: [PATCH 09/15] Swap with temp variable --- packages/superdough/worklets.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index e60cd223e..bf633a63b 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -543,8 +543,9 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor { if (pn >= 1.0) pn -= 1.0; this.phase[n] = pn; // invert right and left gain + const tmp = gainL; gainL = gainR; - gainR = gainL; + gainR = tmp; } } return true; From 30e672a0271bf3233859230ef96cfe8b9cecc1cd Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 22:49:23 -0500 Subject: [PATCH 10/15] wip --- packages/superdough/helpers.mjs | 27 ++++++++++++++++++++++----- packages/superdough/superdough.mjs | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 8e45f7bca..7bca637f2 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -191,8 +191,10 @@ export function applyParameterModulators(audioContext, param, start, end, envelo const lfo = getParamLfo(audioContext, param, start, end, lfoValues); return { lfo, disconnect: () => lfo?.disconnect() }; } - -export function createFilter(context, start, end, params, cps) { +function biloparExponential(x, k) { + return Math.sign(x) * 2 ** (Math.abs(x) * k); +} +export function createFilter(context, start, end, params, cps, cycle) { let { frequency, anchor, @@ -231,6 +233,7 @@ export function createFilter(context, start, end, params, cps) { const offset = envAbs * anchor; let min = clamp(2 ** -offset * frequency, 0, 20000); let max = clamp(2 ** (envAbs - offset) * frequency, 0, 20000); + if (env < 0) [min, max] = [max, min]; getParamADSR(frequencyParam, attack, decay, sustain, release, min, max, start, end, 'exponential'); } @@ -238,8 +241,22 @@ export function createFilter(context, start, end, params, cps) { if (sync != null) { rate = cps * sync; } - const lfoValues = { depth, dcoffset, skew, shape, frequency: rate, min: 10, max: 20000 }; - getParamLfo(context, frequencyParam, start, end, lfoValues); + const hasLFO = [depth, skew, shape, rate].some((v) => v !== undefined); + if (hasLFO) { + depth = depth ?? 1 + + const mag = Math.abs(depth); + const sign = Math.sign(depth); + + const shaped = 2 ** (mag * (1 - dcoffset)); + const dp = clamp((sign * shaped * frequency) - frequency, -20000, 20000); + console.info(dp) + const time = cycle / cps; + // let d = 2 ** -dcoffset + const lfoValues = { depth: dp, dcoffset, skew, shape, frequency: rate, min: 10, max: 20000, time }; + getParamLfo(context, frequencyParam, start, end, lfoValues); + } + return filter; } @@ -386,7 +403,7 @@ export function applyFM(param, value, begin) { duration, } = value; let modulator; - let stop = () => {}; + let stop = () => { }; if (fmModulationIndex) { const ac = getAudioContext(); diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 650f9c2ce..4e1a145c0 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -559,7 +559,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) }; const lpParams = pickAndRename(value, lpMap); lpParams.type = 'lowpass'; - let lp = () => createFilter(ac, t, end, lpParams, cps); + let lp = () => createFilter(ac, t, end, lpParams, cps, cycle); chain.push(lp()); if (ftype === '24db') { chain.push(lp()); From 7bbb653963ace62fdf7f5aba33600da576927d02 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sat, 22 Nov 2025 23:42:20 -0500 Subject: [PATCH 11/15] fixed --- packages/core/controls.mjs | 7 +++++++ packages/superdough/helpers.mjs | 28 +++++++++++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 9a2be7f44..299169973 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1294,6 +1294,8 @@ export const { fanchor } = registerControl('fanchor'); * * @name lprate * @param {number | Pattern} rate rate in hertz + * @example + * note("*16").s("sawtooth").lpf(600).lprate("<4 8 2 1>") */ export const { lprate } = registerControl('lprate'); @@ -1302,6 +1304,8 @@ export const { lprate } = registerControl('lprate'); * * @name lpsync * @param {number | Pattern} rate rate in cycles + * @example + * note("*16").s("sawtooth").lpf(600).lpsync("<4 8 2 1>") */ export const { lpsync } = registerControl('lpsync'); @@ -1310,7 +1314,10 @@ export const { lpsync } = registerControl('lpsync'); * * @name lpdepth * @param {number | Pattern} depth depth of modulation + * @example + * note("*16").s("sawtooth").lpf(600).lpdepth("<1 .5 1.8 0>") */ + export const { lpdepth } = registerControl('lpdepth'); /** diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 7bca637f2..65f5cc36d 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -191,9 +191,6 @@ export function applyParameterModulators(audioContext, param, start, end, envelo const lfo = getParamLfo(audioContext, param, start, end, lfoValues); return { lfo, disconnect: () => lfo?.disconnect() }; } -function biloparExponential(x, k) { - return Math.sign(x) * 2 ** (Math.abs(x) * k); -} export function createFilter(context, start, end, params, cps, cycle) { let { frequency, @@ -233,7 +230,6 @@ export function createFilter(context, start, end, params, cps, cycle) { const offset = envAbs * anchor; let min = clamp(2 ** -offset * frequency, 0, 20000); let max = clamp(2 ** (envAbs - offset) * frequency, 0, 20000); - if (env < 0) [min, max] = [max, min]; getParamADSR(frequencyParam, attack, decay, sustain, release, min, max, start, end, 'exponential'); } @@ -243,17 +239,19 @@ export function createFilter(context, start, end, params, cps, cycle) { } const hasLFO = [depth, skew, shape, rate].some((v) => v !== undefined); if (hasLFO) { - depth = depth ?? 1 - - const mag = Math.abs(depth); - const sign = Math.sign(depth); - - const shaped = 2 ** (mag * (1 - dcoffset)); - const dp = clamp((sign * shaped * frequency) - frequency, -20000, 20000); - console.info(dp) + depth = depth ?? 1; const time = cycle / cps; - // let d = 2 ** -dcoffset - const lfoValues = { depth: dp, dcoffset, skew, shape, frequency: rate, min: 10, max: 20000, time }; + const lfoValues = { + depth: (depth ?? 1) * frequency, + dcoffset, + skew, + shape, + frequency: rate ?? cps, + min: -frequency + 30, + max: 20000 - frequency, + time, + curve: 1, + }; getParamLfo(context, frequencyParam, start, end, lfoValues); } @@ -403,7 +401,7 @@ export function applyFM(param, value, begin) { duration, } = value; let modulator; - let stop = () => { }; + let stop = () => {}; if (fmModulationIndex) { const ac = getAudioContext(); From bde17594ceae18ed4a483715932b124638b62d72 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sun, 23 Nov 2025 00:33:52 -0500 Subject: [PATCH 12/15] test --- test/__snapshots__/examples.test.mjs.snap | 207 ++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 31e4bddd3..4345eedbf 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -5969,6 +5969,75 @@ exports[`runs examples > example "lpdecay" example index 0 1`] = ` ] `; +exports[`runs examples > example "lpdepth" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 lpdepth:1 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 lpdepth:0.5 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 lpdepth:1.8 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 lpdepth:0 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 lpdepth:0 ]", +] +`; + exports[`runs examples > example "lpenv" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c2 s:sawtooth cutoff:300 lpattack:0.5 lpenv:4 ]", @@ -6157,6 +6226,75 @@ exports[`runs examples > example "lpq" example index 0 1`] = ` ] `; +exports[`runs examples > example "lprate" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 lprate:4 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 lprate:4 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 lprate:4 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 lprate:4 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 lprate:4 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 lprate:4 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 lprate:8 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 lprate:8 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 lprate:8 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 lprate:8 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 lprate:8 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 lprate:8 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 lprate:2 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 lprate:2 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 lprate:2 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 lprate:2 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 lprate:2 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 lprate:2 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 lprate:2 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 lprate:1 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 lprate:1 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 lprate:1 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 lprate:1 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 lprate:1 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 lprate:1 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 lprate:1 ]", +] +`; + exports[`runs examples > example "lprelease" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c2 s:sawtooth clip:0.5 cutoff:300 lpenv:4 lprelease:0.5 release:0.5 ]", @@ -6199,6 +6337,75 @@ exports[`runs examples > example "lpsustain" example index 0 1`] = ` ] `; +exports[`runs examples > example "lpsync" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 lpsync:4 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 lpsync:4 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 lpsync:4 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 lpsync:4 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 lpsync:4 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 lpsync:4 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 lpsync:8 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 lpsync:8 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 lpsync:8 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 lpsync:8 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 lpsync:8 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 lpsync:8 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 lpsync:2 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 lpsync:2 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 lpsync:2 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 lpsync:2 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 lpsync:2 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 lpsync:2 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 lpsync:2 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 lpsync:1 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 lpsync:1 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 lpsync:1 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 lpsync:1 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 lpsync:1 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 lpsync:1 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 lpsync:1 ]", +] +`; + exports[`runs examples > example "lrate" example index 0 1`] = ` [ "[ 0/1 → 1/1 | n:0 s:supersquare leslie:1 lrate:1 ]", From 3b2df0b72510a1a217242fd6281e6a06270e18a5 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sun, 23 Nov 2025 19:05:57 -0500 Subject: [PATCH 13/15] synonym: --- packages/core/controls.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 8297746dc..809a45ab2 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1833,6 +1833,7 @@ export const { octave } = registerControl('octave'); * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects. * * @name orbit + * @synonyms o * @param {number | Pattern} number * @example * stack( From e86850b6d83a16f7a0d7e5a64648d62b0035d18f Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Mon, 24 Nov 2025 11:19:49 -0500 Subject: [PATCH 14/15] frequency mod --- packages/core/controls.mjs | 40 +++++++++++++++++++++++++++++- packages/superdough/helpers.mjs | 7 ++++-- packages/superdough/superdough.mjs | 7 ++++-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 2ff2089df..a9d7cc266 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1319,6 +1319,18 @@ export const { lpsync } = registerControl('lpsync'); */ export const { lpdepth } = registerControl('lpdepth'); +/** + * Depth of the LFO for the lowpass filter, in HZ + * + * @name lpdepthfrequency + * @synonyms + * lpdethfreq + * @param {number | Pattern} depth depth of modulation + * @example + * note("*16").s("sawtooth").lpf(600).lpdepthfrequency("<200 500 100 0>") + */ + +export const { lpdepthfrequency } = registerControl('lpdepthfrequency', 'lpdepthfreq'); /** * Shape of the LFO for the lowpass filter @@ -1368,6 +1380,19 @@ export const { bpsync } = registerControl('bpsync'); */ export const { bpdepth } = registerControl('bpdepth'); +/** + * Depth of the LFO for the bandpass filter, in HZ + * + * @name bpdepthfrequency + * @synonyms + * bpdethfreq + * @param {number | Pattern} depth depth of modulation + * @example + * note("*16").s("sawtooth").lpf(600).bpdepthfrequency("<200 500 100 0>") + */ + +export const { bpdepthfrequency } = registerControl('bpdepthfrequency', 'bpdepthfreq'); + /** * Shape of the LFO for the bandpass filter * @@ -1414,7 +1439,20 @@ export const { hpsync } = registerControl('hpsync'); * @name hpdepth * @param {number | Pattern} depth depth of modulation */ -export const { hpdepth } = registerControl('hpdepth'); +export const { hpdepth, hpdepthfreq } = registerControl('hpdepth'); + +/** + * Depth of the LFO for the hipass filter, in hz + * + * @name hpdepthfrequency + * @synonyms + * hpdethfreq + * @param {number | Pattern} depth depth of modulation + * @example + * note("*16").s("sawtooth").lpf(600).hpdepthfrequency("<200 500 100 0>") + */ + +export const { hpdepthfrequency } = registerControl('hpdepthfrequency', 'hpdepthfreq'); /** * Shape of the LFO for the highpass filter diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 11427dc5b..ad11f595c 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -201,12 +201,14 @@ export function createFilter(context, start, end, params, cps, cycle) { q = 1, drive = 0.69, depth, + depthfrequency, dcoffset = -0.5, skew, shape, rate, sync, } = params; + let frequencyParam, filter; if (model === 'ladder') { filter = getWorklet(context, 'ladder-processor', { frequency, q, drive }); @@ -237,12 +239,13 @@ export function createFilter(context, start, end, params, cps, cycle) { if (sync != null) { rate = cps * sync; } - const hasLFO = [depth, skew, shape, rate].some((v) => v !== undefined); + const hasLFO = [depth, depthfrequency, skew, shape, rate].some((v) => v !== undefined); if (hasLFO) { depth = depth ?? 1; const time = cycle / cps; + const modDepth = depthfrequency ?? (depth ?? 1) * frequency; const lfoValues = { - depth: (depth ?? 1) * frequency, + depth: modDepth, dcoffset, skew, shape, diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 4e1a145c0..e3177c7d6 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -553,6 +553,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) rate: 'lprate', sync: 'lpsync', depth: 'lpdepth', + depthfrequency: 'lpdepthfrequency', shape: 'lpshape', dcoffset: 'lpdc', skew: 'lpskew', @@ -581,13 +582,14 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) rate: 'hprate', sync: 'hpsync', depth: 'hpdepth', + depthfrequency: 'hpdepthfrequency', shape: 'hpshape', dcoffset: 'hpdc', skew: 'hpskew', }; const hpParams = pickAndRename(value, hpMap); hpParams.type = 'highpass'; - let hp = () => createFilter(ac, t, end, hpParams, cps); + let hp = () => createFilter(ac, t, end, hpParams, cps, cycle); chain.push(hp()); if (ftype === '24db') { chain.push(hp()); @@ -609,13 +611,14 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) rate: 'bprate', sync: 'bpsync', depth: 'bpdepth', + depthfrequency: 'bpdepthfrequency', shape: 'bpshape', dcoffset: 'bpdc', skew: 'bpskew', }; const bpParams = pickAndRename(value, bpMap); bpParams.type = 'bandpass'; - let bp = () => createFilter(ac, t, end, bpParams, cps); + let bp = () => createFilter(ac, t, end, bpParams, cps, cycle); chain.push(bp()); if (ftype === '24db') { chain.push(bp()); From 7ee6b933cc032c698eef1ac2bfd5f83eafc4a3ef Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Mon, 24 Nov 2025 11:33:21 -0500 Subject: [PATCH 15/15] add tests --- test/__snapshots__/examples.test.mjs.snap | 207 ++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 4345eedbf..8cbee39da 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1391,6 +1391,75 @@ exports[`runs examples > example "bpdecay" example index 0 1`] = ` ] `; +exports[`runs examples > example "bpdepthfrequency" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 bpdepthfrequency:200 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 bpdepthfrequency:500 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:100 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 bpdepthfrequency:0 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 bpdepthfrequency:0 ]", +] +`; + exports[`runs examples > example "bpenv" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c2 s:sawtooth bandf:500 bpattack:0.5 bpenv:4 ]", @@ -4786,6 +4855,75 @@ exports[`runs examples > example "hpdecay" example index 0 1`] = ` ] `; +exports[`runs examples > example "hpdepthfrequency" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 hpdepthfrequency:200 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 hpdepthfrequency:500 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:100 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 hpdepthfrequency:0 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 hpdepthfrequency:0 ]", +] +`; + exports[`runs examples > example "hpenv" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c2 s:sawtooth hcutoff:500 hpattack:0.5 hpenv:4 ]", @@ -6038,6 +6176,75 @@ exports[`runs examples > example "lpdepth" example index 0 1`] = ` ] `; +exports[`runs examples > example "lpdepthfrequency" example index 0 1`] = ` +[ + "[ 0/1 → 1/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 1/16 → 1/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 1/8 → 3/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 3/16 → 1/4 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 1/4 → 5/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 5/16 → 3/8 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 3/8 → 7/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 7/16 → 1/2 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 1/2 → 9/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 9/16 → 5/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 5/8 → 11/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 11/16 → 3/4 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 3/4 → 13/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 13/16 → 7/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 7/8 → 15/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 15/16 → 1/1 | note:c s:sawtooth cutoff:600 lpdepthfrequency:200 ]", + "[ 1/1 → 17/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 17/16 → 9/8 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 9/8 → 19/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 19/16 → 5/4 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 5/4 → 21/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 21/16 → 11/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 11/8 → 23/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 23/16 → 3/2 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 3/2 → 25/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 25/16 → 13/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 13/8 → 27/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 27/16 → 7/4 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 7/4 → 29/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 29/16 → 15/8 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 15/8 → 31/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 31/16 → 2/1 | note:c s:sawtooth cutoff:600 lpdepthfrequency:500 ]", + "[ 2/1 → 33/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 33/16 → 17/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 17/8 → 35/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 35/16 → 9/4 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 9/4 → 37/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 37/16 → 19/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 19/8 → 39/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 39/16 → 5/2 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 5/2 → 41/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 41/16 → 21/8 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 21/8 → 43/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 43/16 → 11/4 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 11/4 → 45/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 45/16 → 23/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 23/8 → 47/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 47/16 → 3/1 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:100 ]", + "[ 3/1 → 49/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 49/16 → 25/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 25/8 → 51/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 51/16 → 13/4 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 13/4 → 53/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 53/16 → 27/8 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 27/8 → 55/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 55/16 → 7/2 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 7/2 → 57/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 57/16 → 29/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 29/8 → 59/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 59/16 → 15/4 | note:c4 s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 15/4 → 61/16 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 61/16 → 31/8 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 31/8 → 63/16 | note:c# s:sawtooth cutoff:600 lpdepthfrequency:0 ]", + "[ 63/16 → 4/1 | note:c s:sawtooth cutoff:600 lpdepthfrequency:0 ]", +] +`; + exports[`runs examples > example "lpenv" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:c2 s:sawtooth cutoff:300 lpattack:0.5 lpenv:4 ]",