From d83139980b3373d26295fa6f49cfe7ca68dfe87c Mon Sep 17 00:00:00 2001 From: Martyn Eggleton Date: Wed, 27 May 2026 21:23:55 +0100 Subject: [PATCH 1/7] Creates a pattern of numbers in base x from a number or pattern of numbers --- packages/core/pattern.mjs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index bf9d8ce0b..e9bc47127 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -4127,3 +4127,30 @@ Pattern.prototype.worklet = function (src, ...inputs) { }; export const worklet = (...args) => pure({}).worklet(...args); + + +/** + * Creates a pattern of numbers in base x from a number or pattern of numbers. + * + * @name base + * @tags generators + * @param {number} n - input number to convert + * @param {number} x - base to convert to defaults to 10 + * @example + * $: note(base("175 543", 10)).scale("c:major").s("saw") + * // $: note("1 7 5 5 4 3").scale("c:major").s("saw") + */ +export const base = (n, x = 10) => { + n = reify(n); + //console.log("base", n, x) + return n.withValue(v => { + let digits = []; + let value = v; + while (value > 0) { + digits.unshift(value % x); + value = Math.floor(value / x); + } + const length = digits.length; + return sequence(digits); + }).squeezeJoin() +}; From f21aeb55bd4c29518d23d7607532a4b19808f4b2 Mon Sep 17 00:00:00 2001 From: Martyn Eggleton Date: Mon, 1 Jun 2026 14:02:20 +0100 Subject: [PATCH 2/7] The base param can be a pattern. We also add a max number of digits to produce for each n --- packages/core/pattern.mjs | 58 +++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index e9bc47127..d0d9404b8 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2028,9 +2028,9 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f const newWhole = !hap.whole ? undefined : new TimeSpan( - newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), - newPart.end.add(hap.whole.end.sub(end).div(factor)), - ); + newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), + newPart.end.add(hap.whole.end.sub(end).div(factor)), + ); return new Hap(newWhole, newPart, hap.value, hap.context); }; return pat.withQuerySpanMaybe(qf).withHap(ef).splitQueries(); @@ -4130,27 +4130,49 @@ export const worklet = (...args) => pure({}).worklet(...args); /** - * Creates a pattern of numbers in base x from a number or pattern of numbers. + * Creates a pattern of numbers in base b from a number or pattern of numbers + * padded & limited to d digits long * * @name base * @tags generators - * @param {number} n - input number to convert - * @param {number} x - base to convert to defaults to 10 + * @param {number} n - number to convert (can be a pattern) + * @param {number} b - base to convert to (defaults to 10) (can be a pattern) + * @param {number} d - max number of digits to produce for each n (defaults to 0 for all) (can be a pattern) * @example - * $: note(base("175 543", 10)).scale("c:major").s("saw") + * $: note(base("7175 543", 10, 3)).scale("c:major").s("saw") * // $: note("1 7 5 5 4 3").scale("c:major").s("saw") */ -export const base = (n, x = 10) => { +export const base = (n, b = 10, d=0) => { n = reify(n); - //console.log("base", n, x) - return n.withValue(v => { - let digits = []; - let value = v; - while (value > 0) { - digits.unshift(value % x); - value = Math.floor(value / x); - } - const length = digits.length; - return sequence(digits); + b = reify(b); + d = reify(d); + + return d.withValue(e => { + return b.withValue(c => { + //console.log("base", n, c) + return n.withValue(v => { + let digits = []; + let value = v; + while (value > 0) { + digits.unshift(value % c); + value = Math.floor(value / c); + } + if (e){ + const l = digits.length + if (l > e){ + digits = digits.slice(-1 * e) + } + /* + if (l < e){ + for (let i = l; i < e; i++) { + digits.unshift("~");//0); //Would like to be padding this but ~- doesn't work + } + console.log("digits", digits) + } + */ + } + return sequence(digits); + }).squeezeJoin() + }).squeezeJoin() }).squeezeJoin() }; From bd68c6a0a7395447282388772c2896080e87333a Mon Sep 17 00:00:00 2001 From: Martyn Eggleton Date: Wed, 3 Jun 2026 12:36:41 +0100 Subject: [PATCH 3/7] Documentation tweak --- packages/core/pattern.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index d0d9404b8..11ae75f08 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -4131,7 +4131,7 @@ export const worklet = (...args) => pure({}).worklet(...args); /** * Creates a pattern of numbers in base b from a number or pattern of numbers - * padded & limited to d digits long + * limited to d digits long from the right * * @name base * @tags generators From 475f17ddfd85691546d5e428f27b1f61283746b0 Mon Sep 17 00:00:00 2001 From: Martyn Eggleton Date: Wed, 3 Jun 2026 21:56:26 +0100 Subject: [PATCH 4/7] base now accepts Arrays which improve compatibility with rockstar-strudel --- packages/core/pattern.mjs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 11ae75f08..d69a04a69 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -4135,7 +4135,7 @@ export const worklet = (...args) => pure({}).worklet(...args); * * @name base * @tags generators - * @param {number} n - number to convert (can be a pattern) + * @param {number} n - number to convert (can be a pattern or array) * @param {number} b - base to convert to (defaults to 10) (can be a pattern) * @param {number} d - max number of digits to produce for each n (defaults to 0 for all) (can be a pattern) * @example @@ -4143,13 +4143,15 @@ export const worklet = (...args) => pure({}).worklet(...args); * // $: note("1 7 5 5 4 3").scale("c:major").s("saw") */ export const base = (n, b = 10, d=0) => { + if(Array.isArray(n)){ + n = sequence(n); + } n = reify(n); b = reify(b); d = reify(d); return d.withValue(e => { return b.withValue(c => { - //console.log("base", n, c) return n.withValue(v => { let digits = []; let value = v; @@ -4158,21 +4160,21 @@ export const base = (n, b = 10, d=0) => { value = Math.floor(value / c); } if (e){ - const l = digits.length + const l = digits.length; if (l > e){ - digits = digits.slice(-1 * e) + digits = digits.slice(-1 * e); } /* if (l < e){ for (let i = l; i < e; i++) { digits.unshift("~");//0); //Would like to be padding this but ~- doesn't work } - console.log("digits", digits) + console.log("digits", digits); } */ } return sequence(digits); - }).squeezeJoin() - }).squeezeJoin() - }).squeezeJoin() + }).squeezeJoin(); + }).squeezeJoin(); + }).squeezeJoin(); }; From 6870b04fb2af8ce73a0af441d8a3ae35038290f7 Mon Sep 17 00:00:00 2001 From: Martyn Eggleton Date: Sun, 21 Jun 2026 13:49:11 +0100 Subject: [PATCH 5/7] Pretty code now --- packages/core/pattern.mjs | 57 +++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 5aea0c11a..aa5e1060f 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2028,9 +2028,9 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f const newWhole = !hap.whole ? undefined : new TimeSpan( - newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), - newPart.end.add(hap.whole.end.sub(end).div(factor)), - ); + newPart.begin.sub(begin.sub(hap.whole.begin).div(factor)), + newPart.end.add(hap.whole.end.sub(end).div(factor)), + ); return new Hap(newWhole, newPart, hap.value, hap.context); }; return pat.withQuerySpanMaybe(qf).withHap(ef).splitQueries(); @@ -4133,7 +4133,6 @@ Pattern.prototype.worklet = function (src, ...inputs) { export const worklet = (...args) => pure({}).worklet(...args); - /** * Creates a pattern of numbers in base b from a number or pattern of numbers * limited to d digits long from the right @@ -4147,29 +4146,32 @@ export const worklet = (...args) => pure({}).worklet(...args); * $: note(base("7175 543", 10, 3)).scale("c:major").s("saw") * // $: note("1 7 5 5 4 3").scale("c:major").s("saw") */ -export const base = (n, b = 10, d=0) => { - if(Array.isArray(n)){ +export const base = (n, b = 10, d = 0) => { + if (Array.isArray(n)) { n = sequence(n); } n = reify(n); b = reify(b); d = reify(d); - return d.withValue(e => { - return b.withValue(c => { - return n.withValue(v => { - let digits = []; - let value = v; - while (value > 0) { - digits.unshift(value % c); - value = Math.floor(value / c); - } - if (e){ - const l = digits.length; - if (l > e){ - digits = digits.slice(-1 * e); - } - /* + return d + .withValue((e) => { + return b + .withValue((c) => { + return n + .withValue((v) => { + let digits = []; + let value = v; + while (value > 0) { + digits.unshift(value % c); + value = Math.floor(value / c); + } + if (e) { + const l = digits.length; + if (l > e) { + digits = digits.slice(-1 * e); + } + /* if (l < e){ for (let i = l; i < e; i++) { digits.unshift("~");//0); //Would like to be padding this but ~- doesn't work @@ -4177,9 +4179,12 @@ export const base = (n, b = 10, d=0) => { console.log("digits", digits); } */ - } - return sequence(digits); - }).squeezeJoin(); - }).squeezeJoin(); - }).squeezeJoin(); + } + return sequence(digits); + }) + .squeezeJoin(); + }) + .squeezeJoin(); + }) + .squeezeJoin(); }; From a7c3407da7056a35c3a90ecabd4498f970373561 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 21 Jun 2026 13:54:38 +0100 Subject: [PATCH 6/7] codeformat --- packages/mqtt/mqtt.mjs | 5 +++-- website/src/pages/workshop/motors.mdx | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/mqtt/mqtt.mjs b/packages/mqtt/mqtt.mjs index a84628567..c0a958cfd 100644 --- a/packages/mqtt/mqtt.mjs +++ b/packages/mqtt/mqtt.mjs @@ -119,9 +119,10 @@ Pattern.prototype.mqtt = function ( }); }; - // This adds the 'move' and 'motor' commands to strudel -export const { move, motor } = createParams('move', 'motor'); window.move = move; window.motor = motor; +export const { move, motor } = createParams('move', 'motor'); +window.move = move; +window.motor = motor; // This adds the 'robot' command Pattern.prototype.robot = function (robot_id, address = 'ws://192.168.8.248:9001/mqtt') { return this.mqtt(undefined, undefined, '/move/' + robot_id, address); diff --git a/website/src/pages/workshop/motors.mdx b/website/src/pages/workshop/motors.mdx index 9d679dee9..761763be8 100644 --- a/website/src/pages/workshop/motors.mdx +++ b/website/src/pages/workshop/motors.mdx @@ -35,7 +35,7 @@ Let's get a motor running! 3. Plug a motor into 'servo' (not motor) plug numbered 1, with the yellow (lightest) cable closest to the '1', and the brown (darkest) cable outward -4. Run the below to set up some values, changing the `x` in 'robot('x')` to the letter on your microcontroller. +4. Run the below to set up some values, changing the `x` in 'robot('x')` to the letter on your microcontroller. - - From 19cb3dedc22c486367b748e7ab3635522274c357 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 21 Jun 2026 14:02:34 +0100 Subject: [PATCH 7/7] snapshot --- test/__snapshots__/examples.test.mjs.snap | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index f465f06bf..9ff81763c 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -1242,6 +1242,35 @@ exports[`runs examples > example "bank" example index 0 1`] = ` ] `; +exports[`runs examples > example "base" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:D3 s:saw ]", + "[ 1/6 → 1/3 | note:C4 s:saw ]", + "[ 1/3 → 1/2 | note:A3 s:saw ]", + "[ 1/2 → 2/3 | note:A3 s:saw ]", + "[ 2/3 → 5/6 | note:G3 s:saw ]", + "[ 5/6 → 1/1 | note:F3 s:saw ]", + "[ 1/1 → 7/6 | note:D3 s:saw ]", + "[ 7/6 → 4/3 | note:C4 s:saw ]", + "[ 4/3 → 3/2 | note:A3 s:saw ]", + "[ 3/2 → 5/3 | note:A3 s:saw ]", + "[ 5/3 → 11/6 | note:G3 s:saw ]", + "[ 11/6 → 2/1 | note:F3 s:saw ]", + "[ 2/1 → 13/6 | note:D3 s:saw ]", + "[ 13/6 → 7/3 | note:C4 s:saw ]", + "[ 7/3 → 5/2 | note:A3 s:saw ]", + "[ 5/2 → 8/3 | note:A3 s:saw ]", + "[ 8/3 → 17/6 | note:G3 s:saw ]", + "[ 17/6 → 3/1 | note:F3 s:saw ]", + "[ 3/1 → 19/6 | note:D3 s:saw ]", + "[ 19/6 → 10/3 | note:C4 s:saw ]", + "[ 10/3 → 7/2 | note:A3 s:saw ]", + "[ 7/2 → 11/3 | note:A3 s:saw ]", + "[ 11/3 → 23/6 | note:G3 s:saw ]", + "[ 23/6 → 4/1 | note:F3 s:saw ]", +] +`; + exports[`runs examples > example "beat" example index 0 1`] = ` [ "[ 0/1 → 1/16 | s:bd ]",