diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 48e52643..d9b63d14 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -734,14 +734,14 @@ export class Pattern {
}
/**
- * Speed up a pattern by the given factor.
+ * Speed up a pattern by the given factor. Used by "*" in mini notation.
*
* @name fast
* @memberof Pattern
* @param {number | Pattern} factor speed up factor
* @returns Pattern
* @example
- * seq(e5, b4, d5, c5).fast(2)
+ * seq(e5, b4, d5, c5).fast(2) // "[e5 b4 d5 c5]*2"
*/
_fast(factor) {
const fastQuery = this.withQueryTime((t) => t.mul(factor));
@@ -749,14 +749,14 @@ export class Pattern {
}
/**
- * Slow down a pattern over the given number of cycles.
+ * Slow down a pattern over the given number of cycles. Like the "/" operator in mini notation.
*
* @name slow
* @memberof Pattern
* @param {number | Pattern} factor slow down factor
* @returns Pattern
* @example
- * seq(e5, b4, d5, c5).slow(2)
+ * seq(e5, b4, d5, c5).slow(2) // "[e5 b4 d5 c5]/2"
*/
_slow(factor) {
return this._fast(Fraction(1).div(factor));
@@ -795,14 +795,32 @@ export class Pattern {
return this._fast(cpm / 60);
}
+ /**
+ * Nudge a pattern to start earlier in time. Equivalent of Tidal's <~ operator
+ *
+ * @name early
+ * @memberof Pattern
+ * @param {number | Pattern} cycles number of cycles to nudge left
+ * @returns Pattern
+ * @example
+ * "bd ~".stack("hh ~".early(.1)).s().out()
+ */
_early(offset) {
- // Equivalent of Tidal's <~ operator
offset = Fraction(offset);
return this.withQueryTime((t) => t.add(offset)).withHapTime((t) => t.sub(offset));
}
+ /**
+ * Nudge a pattern to start later in time. Equivalent of Tidal's ~> operator
+ *
+ * @name late
+ * @memberof Pattern
+ * @param {number | Pattern} cycles number of cycles to nudge right
+ * @returns Pattern
+ * @example
+ * "bd ~".stack("hh ~".late(.1)).s().out()
+ */
_late(offset) {
- // Equivalent of Tidal's ~> operator
offset = Fraction(offset);
return this._early(Fraction(0).sub(offset));
}
@@ -889,12 +907,56 @@ export class Pattern {
return stack(this, func(this.late(time_pat)));
}
+ /**
+ * Applies the given function every n cycles.
+ * @name every
+ * @memberof Pattern
+ * @param {number} n how many cycles
+ * @param {function} func function to apply
+ * @returns Pattern
+ * @example
+ * note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
+ */
+ every(n, func) {
+ const pat = this;
+ const pats = Array(n - 1).fill(pat);
+ // pats.unshift(func(pat));
+ pats.push(func(pat));
+ return slowcatPrime(...pats);
+ }
+ /**
+ * Applies the given function every n cycles, starting from the first cycle.
+ * @name every
+ * @memberof Pattern
+ * @param {number} n how many cycles
+ * @param {function} func function to apply
+ * @returns Pattern
+ * @example
+ * note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
+ */
every(n, func) {
const pat = this;
const pats = Array(n - 1).fill(pat);
pats.unshift(func(pat));
return slowcatPrime(...pats);
}
+
+ /**
+ * Applies the given function every n cycles, starting from the last cycle.
+ * @name each
+ * @memberof Pattern
+ * @param {number} n how many cycles
+ * @param {function} func function to apply
+ * @returns Pattern
+ * @example
+ * note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
+ */
+ each(n, func) {
+ const pat = this;
+ const pats = Array(n - 1).fill(pat);
+ pats.push(func(pat));
+ return slowcatPrime(...pats);
+ }
/**
* Returns a new pattern where every other cycle is played once, twice as
@@ -906,6 +968,15 @@ export class Pattern {
return this.when(slowcat(false, true), (x) => fastcat(x, silence)._late(0.25));
}
+ /**
+ * Reverse all haps in a pattern
+ *
+ * @name rev
+ * @memberof Pattern
+ * @returns Pattern
+ * @example
+ * "c3 d3 e3 g3".rev()
+ */
rev() {
const pat = this;
const query = function (state) {
diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx
index 4b4eecd8..dc963734 100644
--- a/tutorial/tutorial.mdx
+++ b/tutorial/tutorial.mdx
@@ -491,59 +491,72 @@ We can write the same with **stack** and **cat**:
You can also use the shorthand **pr** instead of **polyrhythm**.
-## Pattern modifier functions
+## Time Modifiers
-The following functions modify a pattern.
+The following functions modify a pattern temporal structure in some way.
-### slow(factor)
+{{ 'Pattern.slow' | jsdoc }}
-Like "/" in mini notation, **slow** will slow down a pattern over the given number of cycles:
+{{ 'Pattern.fast' | jsdoc }}
-
+{{ 'Pattern.early' | jsdoc }}
-The same in mini notation:
+{{ 'Pattern.late' | jsdoc }}
-
+{{ 'Pattern.rev' | jsdoc }}
-### fast(factor)
+### struct(binary_pat)
-Like "\*" in mini notation, **fast** will play a pattern times the given number in one cycle:
+Applies the given structure to the pattern:
-
+
-### early(cycles)
+This is also useful to sample signals:
-With early, you can nudge a pattern to start earlier in time:
+
-
+## Conditional Modifiers
-### late(cycles)
+{{ 'Pattern.every' | jsdoc }}
-Like early, but in the other direction:
+{{ 'Pattern.each' | jsdoc }}
-
+### when(binary_pat, func)
-
+Applies the given function whenever the given pattern is in a true state.
-### rev()
+/2", sub(5))`} />
-Will reverse the pattern:
+## Accumulation Modifiers
-
+### stack(pat)
-### every(n, func)
+Stacks the given pattern to the current pattern:
-Will apply the given function every n cycles:
+
-
+### superimpose(...func)
-
+Superimposes the result of the given function(s) on top of the original pattern:
-Note that late is called directly. This is a shortcut for:
+".scale('C minor').superimpose(scaleTranspose("2,4"))`} />
- x.late(0.5)))`} />
+### layer(...func)
-
+Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result.
+
+".scale('C minor').layer(scaleTranspose("0,2,4"))`} />
+
+### off(time, func)
+
+Applies the given function by the given time offset:
+
+
+
+## Value Modifiers
### add(n)
@@ -597,55 +610,12 @@ Rounds all values to the nearest integer:
-### struct(binary_pat)
-
-Applies the given structure to the pattern:
-
-
-
-This is also useful to sample signals:
-
-
-
-### when(binary_pat, func)
-
-Applies the given function whenever the given pattern is in a true state.
-
-/2", sub(5))`} />
-
-### superimpose(...func)
-
-Superimposes the result of the given function(s) on top of the original pattern:
-
-".scale('C minor').superimpose(scaleTranspose("2,4"))`} />
-
-### layer(...func)
-
-Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result.
-
-".scale('C minor').layer(scaleTranspose("0,2,4"))`} />
-
### apply(func)
Like layer, but with a single function:
".scale('C minor').apply(scaleTranspose("0,2,4"))`} />
-### off(time, func)
-
-Applies the given function by the given time offset:
-
-
-
-### stack(pat)
-
-Stacks the given pattern to the current pattern:
-
-
-
## Randomness
These methods add random behavior to your Patterns.