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.