diff --git a/packages/core/euclid.mjs b/packages/core/euclid.mjs
index 45a59783..30871bf9 100644
--- a/packages/core/euclid.mjs
+++ b/packages/core/euclid.mjs
@@ -4,44 +4,49 @@ Copyright (C) 2022 Strudel contributors - see .
*/
-import { Pattern, timeCat } from './pattern.mjs';
+import { Pattern, timeCat, register } from './pattern.mjs';
import bjork from 'bjork';
import { rotate } from './util.mjs';
import Fraction from './fraction.mjs';
-const euclid = (pulses, steps, rotation = 0) => {
- const b = bjork(steps, pulses);
- if (rotation) {
- return rotate(b, -rotation);
- }
- return b;
-};
-
/**
* Changes the structure of the pattern to form an euclidean rhythm.
- * Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers.
- * They were described in 2004 by Godfried Toussaint, a canadian computer scientist.
- * Euclidian rhythms are really useful for computer/algorithmic music because they can accurately
- * describe a large number of rhythms used in the most important music world traditions.
+ * Euclidian rhythms are rhythms obtained using the greatest common
+ * divisor of two numbers. They were described in 2004 by Godfried
+ * Toussaint, a canadian computer scientist. Euclidian rhythms are
+ * really useful for computer/algorithmic music because they can
+ * describe a large number of rhythms with a couple of numbers.
*
* @memberof Pattern
* @name euclid
* @param {number} pulses the number of onsets / beats
* @param {number} steps the number of steps to fill
- * @param {number} rotation (optional) offset in steps
* @returns Pattern
* @example
* // The Cuban tresillo pattern.
* note("c3").euclid(3,8)
*/
+/**
+ * Like `iter`, but has an additional parameter for 'rotating' the resulting sequence.
+ * @memberof Pattern
+ * @name euclidRot
+ * @param {number} pulses the number of onsets / beats
+ * @param {number} steps the number of steps to fill
+ * @param {number} rotation offset in steps
+ * @returns Pattern
+ * @example
+ * // A Samba rhythm necklace from Brazil
+ * note("c3").euclidRot(3,16,14)
+ */
+
/**
* @example // A thirteenth century Persian rhythm called Khafif-e-ramal.
* note("c3").euclid(2,5)
* @example // The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.
* note("c3").euclid(3,4)
* @example // Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.
- * note("c3").euclid(3,5,2)
+ * note("c3").euclidRot(3,5,2)
* @example // A Ruchenitza rhythm used in a Bulgarian folk-dance.
* note("c3").euclid(3,7)
* @example // The Cuban tresillo pattern.
@@ -71,34 +76,55 @@ const euclid = (pulses, steps, rotation = 0) => {
* @example // A common West African bell pattern.
* note("c3").euclid(7,12)
* @example // A Samba rhythm necklace from Brazil.
- * note("c3").euclid(7,16,14)
+ * note("c3").euclidRot(7,16,14)
* @example // A rhythm necklace used in the Central African Republic.
* note("c3").euclid(9,16)
* @example // A rhythm necklace of the Aka Pygmies of Central Africa.
- * note("c3").euclid(11,24,14)
+ * note("c3").euclidRot(11,24,14)
* @example // Another rhythm necklace of the Aka Pygmies of the upper Sangha.
- * note("c3").euclid(13,24,5)
+ * note("c3").euclidRot(13,24,5)
*/
-Pattern.prototype.euclid = function (pulses, steps, rotation = 0) {
- return this.struct(euclid(pulses, steps, rotation));
+
+const _euclidRot = function (pulses, steps, rotation) {
+ const b = bjork(steps, pulses);
+ if (rotation) {
+ return rotate(b, -rotation);
+ }
+ return b;
};
+export const euclid = register('euclid', function (pulses, steps, pat) {
+ return pat.struct(_euclidRot(steps, pulses, 0));
+});
+
+export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], function (pulses, steps, rotation, pat) {
+ return pat.struct(_euclidRot(steps, pulses, rotation));
+});
+
/**
- * Similar to `.euclid`, but each pulse is held until the next pulse, so there will be no gaps.
+ * Similar to `euclid`, but each pulse is held until the next pulse,
+ * so there will be no gaps.
* @name euclidLegato
* @memberof Pattern
* @example
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8)
*/
-Pattern.prototype.euclidLegato = function (pulses, steps, rotation = 0) {
- const bin_pat = euclid(pulses, steps, rotation);
+
+const _euclidLegato = function (pulses, steps, rotation, pat) {
+ const bin_pat = _euclidRot(pulses, steps, rotation);
const firstOne = bin_pat.indexOf(1);
const gapless = rotate(bin_pat, firstOne)
.join('')
.split('1')
.slice(1)
.map((s) => [s.length + 1, true]);
- return this.struct(timeCat(...gapless)).late(Fraction(firstOne).div(steps));
+ return pat.struct(timeCat(...gapless)).late(Fraction(firstOne).div(steps));
};
-export default euclid;
+export const euclidLegato = register(['euclidLegato'], function (pulses, steps, pat) {
+ return _euclidLegato(pulses, steps, 0, pat);
+});
+
+export const euclidLegatoRot = register(['euclidLegatoRot'], function (pulses, steps, rotation, pat) {
+ return _euclidLegato(pulses, steps, rotation, pat);
+});
diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js
index 95752beb..7aa297ad 100644
--- a/packages/mini/krill-parser.js
+++ b/packages/mini/krill-parser.js
@@ -269,17 +269,17 @@ function peg$parse(input, options) {
var peg$e47 = peg$literalExpectation("hush", false);
var peg$f0 = function() { return parseFloat(text()); };
- var peg$f1 = function(chars) { return chars.join("") };
+ var peg$f1 = function(chars) { return new AtomStub(chars.join("")) };
var peg$f2 = function(s) { return s };
var peg$f3 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; };
var peg$f4 = function(a) { return a };
var peg$f5 = function(s) { s.arguments_.alignment = 'slowcat'; return s; };
var peg$f6 = function(a) { return { weight: a} };
- var peg$f7 = function(a) { return { replicate: a } };
- var peg$f8 = function(p, s, r) { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } };
+ var peg$f7 = function(a) { return { replicate: a } };
+ var peg$f8 = function(p, s, r) { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r } } } };
var peg$f9 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } };
var peg$f10 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } };
- var peg$f11 = function(a) { return { operator : { type_: "degradeBy", arguments_ :{ amount:(a? a : 0.5) } } } };
+ var peg$f11 = function(a) { return { operator : { type_: "degradeBy", arguments_ :{ amount:a } } } };
var peg$f12 = function(s, o) { return new ElementStub(s, o);};
var peg$f13 = function(s) { return new PatternStub(s, 'fastcat'); };
var peg$f14 = function(tail) { return { alignment: 'stack', list: tail }; };
@@ -289,7 +289,7 @@ function peg$parse(input, options) {
var peg$f18 = function(sc) { return sc; };
var peg$f19 = function(s) { return { name: "struct", args: { mini:s }}};
var peg$f20 = function(s) { return { name: "target", args : { name:s}}};
- var peg$f21 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: parseInt(p), step:parseInt(s) }}};
+ var peg$f21 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}};
var peg$f22 = function(a) { return { name: "stretch", args :{ amount: a}}};
var peg$f23 = function(a) { return { name: "shift", args :{ amount: "-"+a}}};
var peg$f24 = function(a) { return { name: "shift", args :{ amount: a}}};
@@ -992,7 +992,7 @@ function peg$parse(input, options) {
if (peg$silentFails === 0) { peg$fail(peg$e23); }
}
if (s1 !== peg$FAILED) {
- s2 = peg$parsenumber();
+ s2 = peg$parseslice();
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f4(s2);
@@ -1161,13 +1161,13 @@ function peg$parse(input, options) {
}
if (s1 !== peg$FAILED) {
s2 = peg$parsews();
- s3 = peg$parsenumber();
+ s3 = peg$parseslice_with_modifier();
if (s3 !== peg$FAILED) {
s4 = peg$parsews();
s5 = peg$parsecomma();
if (s5 !== peg$FAILED) {
s6 = peg$parsews();
- s7 = peg$parsenumber();
+ s7 = peg$parseslice_with_modifier();
if (s7 !== peg$FAILED) {
s8 = peg$parsews();
s9 = peg$parsecomma();
@@ -1175,7 +1175,7 @@ function peg$parse(input, options) {
s9 = null;
}
s10 = peg$parsews();
- s11 = peg$parsenumber();
+ s11 = peg$parseslice_with_modifier();
if (s11 === peg$FAILED) {
s11 = null;
}
@@ -1226,7 +1226,7 @@ function peg$parse(input, options) {
if (peg$silentFails === 0) { peg$fail(peg$e30); }
}
if (s1 !== peg$FAILED) {
- s2 = peg$parsenumber();
+ s2 = peg$parseslice();
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f9(s2);
@@ -1254,7 +1254,7 @@ function peg$parse(input, options) {
if (peg$silentFails === 0) { peg$fail(peg$e31); }
}
if (s1 !== peg$FAILED) {
- s2 = peg$parsenumber();
+ s2 = peg$parseslice();
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f10(s2);
@@ -2148,6 +2148,13 @@ function peg$parse(input, options) {
}
+ var AtomStub = function(source)
+ {
+ this.type_ = "atom";
+ this.source_ = source;
+ this.location_ = location();
+ }
+
var PatternStub = function(source, alignment)
{
this.type_ = "pattern";
diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs
index bee60e0c..b79d88d1 100644
--- a/packages/mini/krill.pegjs
+++ b/packages/mini/krill.pegjs
@@ -12,6 +12,13 @@ This program is free software: you can redistribute it and/or modify it under th
{
+ var AtomStub = function(source)
+ {
+ this.type_ = "atom";
+ this.source_ = source;
+ this.location_ = location();
+ }
+
var PatternStub = function(source, alignment)
{
this.type_ = "pattern";
@@ -90,7 +97,7 @@ quote = '"' / "'"
// single step definition (e.g bd)
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_" / ":"
-step = ws chars:step_char+ ws { return chars.join("") }
+step = ws chars:step_char+ ws { return new AtomStub(chars.join("")) }
// define a sub cycle e.g. [1 2, 3 [4]]
sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s }
@@ -99,7 +106,7 @@ sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s }
polymeter = ws "{" ws s:polymeter_stack ws "}" stepsPerCycle:polymeter_steps? ws
{ s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }
-polymeter_steps = "%"a:number
+polymeter_steps = "%"a:slice
{ return a }
// define a step-per-cycle timeline e.g <1 3 [3 5]>. We simply defer to a sequence and
@@ -118,19 +125,19 @@ slice_weight = "@" a:number
{ return { weight: a} }
slice_replicate = "!"a:number
- { return { replicate: a } }
+ { return { replicate: a } }
-slice_bjorklund = "(" ws p:number ws comma ws s:number ws comma? ws r:number? ws ")"
- { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } }
+slice_bjorklund = "(" ws p:slice_with_modifier ws comma ws s:slice_with_modifier ws comma? ws r:slice_with_modifier? ws ")"
+ { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r } } } }
-slice_slow = "/"a:number
+slice_slow = "/"a:slice
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } }
-slice_fast = "*"a:number
+slice_fast = "*"a:slice
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } }
slice_degrade = "?"a:number?
- { return { operator : { type_: "degradeBy", arguments_ :{ amount:(a? a : 0.5) } } } }
+ { return { operator : { type_: "degradeBy", arguments_ :{ amount:a } } } }
// a slice with an modifier applied i.e [bd@4 sd@3]@2 hh]
slice_with_modifier = s:slice o:slice_modifier?
@@ -177,7 +184,7 @@ target = "target" ws quote s:step quote
{ return { name: "target", args : { name:s}}}
bjorklund = "euclid" ws p:int ws s:int ws r:int?
- { return { name: "bjorklund", args :{ pulse: parseInt(p), step:parseInt(s) }}}
+ { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}
slow = "slow" ws a:number
{ return { name: "stretch", args :{ amount: a}}}
diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs
index c0ad106f..21f7314a 100644
--- a/packages/mini/mini.mjs
+++ b/packages/mini/mini.mjs
@@ -14,7 +14,7 @@ function _nextSeed() {
return _seedState++;
} */
-const applyOptions = (parent) => (pat, i) => {
+const applyOptions = (parent, code) => (pat, i) => {
const ast = parent.source_[i];
const options = ast.options_;
const operator = options?.operator;
@@ -26,10 +26,21 @@ const applyOptions = (parent) => (pat, i) => {
if (!legalTypes.includes(type)) {
throw new Error(`mini: stretch: type must be one of ${legalTypes.join('|')} but got ${type}`);
}
- return strudel.reify(pat)[type](amount);
+ return strudel.reify(pat)[type](patternifyAST(amount, code));
}
case 'bjorklund':
- return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
+ if (operator.arguments_.rotation) {
+ return pat.euclidRot(
+ patternifyAST(operator.arguments_.pulse, code),
+ patternifyAST(operator.arguments_.step, code),
+ patternifyAST(operator.arguments_.rotation, code),
+ );
+ } else {
+ return pat.euclid(
+ patternifyAST(operator.arguments_.pulse, code),
+ patternifyAST(operator.arguments_.step, code),
+ );
+ }
case 'degradeBy':
// TODO: find out what is right here
// example:
@@ -51,9 +62,7 @@ const applyOptions = (parent) => (pat, i) => {
operator.arguments_.amount ?? 0.5,
);
*/
- return strudel.reify(pat)._degradeBy(operator.arguments_.amount ?? 0.5);
-
- // TODO: case 'fixed-step': "%"
+ return strudel.reify(pat).degradeBy(operator.arguments_.amount === null ? 0.5 : operator.arguments_.amount);
}
console.warn(`operator "${operator.type_}" not implemented`);
}
@@ -72,57 +81,34 @@ const applyOptions = (parent) => (pat, i) => {
};
function resolveReplications(ast) {
- // the general idea here: x!3 = [x*3]@3
- // could this be made easier?!
- ast.source_ = ast.source_.map((child) => {
- const { replicate, ...options } = child.options_ || {};
- if (!replicate) {
- return child;
- }
- return {
- ...child,
- options_: { ...options, weight: replicate },
- source_: {
- type_: 'pattern',
- arguments_: {
- alignment: 'fastcat',
- },
- source_: [
- {
- type_: 'element',
- source_: child.source_,
- location_: child.location_,
- options_: {
- operator: {
- type_: 'stretch',
- arguments_: { amount: replicate, type: 'fast' },
- },
- },
- },
- ],
- },
- };
- });
+ ast.source_ = strudel.flatten(
+ ast.source_.map((child) => {
+ const { replicate, ...options } = child.options_ || {};
+ if (!replicate) {
+ return [child];
+ }
+ delete child.options_.replicate;
+ return Array(replicate).fill(child);
+ }),
+ );
}
export function patternifyAST(ast, code) {
switch (ast.type_) {
case 'pattern': {
resolveReplications(ast);
- const children = ast.source_.map((child) => patternifyAST(child, code)).map(applyOptions(ast));
+ const children = ast.source_.map((child) => patternifyAST(child, code)).map(applyOptions(ast, code));
const alignment = ast.arguments_.alignment;
if (alignment === 'stack') {
return strudel.stack(...children);
}
if (alignment === 'polymeter') {
// polymeter
- const stepsPerCycle = strudel.Fraction(
- ast.arguments_.stepsPerCycle
- ? ast.arguments_.stepsPerCycle
- : strudel.Fraction(children.length > 0 ? children[0].__weight : 1),
- );
+ const stepsPerCycle = ast.arguments_.stepsPerCycle
+ ? patternifyAST(ast.arguments_.stepsPerCycle, code).fmap((x) => strudel.Fraction(x))
+ : strudel.pure(strudel.Fraction(children.length > 0 ? children[0].__weight : 1));
- const aligned = children.map((child) => child.fast(stepsPerCycle.div(child.__weight || strudel.Fraction(1))));
+ const aligned = children.map((child) => child.fast(stepsPerCycle.fmap((x) => x.div(child.__weight || 1))));
return strudel.stack(...aligned);
}
if (alignment === 'rand') {
@@ -144,38 +130,38 @@ export function patternifyAST(ast, code) {
return pat;
}
const pat = strudel.sequence(...children);
- pat.__weight = strudel.Fraction(children.length);
+ pat.__weight = children.length;
return pat;
}
case 'element': {
+ return patternifyAST(ast.source_, code);
+ }
+ case 'atom': {
if (ast.source_ === '~') {
return strudel.silence;
}
- if (typeof ast.source_ !== 'object') {
- if (!ast.location_) {
- console.warn('no location for', ast);
- return ast.source_;
- }
- const { start, end } = ast.location_;
- const value = !isNaN(Number(ast.source_)) ? Number(ast.source_) : ast.source_;
- // the following line expects the shapeshifter append .withMiniLocation
- // because location_ is only relative to the mini string, but we need it relative to whole code
- // make sure whitespaces are not part of the highlight:
- const actual = code?.split('').slice(start.offset, end.offset).join('');
- const [offsetStart = 0, offsetEnd = 0] = actual
- ? actual.split(ast.source_).map((p) => p.split('').filter((c) => c === ' ').length)
- : [];
- return strudel
- .pure(value)
- .withLocation(
- [start.line, start.column + offsetStart, start.offset + offsetStart],
- [start.line, end.column - offsetEnd, end.offset - offsetEnd],
- );
+ if (!ast.location_) {
+ console.warn('no location for', ast);
+ return ast.source_;
}
- return patternifyAST(ast.source_, code);
+ const { start, end } = ast.location_;
+ const value = !isNaN(Number(ast.source_)) ? Number(ast.source_) : ast.source_;
+ // the following line expects the shapeshifter append .withMiniLocation
+ // because location_ is only relative to the mini string, but we need it relative to whole code
+ // make sure whitespaces are not part of the highlight:
+ const actual = code?.split('').slice(start.offset, end.offset).join('');
+ const [offsetStart = 0, offsetEnd = 0] = actual
+ ? actual.split(ast.source_).map((p) => p.split('').filter((c) => c === ' ').length)
+ : [];
+ return strudel
+ .pure(value)
+ .withLocation(
+ [start.line, start.column + offsetStart, start.offset + offsetStart],
+ [start.line, end.column - offsetEnd, end.offset - offsetEnd],
+ );
}
case 'stretch':
- return patternifyAST(ast.source_, code).slow(ast.arguments_.amount);
+ return patternifyAST(ast.source_, code).slow(patternifyAST(ast.arguments_.amount, code));
/* case 'scale':
let [tonic, scale] = Scale.tokenize(ast.arguments_.scale);
const intervals = Scale.get(scale).intervals;
diff --git a/packages/mini/test/mini.test.mjs b/packages/mini/test/mini.test.mjs
index dacb4fa0..123845ac 100644
--- a/packages/mini/test/mini.test.mjs
+++ b/packages/mini/test/mini.test.mjs
@@ -21,6 +21,21 @@ describe('mini', () => {
expect(minS('a b')).toEqual(['a: 0 - 1/2', 'b: 1/2 - 1']);
expect(minS('a b c')).toEqual(['a: 0 - 1/3', 'b: 1/3 - 2/3', 'c: 2/3 - 1']);
});
+ it('supports fast', () => {
+ expect(minS('a*3 b')).toEqual(minS('[a a a] b'));
+ });
+ it('supports patterned fast', () => {
+ expect(minS('[a*<3 5>]*2')).toEqual(minS('[a a a] [a a a a a]'));
+ });
+ it('supports slow', () => {
+ expect(minS('[a a a]/3 b')).toEqual(minS('a b'));
+ });
+ it('supports patterned slow', () => {
+ expect(minS('[a a a a a a a a]/[2 4]')).toEqual(minS('[a a] a'));
+ });
+ it('supports patterned fast', () => {
+ expect(minS('[a*<3 5>]*2')).toEqual(minS('[a a a] [a a a a a]'));
+ });
it('supports slowcat', () => {
expect(minV('')).toEqual(['a']);
});
@@ -56,10 +71,14 @@ describe('mini', () => {
});
it('supports replication', () => {
expect(minS('a!3 b')).toEqual(['a: 0 - 1/4', 'a: 1/4 - 1/2', 'a: 1/2 - 3/4', 'b: 3/4 - 1']);
+ expect(minS('[]!3 d')).toEqual(minS(' d'));
});
it('supports euclidean rhythms', () => {
expect(minS('a(3, 8)')).toEqual(['a: 0 - 1/8', 'a: 3/8 - 1/2', 'a: 3/4 - 7/8']);
});
+ it('supports patterning euclidean rhythms', () => {
+ expect(minS('[a(<3 5>, <8 16>)]*2')).toEqual(minS('a(3,8) a(5,16)'));
+ });
it('supports the ? operator', () => {
expect(
mini('a?')
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 0bc774fb..533c192c 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -1,5 +1,570 @@
// Vitest Snapshot v1
+exports[`runs examples > example "_euclidRot" example index 0 1`] = `
+[
+ "[ 1/5 → 2/5 | note:c3 ]",
+ "[ 3/5 → 4/5 | note:c3 ]",
+ "[ 6/5 → 7/5 | note:c3 ]",
+ "[ 8/5 → 9/5 | note:c3 ]",
+ "[ 11/5 → 12/5 | note:c3 ]",
+ "[ 13/5 → 14/5 | note:c3 ]",
+ "[ 16/5 → 17/5 | note:c3 ]",
+ "[ 18/5 → 19/5 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 1 1`] = `
+[
+ "[ 1/4 → 1/2 | note:c3 ]",
+ "[ 1/2 → 3/4 | note:c3 ]",
+ "[ 3/4 → 1/1 | note:c3 ]",
+ "[ 5/4 → 3/2 | note:c3 ]",
+ "[ 3/2 → 7/4 | note:c3 ]",
+ "[ 7/4 → 2/1 | note:c3 ]",
+ "[ 9/4 → 5/2 | note:c3 ]",
+ "[ 5/2 → 11/4 | note:c3 ]",
+ "[ 11/4 → 3/1 | note:c3 ]",
+ "[ 13/4 → 7/2 | note:c3 ]",
+ "[ 7/2 → 15/4 | note:c3 ]",
+ "[ 15/4 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 2 1`] = `
+[
+ "[ 1/5 → 2/5 | note:c3 ]",
+ "[ 2/5 → 3/5 | note:c3 ]",
+ "[ 4/5 → 1/1 | note:c3 ]",
+ "[ 6/5 → 7/5 | note:c3 ]",
+ "[ 7/5 → 8/5 | note:c3 ]",
+ "[ 9/5 → 2/1 | note:c3 ]",
+ "[ 11/5 → 12/5 | note:c3 ]",
+ "[ 12/5 → 13/5 | note:c3 ]",
+ "[ 14/5 → 3/1 | note:c3 ]",
+ "[ 16/5 → 17/5 | note:c3 ]",
+ "[ 17/5 → 18/5 | note:c3 ]",
+ "[ 19/5 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 3 1`] = `
+[
+ "[ 1/7 → 2/7 | note:c3 ]",
+ "[ 3/7 → 4/7 | note:c3 ]",
+ "[ 5/7 → 6/7 | note:c3 ]",
+ "[ 8/7 → 9/7 | note:c3 ]",
+ "[ 10/7 → 11/7 | note:c3 ]",
+ "[ 12/7 → 13/7 | note:c3 ]",
+ "[ 15/7 → 16/7 | note:c3 ]",
+ "[ 17/7 → 18/7 | note:c3 ]",
+ "[ 19/7 → 20/7 | note:c3 ]",
+ "[ 22/7 → 23/7 | note:c3 ]",
+ "[ 24/7 → 25/7 | note:c3 ]",
+ "[ 26/7 → 27/7 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 4 1`] = `
+[
+ "[ 0/1 → 1/8 | note:c3 ]",
+ "[ 3/8 → 1/2 | note:c3 ]",
+ "[ 3/4 → 7/8 | note:c3 ]",
+ "[ 1/1 → 9/8 | note:c3 ]",
+ "[ 11/8 → 3/2 | note:c3 ]",
+ "[ 7/4 → 15/8 | note:c3 ]",
+ "[ 2/1 → 17/8 | note:c3 ]",
+ "[ 19/8 → 5/2 | note:c3 ]",
+ "[ 11/4 → 23/8 | note:c3 ]",
+ "[ 3/1 → 25/8 | note:c3 ]",
+ "[ 27/8 → 7/2 | note:c3 ]",
+ "[ 15/4 → 31/8 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 5 1`] = `
+[
+ "[ 0/1 → 1/7 | note:c3 ]",
+ "[ 2/7 → 3/7 | note:c3 ]",
+ "[ 4/7 → 5/7 | note:c3 ]",
+ "[ 6/7 → 1/1 | note:c3 ]",
+ "[ 1/1 → 8/7 | note:c3 ]",
+ "[ 9/7 → 10/7 | note:c3 ]",
+ "[ 11/7 → 12/7 | note:c3 ]",
+ "[ 13/7 → 2/1 | note:c3 ]",
+ "[ 2/1 → 15/7 | note:c3 ]",
+ "[ 16/7 → 17/7 | note:c3 ]",
+ "[ 18/7 → 19/7 | note:c3 ]",
+ "[ 20/7 → 3/1 | note:c3 ]",
+ "[ 3/1 → 22/7 | note:c3 ]",
+ "[ 23/7 → 24/7 | note:c3 ]",
+ "[ 25/7 → 26/7 | note:c3 ]",
+ "[ 27/7 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 6 1`] = `
+[
+ "[ 1/9 → 2/9 | note:c3 ]",
+ "[ 1/3 → 4/9 | note:c3 ]",
+ "[ 5/9 → 2/3 | note:c3 ]",
+ "[ 7/9 → 8/9 | note:c3 ]",
+ "[ 10/9 → 11/9 | note:c3 ]",
+ "[ 4/3 → 13/9 | note:c3 ]",
+ "[ 14/9 → 5/3 | note:c3 ]",
+ "[ 16/9 → 17/9 | note:c3 ]",
+ "[ 19/9 → 20/9 | note:c3 ]",
+ "[ 7/3 → 22/9 | note:c3 ]",
+ "[ 23/9 → 8/3 | note:c3 ]",
+ "[ 25/9 → 26/9 | note:c3 ]",
+ "[ 28/9 → 29/9 | note:c3 ]",
+ "[ 10/3 → 31/9 | note:c3 ]",
+ "[ 32/9 → 11/3 | note:c3 ]",
+ "[ 34/9 → 35/9 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 7 1`] = `
+[
+ "[ 0/1 → 1/11 | note:c3 ]",
+ "[ 3/11 → 4/11 | note:c3 ]",
+ "[ 6/11 → 7/11 | note:c3 ]",
+ "[ 9/11 → 10/11 | note:c3 ]",
+ "[ 1/1 → 12/11 | note:c3 ]",
+ "[ 14/11 → 15/11 | note:c3 ]",
+ "[ 17/11 → 18/11 | note:c3 ]",
+ "[ 20/11 → 21/11 | note:c3 ]",
+ "[ 2/1 → 23/11 | note:c3 ]",
+ "[ 25/11 → 26/11 | note:c3 ]",
+ "[ 28/11 → 29/11 | note:c3 ]",
+ "[ 31/11 → 32/11 | note:c3 ]",
+ "[ 3/1 → 34/11 | note:c3 ]",
+ "[ 36/11 → 37/11 | note:c3 ]",
+ "[ 39/11 → 40/11 | note:c3 ]",
+ "[ 42/11 → 43/11 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 8 1`] = `
+[
+ "[ 1/6 → 1/3 | note:c3 ]",
+ "[ 1/3 → 1/2 | note:c3 ]",
+ "[ 1/2 → 2/3 | note:c3 ]",
+ "[ 2/3 → 5/6 | note:c3 ]",
+ "[ 5/6 → 1/1 | note:c3 ]",
+ "[ 7/6 → 4/3 | note:c3 ]",
+ "[ 4/3 → 3/2 | note:c3 ]",
+ "[ 3/2 → 5/3 | note:c3 ]",
+ "[ 5/3 → 11/6 | note:c3 ]",
+ "[ 11/6 → 2/1 | note:c3 ]",
+ "[ 13/6 → 7/3 | note:c3 ]",
+ "[ 7/3 → 5/2 | note:c3 ]",
+ "[ 5/2 → 8/3 | note:c3 ]",
+ "[ 8/3 → 17/6 | note:c3 ]",
+ "[ 17/6 → 3/1 | note:c3 ]",
+ "[ 19/6 → 10/3 | note:c3 ]",
+ "[ 10/3 → 7/2 | note:c3 ]",
+ "[ 7/2 → 11/3 | note:c3 ]",
+ "[ 11/3 → 23/6 | note:c3 ]",
+ "[ 23/6 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 9 1`] = `
+[
+ "[ 0/1 → 1/7 | note:c3 ]",
+ "[ 2/7 → 3/7 | note:c3 ]",
+ "[ 3/7 → 4/7 | note:c3 ]",
+ "[ 5/7 → 6/7 | note:c3 ]",
+ "[ 6/7 → 1/1 | note:c3 ]",
+ "[ 1/1 → 8/7 | note:c3 ]",
+ "[ 9/7 → 10/7 | note:c3 ]",
+ "[ 10/7 → 11/7 | note:c3 ]",
+ "[ 12/7 → 13/7 | note:c3 ]",
+ "[ 13/7 → 2/1 | note:c3 ]",
+ "[ 2/1 → 15/7 | note:c3 ]",
+ "[ 16/7 → 17/7 | note:c3 ]",
+ "[ 17/7 → 18/7 | note:c3 ]",
+ "[ 19/7 → 20/7 | note:c3 ]",
+ "[ 20/7 → 3/1 | note:c3 ]",
+ "[ 3/1 → 22/7 | note:c3 ]",
+ "[ 23/7 → 24/7 | note:c3 ]",
+ "[ 24/7 → 25/7 | note:c3 ]",
+ "[ 26/7 → 27/7 | note:c3 ]",
+ "[ 27/7 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 10 1`] = `
+[
+ "[ 1/8 → 1/4 | note:c3 ]",
+ "[ 1/4 → 3/8 | note:c3 ]",
+ "[ 1/2 → 5/8 | note:c3 ]",
+ "[ 5/8 → 3/4 | note:c3 ]",
+ "[ 7/8 → 1/1 | note:c3 ]",
+ "[ 9/8 → 5/4 | note:c3 ]",
+ "[ 5/4 → 11/8 | note:c3 ]",
+ "[ 3/2 → 13/8 | note:c3 ]",
+ "[ 13/8 → 7/4 | note:c3 ]",
+ "[ 15/8 → 2/1 | note:c3 ]",
+ "[ 17/8 → 9/4 | note:c3 ]",
+ "[ 9/4 → 19/8 | note:c3 ]",
+ "[ 5/2 → 21/8 | note:c3 ]",
+ "[ 21/8 → 11/4 | note:c3 ]",
+ "[ 23/8 → 3/1 | note:c3 ]",
+ "[ 25/8 → 13/4 | note:c3 ]",
+ "[ 13/4 → 27/8 | note:c3 ]",
+ "[ 7/2 → 29/8 | note:c3 ]",
+ "[ 29/8 → 15/4 | note:c3 ]",
+ "[ 31/8 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 11 1`] = `
+[
+ "[ 0/1 → 1/9 | note:c3 ]",
+ "[ 2/9 → 1/3 | note:c3 ]",
+ "[ 4/9 → 5/9 | note:c3 ]",
+ "[ 2/3 → 7/9 | note:c3 ]",
+ "[ 8/9 → 1/1 | note:c3 ]",
+ "[ 1/1 → 10/9 | note:c3 ]",
+ "[ 11/9 → 4/3 | note:c3 ]",
+ "[ 13/9 → 14/9 | note:c3 ]",
+ "[ 5/3 → 16/9 | note:c3 ]",
+ "[ 17/9 → 2/1 | note:c3 ]",
+ "[ 2/1 → 19/9 | note:c3 ]",
+ "[ 20/9 → 7/3 | note:c3 ]",
+ "[ 22/9 → 23/9 | note:c3 ]",
+ "[ 8/3 → 25/9 | note:c3 ]",
+ "[ 26/9 → 3/1 | note:c3 ]",
+ "[ 3/1 → 28/9 | note:c3 ]",
+ "[ 29/9 → 10/3 | note:c3 ]",
+ "[ 31/9 → 32/9 | note:c3 ]",
+ "[ 11/3 → 34/9 | note:c3 ]",
+ "[ 35/9 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 12 1`] = `
+[
+ "[ 1/11 → 2/11 | note:c3 ]",
+ "[ 3/11 → 4/11 | note:c3 ]",
+ "[ 5/11 → 6/11 | note:c3 ]",
+ "[ 7/11 → 8/11 | note:c3 ]",
+ "[ 9/11 → 10/11 | note:c3 ]",
+ "[ 12/11 → 13/11 | note:c3 ]",
+ "[ 14/11 → 15/11 | note:c3 ]",
+ "[ 16/11 → 17/11 | note:c3 ]",
+ "[ 18/11 → 19/11 | note:c3 ]",
+ "[ 20/11 → 21/11 | note:c3 ]",
+ "[ 23/11 → 24/11 | note:c3 ]",
+ "[ 25/11 → 26/11 | note:c3 ]",
+ "[ 27/11 → 28/11 | note:c3 ]",
+ "[ 29/11 → 30/11 | note:c3 ]",
+ "[ 31/11 → 32/11 | note:c3 ]",
+ "[ 34/11 → 35/11 | note:c3 ]",
+ "[ 36/11 → 37/11 | note:c3 ]",
+ "[ 38/11 → 39/11 | note:c3 ]",
+ "[ 40/11 → 41/11 | note:c3 ]",
+ "[ 42/11 → 43/11 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 13 1`] = `
+[
+ "[ 0/1 → 1/12 | note:c3 ]",
+ "[ 1/4 → 1/3 | note:c3 ]",
+ "[ 5/12 → 1/2 | note:c3 ]",
+ "[ 2/3 → 3/4 | note:c3 ]",
+ "[ 5/6 → 11/12 | note:c3 ]",
+ "[ 1/1 → 13/12 | note:c3 ]",
+ "[ 5/4 → 4/3 | note:c3 ]",
+ "[ 17/12 → 3/2 | note:c3 ]",
+ "[ 5/3 → 7/4 | note:c3 ]",
+ "[ 11/6 → 23/12 | note:c3 ]",
+ "[ 2/1 → 25/12 | note:c3 ]",
+ "[ 9/4 → 7/3 | note:c3 ]",
+ "[ 29/12 → 5/2 | note:c3 ]",
+ "[ 8/3 → 11/4 | note:c3 ]",
+ "[ 17/6 → 35/12 | note:c3 ]",
+ "[ 3/1 → 37/12 | note:c3 ]",
+ "[ 13/4 → 10/3 | note:c3 ]",
+ "[ 41/12 → 7/2 | note:c3 ]",
+ "[ 11/3 → 15/4 | note:c3 ]",
+ "[ 23/6 → 47/12 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 14 1`] = `
+[
+ "[ 1/16 → 1/8 | note:c3 ]",
+ "[ 1/4 → 5/16 | note:c3 ]",
+ "[ 7/16 → 1/2 | note:c3 ]",
+ "[ 5/8 → 11/16 | note:c3 ]",
+ "[ 13/16 → 7/8 | note:c3 ]",
+ "[ 17/16 → 9/8 | note:c3 ]",
+ "[ 5/4 → 21/16 | note:c3 ]",
+ "[ 23/16 → 3/2 | note:c3 ]",
+ "[ 13/8 → 27/16 | note:c3 ]",
+ "[ 29/16 → 15/8 | note:c3 ]",
+ "[ 33/16 → 17/8 | note:c3 ]",
+ "[ 9/4 → 37/16 | note:c3 ]",
+ "[ 39/16 → 5/2 | note:c3 ]",
+ "[ 21/8 → 43/16 | note:c3 ]",
+ "[ 45/16 → 23/8 | note:c3 ]",
+ "[ 49/16 → 25/8 | note:c3 ]",
+ "[ 13/4 → 53/16 | note:c3 ]",
+ "[ 55/16 → 7/2 | note:c3 ]",
+ "[ 29/8 → 59/16 | note:c3 ]",
+ "[ 61/16 → 31/8 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 15 1`] = `
+[
+ "[ 1/8 → 1/4 | note:c3 ]",
+ "[ 1/4 → 3/8 | note:c3 ]",
+ "[ 3/8 → 1/2 | note:c3 ]",
+ "[ 1/2 → 5/8 | note:c3 ]",
+ "[ 5/8 → 3/4 | note:c3 ]",
+ "[ 3/4 → 7/8 | note:c3 ]",
+ "[ 7/8 → 1/1 | note:c3 ]",
+ "[ 9/8 → 5/4 | note:c3 ]",
+ "[ 5/4 → 11/8 | note:c3 ]",
+ "[ 11/8 → 3/2 | note:c3 ]",
+ "[ 3/2 → 13/8 | note:c3 ]",
+ "[ 13/8 → 7/4 | note:c3 ]",
+ "[ 7/4 → 15/8 | note:c3 ]",
+ "[ 15/8 → 2/1 | note:c3 ]",
+ "[ 17/8 → 9/4 | note:c3 ]",
+ "[ 9/4 → 19/8 | note:c3 ]",
+ "[ 19/8 → 5/2 | note:c3 ]",
+ "[ 5/2 → 21/8 | note:c3 ]",
+ "[ 21/8 → 11/4 | note:c3 ]",
+ "[ 11/4 → 23/8 | note:c3 ]",
+ "[ 23/8 → 3/1 | note:c3 ]",
+ "[ 25/8 → 13/4 | note:c3 ]",
+ "[ 13/4 → 27/8 | note:c3 ]",
+ "[ 27/8 → 7/2 | note:c3 ]",
+ "[ 7/2 → 29/8 | note:c3 ]",
+ "[ 29/8 → 15/4 | note:c3 ]",
+ "[ 15/4 → 31/8 | note:c3 ]",
+ "[ 31/8 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 16 1`] = `
+[
+ "[ 1/12 → 1/6 | note:c3 ]",
+ "[ 1/6 → 1/4 | note:c3 ]",
+ "[ 1/3 → 5/12 | note:c3 ]",
+ "[ 1/2 → 7/12 | note:c3 ]",
+ "[ 7/12 → 2/3 | note:c3 ]",
+ "[ 3/4 → 5/6 | note:c3 ]",
+ "[ 11/12 → 1/1 | note:c3 ]",
+ "[ 13/12 → 7/6 | note:c3 ]",
+ "[ 7/6 → 5/4 | note:c3 ]",
+ "[ 4/3 → 17/12 | note:c3 ]",
+ "[ 3/2 → 19/12 | note:c3 ]",
+ "[ 19/12 → 5/3 | note:c3 ]",
+ "[ 7/4 → 11/6 | note:c3 ]",
+ "[ 23/12 → 2/1 | note:c3 ]",
+ "[ 25/12 → 13/6 | note:c3 ]",
+ "[ 13/6 → 9/4 | note:c3 ]",
+ "[ 7/3 → 29/12 | note:c3 ]",
+ "[ 5/2 → 31/12 | note:c3 ]",
+ "[ 31/12 → 8/3 | note:c3 ]",
+ "[ 11/4 → 17/6 | note:c3 ]",
+ "[ 35/12 → 3/1 | note:c3 ]",
+ "[ 37/12 → 19/6 | note:c3 ]",
+ "[ 19/6 → 13/4 | note:c3 ]",
+ "[ 10/3 → 41/12 | note:c3 ]",
+ "[ 7/2 → 43/12 | note:c3 ]",
+ "[ 43/12 → 11/3 | note:c3 ]",
+ "[ 15/4 → 23/6 | note:c3 ]",
+ "[ 47/12 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 17 1`] = `
+[
+ "[ 1/16 → 1/8 | note:c3 ]",
+ "[ 3/16 → 1/4 | note:c3 ]",
+ "[ 5/16 → 3/8 | note:c3 ]",
+ "[ 1/2 → 9/16 | note:c3 ]",
+ "[ 5/8 → 11/16 | note:c3 ]",
+ "[ 3/4 → 13/16 | note:c3 ]",
+ "[ 7/8 → 15/16 | note:c3 ]",
+ "[ 17/16 → 9/8 | note:c3 ]",
+ "[ 19/16 → 5/4 | note:c3 ]",
+ "[ 21/16 → 11/8 | note:c3 ]",
+ "[ 3/2 → 25/16 | note:c3 ]",
+ "[ 13/8 → 27/16 | note:c3 ]",
+ "[ 7/4 → 29/16 | note:c3 ]",
+ "[ 15/8 → 31/16 | note:c3 ]",
+ "[ 33/16 → 17/8 | note:c3 ]",
+ "[ 35/16 → 9/4 | note:c3 ]",
+ "[ 37/16 → 19/8 | note:c3 ]",
+ "[ 5/2 → 41/16 | note:c3 ]",
+ "[ 21/8 → 43/16 | note:c3 ]",
+ "[ 11/4 → 45/16 | note:c3 ]",
+ "[ 23/8 → 47/16 | note:c3 ]",
+ "[ 49/16 → 25/8 | note:c3 ]",
+ "[ 51/16 → 13/4 | note:c3 ]",
+ "[ 53/16 → 27/8 | note:c3 ]",
+ "[ 7/2 → 57/16 | note:c3 ]",
+ "[ 29/8 → 59/16 | note:c3 ]",
+ "[ 15/4 → 61/16 | note:c3 ]",
+ "[ 31/8 → 63/16 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 18 1`] = `
+[
+ "[ 1/16 → 1/8 | note:c3 ]",
+ "[ 1/8 → 3/16 | note:c3 ]",
+ "[ 1/4 → 5/16 | note:c3 ]",
+ "[ 3/8 → 7/16 | note:c3 ]",
+ "[ 1/2 → 9/16 | note:c3 ]",
+ "[ 9/16 → 5/8 | note:c3 ]",
+ "[ 11/16 → 3/4 | note:c3 ]",
+ "[ 13/16 → 7/8 | note:c3 ]",
+ "[ 15/16 → 1/1 | note:c3 ]",
+ "[ 17/16 → 9/8 | note:c3 ]",
+ "[ 9/8 → 19/16 | note:c3 ]",
+ "[ 5/4 → 21/16 | note:c3 ]",
+ "[ 11/8 → 23/16 | note:c3 ]",
+ "[ 3/2 → 25/16 | note:c3 ]",
+ "[ 25/16 → 13/8 | note:c3 ]",
+ "[ 27/16 → 7/4 | note:c3 ]",
+ "[ 29/16 → 15/8 | note:c3 ]",
+ "[ 31/16 → 2/1 | note:c3 ]",
+ "[ 33/16 → 17/8 | note:c3 ]",
+ "[ 17/8 → 35/16 | note:c3 ]",
+ "[ 9/4 → 37/16 | note:c3 ]",
+ "[ 19/8 → 39/16 | note:c3 ]",
+ "[ 5/2 → 41/16 | note:c3 ]",
+ "[ 41/16 → 21/8 | note:c3 ]",
+ "[ 43/16 → 11/4 | note:c3 ]",
+ "[ 45/16 → 23/8 | note:c3 ]",
+ "[ 47/16 → 3/1 | note:c3 ]",
+ "[ 49/16 → 25/8 | note:c3 ]",
+ "[ 25/8 → 51/16 | note:c3 ]",
+ "[ 13/4 → 53/16 | note:c3 ]",
+ "[ 27/8 → 55/16 | note:c3 ]",
+ "[ 7/2 → 57/16 | note:c3 ]",
+ "[ 57/16 → 29/8 | note:c3 ]",
+ "[ 59/16 → 15/4 | note:c3 ]",
+ "[ 61/16 → 31/8 | note:c3 ]",
+ "[ 63/16 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 19 1`] = `
+[
+ "[ 1/24 → 1/12 | note:c3 ]",
+ "[ 1/6 → 5/24 | note:c3 ]",
+ "[ 1/4 → 7/24 | note:c3 ]",
+ "[ 1/3 → 3/8 | note:c3 ]",
+ "[ 5/12 → 11/24 | note:c3 ]",
+ "[ 1/2 → 13/24 | note:c3 ]",
+ "[ 7/12 → 5/8 | note:c3 ]",
+ "[ 17/24 → 3/4 | note:c3 ]",
+ "[ 19/24 → 5/6 | note:c3 ]",
+ "[ 7/8 → 11/12 | note:c3 ]",
+ "[ 23/24 → 1/1 | note:c3 ]",
+ "[ 25/24 → 13/12 | note:c3 ]",
+ "[ 7/6 → 29/24 | note:c3 ]",
+ "[ 5/4 → 31/24 | note:c3 ]",
+ "[ 4/3 → 11/8 | note:c3 ]",
+ "[ 17/12 → 35/24 | note:c3 ]",
+ "[ 3/2 → 37/24 | note:c3 ]",
+ "[ 19/12 → 13/8 | note:c3 ]",
+ "[ 41/24 → 7/4 | note:c3 ]",
+ "[ 43/24 → 11/6 | note:c3 ]",
+ "[ 15/8 → 23/12 | note:c3 ]",
+ "[ 47/24 → 2/1 | note:c3 ]",
+ "[ 49/24 → 25/12 | note:c3 ]",
+ "[ 13/6 → 53/24 | note:c3 ]",
+ "[ 9/4 → 55/24 | note:c3 ]",
+ "[ 7/3 → 19/8 | note:c3 ]",
+ "[ 29/12 → 59/24 | note:c3 ]",
+ "[ 5/2 → 61/24 | note:c3 ]",
+ "[ 31/12 → 21/8 | note:c3 ]",
+ "[ 65/24 → 11/4 | note:c3 ]",
+ "[ 67/24 → 17/6 | note:c3 ]",
+ "[ 23/8 → 35/12 | note:c3 ]",
+ "[ 71/24 → 3/1 | note:c3 ]",
+ "[ 73/24 → 37/12 | note:c3 ]",
+ "[ 19/6 → 77/24 | note:c3 ]",
+ "[ 13/4 → 79/24 | note:c3 ]",
+ "[ 10/3 → 27/8 | note:c3 ]",
+ "[ 41/12 → 83/24 | note:c3 ]",
+ "[ 7/2 → 85/24 | note:c3 ]",
+ "[ 43/12 → 29/8 | note:c3 ]",
+ "[ 89/24 → 15/4 | note:c3 ]",
+ "[ 91/24 → 23/6 | note:c3 ]",
+ "[ 31/8 → 47/12 | note:c3 ]",
+ "[ 95/24 → 4/1 | note:c3 ]",
+]
+`;
+
+exports[`runs examples > example "_euclidRot" example index 20 1`] = `
+[
+ "[ 0/1 → 1/24 | note:c3 ]",
+ "[ 1/12 → 1/8 | note:c3 ]",
+ "[ 1/6 → 5/24 | note:c3 ]",
+ "[ 1/4 → 7/24 | note:c3 ]",
+ "[ 7/24 → 1/3 | note:c3 ]",
+ "[ 3/8 → 5/12 | note:c3 ]",
+ "[ 11/24 → 1/2 | note:c3 ]",
+ "[ 13/24 → 7/12 | note:c3 ]",
+ "[ 5/8 → 2/3 | note:c3 ]",
+ "[ 17/24 → 3/4 | note:c3 ]",
+ "[ 3/4 → 19/24 | note:c3 ]",
+ "[ 5/6 → 7/8 | note:c3 ]",
+ "[ 11/12 → 23/24 | note:c3 ]",
+ "[ 1/1 → 25/24 | note:c3 ]",
+ "[ 13/12 → 9/8 | note:c3 ]",
+ "[ 7/6 → 29/24 | note:c3 ]",
+ "[ 5/4 → 31/24 | note:c3 ]",
+ "[ 31/24 → 4/3 | note:c3 ]",
+ "[ 11/8 → 17/12 | note:c3 ]",
+ "[ 35/24 → 3/2 | note:c3 ]",
+ "[ 37/24 → 19/12 | note:c3 ]",
+ "[ 13/8 → 5/3 | note:c3 ]",
+ "[ 41/24 → 7/4 | note:c3 ]",
+ "[ 7/4 → 43/24 | note:c3 ]",
+ "[ 11/6 → 15/8 | note:c3 ]",
+ "[ 23/12 → 47/24 | note:c3 ]",
+ "[ 2/1 → 49/24 | note:c3 ]",
+ "[ 25/12 → 17/8 | note:c3 ]",
+ "[ 13/6 → 53/24 | note:c3 ]",
+ "[ 9/4 → 55/24 | note:c3 ]",
+ "[ 55/24 → 7/3 | note:c3 ]",
+ "[ 19/8 → 29/12 | note:c3 ]",
+ "[ 59/24 → 5/2 | note:c3 ]",
+ "[ 61/24 → 31/12 | note:c3 ]",
+ "[ 21/8 → 8/3 | note:c3 ]",
+ "[ 65/24 → 11/4 | note:c3 ]",
+ "[ 11/4 → 67/24 | note:c3 ]",
+ "[ 17/6 → 23/8 | note:c3 ]",
+ "[ 35/12 → 71/24 | note:c3 ]",
+ "[ 3/1 → 73/24 | note:c3 ]",
+ "[ 37/12 → 25/8 | note:c3 ]",
+ "[ 19/6 → 77/24 | note:c3 ]",
+ "[ 13/4 → 79/24 | note:c3 ]",
+ "[ 79/24 → 10/3 | note:c3 ]",
+ "[ 27/8 → 41/12 | note:c3 ]",
+ "[ 83/24 → 7/2 | note:c3 ]",
+ "[ 85/24 → 43/12 | note:c3 ]",
+ "[ 29/8 → 11/3 | note:c3 ]",
+ "[ 89/24 → 15/4 | note:c3 ]",
+ "[ 15/4 → 91/24 | note:c3 ]",
+ "[ 23/6 → 31/8 | note:c3 ]",
+ "[ 47/12 → 95/24 | note:c3 ]",
+]
+`;
+
exports[`runs examples > example "accelerate" example index 0 1`] = `
[
"[ (0/1 → 1/1) ⇝ 2/1 | s:sax accelerate:0 ]",
@@ -1544,6 +2109,23 @@ exports[`runs examples > example "euclidLegato" example index 0 1`] = `
]
`;
+exports[`runs examples > example "euclidRot" example index 0 1`] = `
+[
+ "[ 1/4 → 5/16 | note:c3 ]",
+ "[ 9/16 → 5/8 | note:c3 ]",
+ "[ 15/16 → 1/1 | note:c3 ]",
+ "[ 5/4 → 21/16 | note:c3 ]",
+ "[ 25/16 → 13/8 | note:c3 ]",
+ "[ 31/16 → 2/1 | note:c3 ]",
+ "[ 9/4 → 37/16 | note:c3 ]",
+ "[ 41/16 → 21/8 | note:c3 ]",
+ "[ 47/16 → 3/1 | note:c3 ]",
+ "[ 13/4 → 53/16 | note:c3 ]",
+ "[ 57/16 → 29/8 | note:c3 ]",
+ "[ 63/16 → 4/1 | note:c3 ]",
+]
+`;
+
exports[`runs examples > example "every" example index 0 1`] = `
[
"[ 3/4 → 1/1 | note:c3 ]",
diff --git a/website/src/repl/tunes.mjs b/website/src/repl/tunes.mjs
index 88fb60d2..b8bfaa26 100644
--- a/website/src/repl/tunes.mjs
+++ b/website/src/repl/tunes.mjs
@@ -425,7 +425,7 @@ stack(
.scale(cat('D minor pentatonic')).note()
.s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8),
// bass
- "".euclidLegato(6,8,1).note().s('bass').clip(1).gain(.8)
+ "".euclidLegatoRot(6,8,1).note().s('bass').clip(1).gain(.8)
)
.slow(6)
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})