diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 47cdeba2e..9c6d66786 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -2970,8 +2970,22 @@ export const grow = register(
);
/**
- * *EXPERIMENTAL*
+ * *Experimental*
+ *
+ * Inserts a pattern into a list of patterns. On the first repetition it will be inserted at the end of the list, then moved backwards through the list
+ * on successive repetitions. The patterns are added together stepwise, with all repetitions taking place over a single cycle. Using `pace` to set the
+ * number of steps per cycle is therefore usually recommended.
+ *
+ * @return {Pattern}
+ * @example
+ * "[c g]".tour("e f", "e f g", "g f e c").note()
+ .sound("folkharp")
+ .pace(8)
*/
+export const tour = function (pat, ...many) {
+ return pat.tour(...many);
+};
+
Pattern.prototype.tour = function (...many) {
return stepcat(
...[].concat(
@@ -2982,15 +2996,23 @@ Pattern.prototype.tour = function (...many) {
);
};
-export const tour = function (pat, ...many) {
- return pat.tour(...many);
-};
-
-const zip = function (...pats) {
+/**
+ * *Experimental*
+ *
+ * 'zips' together the steps of the provided patterns. This can create a long repetition, taking place over a single, dense cycle.
+ * Using `pace` to set the number of steps per cycle is therefore usually recommended.
+ *
+ * @returns {Pattern}
+ * @example
+ * zip("e f", "e f g", "g [f e] a f4 c").note()
+ .sound("folkharp")
+ .pace(8)
+ */
+export const zip = function (...pats) {
pats = pats.filter((pat) => pat.hasTactus);
const zipped = slowcat(...pats.map((pat) => pat._slow(pat.tactus)));
- // Should maybe use lcm or gcd for tactus?
- return zipped._fast(pats[0].tactus).setTactus(pats[0].tactus);
+ const tactus = lcm(...pats.map((x) => x.tactus));
+ return zipped._fast(tactus).setTactus(tactus);
};
/** Aliases for `stepcat` */
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 611caa6e3..3cd86382c 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -8746,6 +8746,47 @@ exports[`runs examples > example "take" example index 2 1`] = `
]
`;
+exports[`runs examples > example "tour" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:e s:folkharp ]",
+ "[ 1/8 → 1/4 | note:f s:folkharp ]",
+ "[ 1/4 → 3/8 | note:e s:folkharp ]",
+ "[ 3/8 → 1/2 | note:f s:folkharp ]",
+ "[ 1/2 → 5/8 | note:g s:folkharp ]",
+ "[ 5/8 → 3/4 | note:g s:folkharp ]",
+ "[ 3/4 → 7/8 | note:f s:folkharp ]",
+ "[ 7/8 → 1/1 | note:e s:folkharp ]",
+ "[ 1/1 → 9/8 | note:c s:folkharp ]",
+ "[ 9/8 → 19/16 | note:c s:folkharp ]",
+ "[ 19/16 → 5/4 | note:g s:folkharp ]",
+ "[ 5/4 → 11/8 | note:e s:folkharp ]",
+ "[ 11/8 → 3/2 | note:f s:folkharp ]",
+ "[ 3/2 → 13/8 | note:e s:folkharp ]",
+ "[ 13/8 → 7/4 | note:f s:folkharp ]",
+ "[ 7/4 → 15/8 | note:g s:folkharp ]",
+ "[ 15/8 → 31/16 | note:c s:folkharp ]",
+ "[ 31/16 → 2/1 | note:g s:folkharp ]",
+ "[ 2/1 → 17/8 | note:g s:folkharp ]",
+ "[ 17/8 → 9/4 | note:f s:folkharp ]",
+ "[ 9/4 → 19/8 | note:e s:folkharp ]",
+ "[ 19/8 → 5/2 | note:c s:folkharp ]",
+ "[ 5/2 → 21/8 | note:e s:folkharp ]",
+ "[ 21/8 → 11/4 | note:f s:folkharp ]",
+ "[ 11/4 → 45/16 | note:c s:folkharp ]",
+ "[ 45/16 → 23/8 | note:g s:folkharp ]",
+ "[ 23/8 → 3/1 | note:e s:folkharp ]",
+ "[ 3/1 → 25/8 | note:f s:folkharp ]",
+ "[ 25/8 → 13/4 | note:g s:folkharp ]",
+ "[ 13/4 → 27/8 | note:g s:folkharp ]",
+ "[ 27/8 → 7/2 | note:f s:folkharp ]",
+ "[ 7/2 → 29/8 | note:e s:folkharp ]",
+ "[ 29/8 → 15/4 | note:c s:folkharp ]",
+ "[ 15/4 → 61/16 | note:c s:folkharp ]",
+ "[ 61/16 → 31/8 | note:g s:folkharp ]",
+ "[ 31/8 → 4/1 | note:e s:folkharp ]",
+]
+`;
+
exports[`runs examples > example "transpose" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:C2 ]",
@@ -9431,6 +9472,45 @@ exports[`runs examples > example "xfade" example index 0 1`] = `
]
`;
+exports[`runs examples > example "zip" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:e s:folkharp ]",
+ "[ 1/8 → 1/4 | note:e s:folkharp ]",
+ "[ 1/4 → 3/8 | note:g s:folkharp ]",
+ "[ 3/8 → 1/2 | note:f s:folkharp ]",
+ "[ 1/2 → 5/8 | note:f s:folkharp ]",
+ "[ 5/8 → 11/16 | note:f s:folkharp ]",
+ "[ 11/16 → 3/4 | note:e s:folkharp ]",
+ "[ 3/4 → 7/8 | note:e s:folkharp ]",
+ "[ 7/8 → 1/1 | note:g s:folkharp ]",
+ "[ 1/1 → 9/8 | note:a s:folkharp ]",
+ "[ 9/8 → 5/4 | note:f s:folkharp ]",
+ "[ 5/4 → 11/8 | note:e s:folkharp ]",
+ "[ 11/8 → 3/2 | note:f4 s:folkharp ]",
+ "[ 3/2 → 13/8 | note:e s:folkharp ]",
+ "[ 13/8 → 7/4 | note:f s:folkharp ]",
+ "[ 7/4 → 15/8 | note:c s:folkharp ]",
+ "[ 15/8 → 2/1 | note:f s:folkharp ]",
+ "[ 2/1 → 17/8 | note:g s:folkharp ]",
+ "[ 17/8 → 9/4 | note:g s:folkharp ]",
+ "[ 9/4 → 19/8 | note:e s:folkharp ]",
+ "[ 19/8 → 5/2 | note:e s:folkharp ]",
+ "[ 5/2 → 41/16 | note:f s:folkharp ]",
+ "[ 41/16 → 21/8 | note:e s:folkharp ]",
+ "[ 21/8 → 11/4 | note:f s:folkharp ]",
+ "[ 11/4 → 23/8 | note:f s:folkharp ]",
+ "[ 23/8 → 3/1 | note:a s:folkharp ]",
+ "[ 3/1 → 25/8 | note:e s:folkharp ]",
+ "[ 25/8 → 13/4 | note:g s:folkharp ]",
+ "[ 13/4 → 27/8 | note:f4 s:folkharp ]",
+ "[ 27/8 → 7/2 | note:f s:folkharp ]",
+ "[ 7/2 → 29/8 | note:e s:folkharp ]",
+ "[ 29/8 → 15/4 | note:c s:folkharp ]",
+ "[ 15/4 → 31/8 | note:e s:folkharp ]",
+ "[ 31/8 → 4/1 | note:f s:folkharp ]",
+]
+`;
+
exports[`runs examples > example "zoom" example index 0 1`] = `
[
"[ 0/1 → 1/6 | s:hh ]",
diff --git a/website/src/pages/learn/stepwise.mdx b/website/src/pages/learn/stepwise.mdx
index d9181ad33..5c9c38908 100644
--- a/website/src/pages/learn/stepwise.mdx
+++ b/website/src/pages/learn/stepwise.mdx
@@ -8,7 +8,9 @@ import { JsDoc } from '../../docs/JsDoc';
# Stepwise patterning (experimental)
-This is a developing area of strudel, and behaviour might change or be renamed in future versions.
+This is a developing area of strudel, and behaviour might change or be renamed in future versions. Feedback and ideas are welcome!
+
+## Introduction
Usually in strudel, the only reference point for most pattern transformations is the _cycle_. Now it is possible to also work with _steps_, via a growing range of functions.
@@ -20,35 +22,59 @@ With the new stepwise `stepcat` function, the steps of the two patterns will be
-Some stepwise functions don't appear to do very much on their own, for example these two examples of the `expand` function sound the same despite being expanded by different amounts:
+By default, steps are counted according to the 'top level' in mini-notation. For example `"a [b c] d e"` has five events in it per cycle, but is counted as four steps, where `[b c]` is counted as a single step.
+
+However, you can mark a different metrical level to count steps relative to, using a `^` at the start of a sub-pattern. If we do this to the subpattern in our example: `"a [^b c] d e"`, then the pattern is now counted as having _eight_ steps. This is because 'b' and 'c' are each counted as single steps, and the events in the pattenr are twice as long, and so counted as two steps each.
+
+## Pacing the steps
+
+Some stepwise functions don't appear to do very much on their own, for example these two examples of the `expand` function sound exactly the same despite being expanded by different amounts:
-
+
-
+
-The number of steps per cycle is changing, but on its own, that doesn't do anything. You will hear a difference once you use another stepwise function with it though, for example `stepcat`:
+The number of steps per cycle is being changed behind the scenes, but on its own, that doesn't do anything. You will hear a difference however, once you use another stepwise function with it, for example `stepcat`:
-
+
-
+
-You should be able to hear that `expand` increases the duration of the steps of the first subpattern, proportionally.
+You should be able to hear that `expand` increases the duration of the steps of the first subpattern, proportionally to the second one.
You can also change the speed of a pattern to match a given number of steps per cycle, with the `pace` function:
-
+
-
+
-The first example has ten steps, and the second example has 16 steps, with both played at a rate of 8 steps per cycle.
+The first example has ten steps, and the second example has 18 steps, but are then both played a rate of 8 steps per cycle.
-The argument to `expand` can also be patterned, and will be treated in a stepwise fashion where the resulting patterns from the value in the argument will be `stepcat`ted together:
+The argument to `expand` can also be patterned, and will be treated in a stepwise fashion. This means that the patterns from the changing values in the argument will be `stepcat`ted together:
-
+
-This results in a pretty dense pattern, because the different expanded versions are squashed (stepwise) into a single cycle. `pace` is again handy here for slowing down the pattern to a particular number of steps per cycle:
+This results in a dense pattern, because the different expanded versions are squashed into a single cycle. `pace` is again handy here for slowing down the pattern to a particular number of steps per cycle:
-
+
## Stepwise functions