diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index b63a702f8..2c1dcfce9 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1056,7 +1056,55 @@ function _composeOp(a, b, func) { // pattern composers const COMPOSERS = { + /** + * When called on a pattern `a`, with a input pattern `b` (`a.set(b)`), + * combines `a` and `b` such that anything defined in `b` + * and anything defined in `a` that is *not* defined in `b` + * will be in the resulting pattern. + * + * The structure is maintained from `a`, + * because the default pattern alignment is `in`, + * see the section on `Pattern Alignment` + * in the technical manual in the docs + * + * This is the inverse of `keep` + * + * See examples below + * @name set + * @param {Pattern} pat + * @returns {Pattern} + * @memberof Pattern + * @tags internal, combiners + * @example + * // because input pattern has `s` set, + * // it overrides the "sine" declared earlier + * note("c a f e").s("sine").set(s("triangle")) + */ set: [(a, b) => b], + /** + * When called on a pattern `a`, with a input pattern `b` (`a.keep(b)`), + * combines `a` and `b` such that anything defined in `a`, + * and anything defined in `b` that is *not* defined in `a` + * will be in the resulting pattern + * + * The structure is maintained from `a`, + * because the default pattern alignment is `in`, + * see the section on `Pattern Alignment` + * in the technical manual in the docs + * + * This is the inverse of `set` + * + * See examples below + * @name keep + * @param {Pattern} pat + * @memberof Pattern + * @returns {Pattern} + * @tags internal, combiners + * @example + * // notes, already defined, will stay "c a f e", + * // while "s", not defined, will be set to "piano" + * note("c a f e").keep(note("e f a c").s("piano")) + */ keep: [(a) => a], keepif: [(a, b) => (b ? a : undefined)], diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 831e48767..5d19a0bb0 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -3012,15 +3012,6 @@ exports[`runs examples > example "delayfeedback" example index 0 1`] = ` ] `; -exports[`runs examples > example "delayfeedback" example index 0 2`] = ` -[ - "[ 0/1 → 1/1 | s:bd delay:0.25 delayfeedback:0.25 ]", - "[ 1/1 → 2/1 | s:bd delay:0.25 delayfeedback:0.5 ]", - "[ 2/1 → 3/1 | s:bd delay:0.25 delayfeedback:0.75 ]", - "[ 3/1 → 4/1 | s:bd delay:0.25 delayfeedback:1 ]", -] -`; - exports[`runs examples > example "delayspeed" example index 0 1`] = ` [ "[ 0/1 → 1/8 | note:d s:sawtooth delay:0.8 delaytime:0.5 delayspeed:2 ]", @@ -6403,6 +6394,27 @@ exports[`runs examples > example "juxBy" example index 0 1`] = ` ] `; +exports[`runs examples > example "keep" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c s:piano ]", + "[ 1/4 → 1/2 | note:a s:piano ]", + "[ 1/2 → 3/4 | note:f s:piano ]", + "[ 3/4 → 1/1 | note:e s:piano ]", + "[ 1/1 → 5/4 | note:c s:piano ]", + "[ 5/4 → 3/2 | note:a s:piano ]", + "[ 3/2 → 7/4 | note:f s:piano ]", + "[ 7/4 → 2/1 | note:e s:piano ]", + "[ 2/1 → 9/4 | note:c s:piano ]", + "[ 9/4 → 5/2 | note:a s:piano ]", + "[ 5/2 → 11/4 | note:f s:piano ]", + "[ 11/4 → 3/1 | note:e s:piano ]", + "[ 3/1 → 13/4 | note:c s:piano ]", + "[ 13/4 → 7/2 | note:a s:piano ]", + "[ 7/2 → 15/4 | note:f s:piano ]", + "[ 15/4 → 4/1 | note:e s:piano ]", +] +`; + exports[`runs examples > example "keyDown" example index 0 1`] = `[]`; exports[`runs examples > example "lastOf" example index 0 1`] = ` @@ -11110,6 +11122,27 @@ exports[`runs examples > example "seqPLoop" example index 0 1`] = ` ] `; +exports[`runs examples > example "set" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c s:triangle ]", + "[ 1/4 → 1/2 | note:a s:triangle ]", + "[ 1/2 → 3/4 | note:f s:triangle ]", + "[ 3/4 → 1/1 | note:e s:triangle ]", + "[ 1/1 → 5/4 | note:c s:triangle ]", + "[ 5/4 → 3/2 | note:a s:triangle ]", + "[ 3/2 → 7/4 | note:f s:triangle ]", + "[ 7/4 → 2/1 | note:e s:triangle ]", + "[ 2/1 → 9/4 | note:c s:triangle ]", + "[ 9/4 → 5/2 | note:a s:triangle ]", + "[ 5/2 → 11/4 | note:f s:triangle ]", + "[ 11/4 → 3/1 | note:e s:triangle ]", + "[ 3/1 → 13/4 | note:c s:triangle ]", + "[ 13/4 → 7/2 | note:a s:triangle ]", + "[ 7/2 → 15/4 | note:f s:triangle ]", + "[ 15/4 → 4/1 | note:e s:triangle ]", +] +`; + exports[`runs examples > example "setDefaultJoin" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:saw velocity:1 note:F delay:0 ]", diff --git a/website/src/pages/technical-manual/alignment.mdx b/website/src/pages/technical-manual/alignment.mdx index dd3a6db5f..c2a70f1a9 100644 --- a/website/src/pages/technical-manual/alignment.mdx +++ b/website/src/pages/technical-manual/alignment.mdx @@ -1,11 +1,11 @@ --- -title: Pattern Aligment +title: Pattern Alignment layout: ../../layouts/MainLayout.astro --- import { MiniRepl } from '../../docs/MiniRepl'; -# Pattern Aligment & Combination +# Pattern Alignment & Combination One core aspect of Strudel, inherited from Tidal, is the flexible way that patterns can be combined, irrespective of their structure. Its declarative approach means a live coder does not have to think about the details of _how_ this is done, only _what_ is to be done.