From 4229d673c9f8cbf91980d2a67a9423ea1e97cf20 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 18:21:56 +0100 Subject: [PATCH 01/16] basic community oven --- website/src/components/Oven/Oven.jsx | 47 ++++++++++++++++++++++ website/src/config.ts | 1 + website/src/pages/oven.astro | 60 ++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 website/src/components/Oven/Oven.jsx create mode 100644 website/src/pages/oven.astro diff --git a/website/src/components/Oven/Oven.jsx b/website/src/components/Oven/Oven.jsx new file mode 100644 index 00000000..7cb2e7a7 --- /dev/null +++ b/website/src/components/Oven/Oven.jsx @@ -0,0 +1,47 @@ +import { useState, useEffect } from 'react'; +import { loadFeaturedPatterns, loadPublicPatterns } from '@src/repl/util.mjs'; +import { MiniRepl } from '@src/docs/MiniRepl'; +import { PatternLabel } from '@src/repl/panel/PatternsTab'; + +function PatternList({ patterns }) { + return ( +
+ {patterns.map((pat) => ( +
+
+

+ + + +

+
+ {/* */} + {/*
{JSON.stringify(pat)}
*/} +
+ ))} +
+ ); +} + +export function Oven() { + const [featuredPatterns, setFeaturedPatterns] = useState([]); + const [publicPatterns, setPublicPatterns] = useState([]); + useEffect(() => { + loadPublicPatterns().then(({ data: pats }) => { + console.log('pats', pats); + setPublicPatterns(pats); + }); + loadFeaturedPatterns().then(({ data: pats }) => { + console.log('pats', pats); + setFeaturedPatterns(pats); + }); + }, []); + return ( +
+ + +

Last Creations

+ +
+ ); +} diff --git a/website/src/config.ts b/website/src/config.ts index effc593c..3eab0a2a 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -58,6 +58,7 @@ export const SIDEBAR: Sidebar = { { text: 'What is Strudel?', link: 'workshop/getting-started' }, { text: 'Showcase', link: 'intro/showcase' }, { text: 'Blog', link: 'blog' }, + { text: 'Community Oven', link: 'oven' }, ], Workshop: [ // { text: 'Getting Started', link: 'workshop/getting-started' }, diff --git a/website/src/pages/oven.astro b/website/src/pages/oven.astro new file mode 100644 index 00000000..b6961f60 --- /dev/null +++ b/website/src/pages/oven.astro @@ -0,0 +1,60 @@ +--- +import HeadCommon from '../components/HeadCommon.astro'; +import Header from '../components/Header/Header.astro'; +import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; +import PageContent from '../components/PageContent/PageContent.astro'; +import { getCollection } from 'astro:content'; +import { compareDesc } from 'date-fns'; +import { Oven as CommunityOven } from '../components/Oven/Oven.jsx'; +import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; + +const currentPage = Astro.url.pathname; + +const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.date, b.data.date)); +--- + + + + + 🌀 Strudel Community Oven + + + +
+
+
+
+
+
+ + +

Community Oven

+

+ This page contains all the strudels baked by the community.
Add your own by clicking the "Share" button + in the REPL +

+ +
+ +
+
+
+ + From c6f3a8b7c72af1c40b6622d147d1d2eb964524ac Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 18:30:57 +0100 Subject: [PATCH 02/16] more text --- website/src/pages/oven.astro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/pages/oven.astro b/website/src/pages/oven.astro index b6961f60..4410e283 100644 --- a/website/src/pages/oven.astro +++ b/website/src/pages/oven.astro @@ -32,8 +32,8 @@ const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.da

Community Oven

- This page contains all the strudels baked by the community.
Add your own by clicking the "Share" button - in the REPL + This page contains all the strudel patterns baked by the community. Add your own by clicking the "Share" + button in the REPL. Have fun, and please share some of what you create with the community.

From 4f7415b0ec20c319bfc29f12eaa3cb067717d43e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 21:31:21 +0100 Subject: [PATCH 03/16] rename --- website/src/config.ts | 2 +- website/src/pages/oven.astro | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/config.ts b/website/src/config.ts index 3eab0a2a..a5cbcb62 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -58,7 +58,7 @@ export const SIDEBAR: Sidebar = { { text: 'What is Strudel?', link: 'workshop/getting-started' }, { text: 'Showcase', link: 'intro/showcase' }, { text: 'Blog', link: 'blog' }, - { text: 'Community Oven', link: 'oven' }, + { text: 'Community Bakery', link: 'oven' }, ], Workshop: [ // { text: 'Getting Started', link: 'workshop/getting-started' }, diff --git a/website/src/pages/oven.astro b/website/src/pages/oven.astro index 4410e283..40c1c54f 100644 --- a/website/src/pages/oven.astro +++ b/website/src/pages/oven.astro @@ -16,7 +16,7 @@ const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.da - 🌀 Strudel Community Oven + 🌀 Strudel Community Bakery @@ -30,7 +30,7 @@ const posts = (await getCollection('blog')).sort((a, b) => compareDesc(a.data.da -

Community Oven

+

Community Bakery

This page contains all the strudel patterns baked by the community. Add your own by clicking the "Share" button in the REPL. Have fun, and please share some of what you create with the community. From 6667738dc9c46d5dde0d837031a1df2ef726f158 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 18 Jan 2024 21:34:20 +0100 Subject: [PATCH 04/16] more rename --- website/src/config.ts | 2 +- website/src/pages/{oven.astro => bakery.astro} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename website/src/pages/{oven.astro => bakery.astro} (100%) diff --git a/website/src/config.ts b/website/src/config.ts index a5cbcb62..adbcc7f0 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -58,7 +58,7 @@ export const SIDEBAR: Sidebar = { { text: 'What is Strudel?', link: 'workshop/getting-started' }, { text: 'Showcase', link: 'intro/showcase' }, { text: 'Blog', link: 'blog' }, - { text: 'Community Bakery', link: 'oven' }, + { text: 'Community Bakery', link: 'bakery' }, ], Workshop: [ // { text: 'Getting Started', link: 'workshop/getting-started' }, diff --git a/website/src/pages/oven.astro b/website/src/pages/bakery.astro similarity index 100% rename from website/src/pages/oven.astro rename to website/src/pages/bakery.astro From 9ffbc06cf926f1e81366619902956960775e0156 Mon Sep 17 00:00:00 2001 From: Renzo Torr- <56176668+geikha@users.noreply.github.com> Date: Fri, 19 Jan 2024 02:45:54 -0300 Subject: [PATCH 05/16] add pickF and pickmodF allows to pick functions via a pattern of numbers, to apply to another pattern --- packages/core/signal.mjs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 253458ce..bdf01d9b 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -214,6 +214,32 @@ export const pickmod = register('pickmod', function (lookup, pat) { return _pick(lookup, pat, true).innerJoin(); }); +/** * pickF lets you use a pattern of numbers to pick which function to apply to another pattern. + * @param {Pattern} pat + * @param {Pattern} lookup a pattern of indices + * @param {function[]} funcs the array of functions from which to pull + * @returns {Pattern} + * @example + * s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)]) + * @example + * note("(3,8)").s("square") + * .pickF("<0 2> 1", [jux(rev),fast(2),x=>x.lpf(800)]) + */ +export const pickF = register('pickF', function (lookup, funcs, pat) { + return pat.apply(pick(lookup, funcs)); +}); + +/** * The same as `pickF`, but if you pick a number greater than the size of the functions list, + * it wraps around, rather than sticking at the maximum value. +* @param {Pattern} pat +* @param {Pattern} lookup a pattern of indices +* @param {function[]} funcs the array of functions from which to pull +* @returns {Pattern} + */ +export const pickmodF = register('pickmodF', function (lookup, funcs, pat) { + return pat.apply(pickmod(lookup, funcs)); +}); + /** /** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). * Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern. From 491c99c3487f9893490cfd432e52d997e092a661 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Fri, 19 Jan 2024 14:10:47 +0000 Subject: [PATCH 06/16] Mini-notation additions towards tidal compatibility (#926) - `.` feet now work, e.g. `"a b c . d e . f"` is the same as `"[a b c] [d e] [f]"` - `_` elongation now works, e.g. `"a _ _ b"` is the same as `"a@3 b"` (`"a @ @ b"` also works, like in tidal) - standalone `!` now works, e.g. `"a ! ! b"` is the same as `"a!3 b"` Reworks #47 and #49 Ref #30 --- packages/mini/krill-parser.js | 289 +++++++++++++++++++++---------- packages/mini/krill.pegjs | 20 ++- packages/mini/mini.mjs | 3 + packages/mini/test/mini.test.mjs | 14 ++ 4 files changed, 223 insertions(+), 103 deletions(-) diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index ac9e8309..b482d96c 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -288,48 +288,50 @@ function peg$parse(input, options) { var peg$f0 = function() { return parseFloat(text()); }; var peg$f1 = function() { return parseInt(text()); }; - var peg$f2 = function(chars) { return new AtomStub(chars.join("")) }; - var peg$f3 = function(s) { return s }; - var peg$f4 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }; - var peg$f5 = function(a) { return a }; - var peg$f6 = function(s) { s.arguments_.alignment = 'polymeter_slowcat'; return s; }; - var peg$f7 = function(a) { return x => x.options_['weight'] = a }; - var peg$f8 = function(a) { return x => x.options_['reps'] = a }; - var peg$f9 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; - var peg$f10 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; - var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; - var peg$f12 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; - var peg$f13 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; - var peg$f14 = function(s) { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) }; - var peg$f15 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); + var peg$f2 = function(chars) { const s = chars.join(""); return (s === ".") || (s === "_") }; + var peg$f3 = function(chars) { return new AtomStub(chars.join("")) }; + var peg$f4 = function(s) { return s }; + var peg$f5 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }; + var peg$f6 = function(a) { return a }; + var peg$f7 = function(s) { s.arguments_.alignment = 'polymeter_slowcat'; return s; }; + var peg$f8 = function(a) { return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 }; + var peg$f9 = function(a) { return x => x.options_['reps'] = (x.options_['reps'] ?? 1) + (a ?? 2) - 1 }; + var peg$f10 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; + var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; + var peg$f12 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; + var peg$f13 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; + var peg$f14 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; + var peg$f15 = function(s) { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) }; + var peg$f16 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); for (const op of ops) { op(result); } return result; }; - var peg$f16 = function(s) { return new PatternStub(s, 'fastcat'); }; - var peg$f17 = function(tail) { return { alignment: 'stack', list: tail }; }; - var peg$f18 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; - var peg$f19 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; - var peg$f20 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; - var peg$f21 = function(sc) { return sc; }; - var peg$f22 = function(s) { return { name: "struct", args: { mini:s }}}; - var peg$f23 = function(s) { return { name: "target", args : { name:s}}}; - var peg$f24 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}; - var peg$f25 = function(a) { return { name: "stretch", args :{ amount: a}}}; - var peg$f26 = function(a) { return { name: "shift", args :{ amount: "-"+a}}}; - var peg$f27 = function(a) { return { name: "shift", args :{ amount: a}}}; - var peg$f28 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}}; - var peg$f29 = function(s) { return { name: "scale", args :{ scale: s.join("")}}}; - var peg$f30 = function(s, v) { return v}; - var peg$f31 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); }; - var peg$f32 = function(sg) {return sg}; - var peg$f33 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)}; - var peg$f34 = function(sc) { return sc }; - var peg$f35 = function(c) { return c }; - var peg$f36 = function(v) { return new CommandStub("setcps", { value: v})}; - var peg$f37 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})}; - var peg$f38 = function() { return new CommandStub("hush")}; + var peg$f17 = function(s) { return new PatternStub(s, 'fastcat'); }; + var peg$f18 = function(tail) { return { alignment: 'stack', list: tail }; }; + var peg$f19 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; + var peg$f20 = function(tail) { return { alignment: 'feet', list: tail, seed: seed++ }; }; + var peg$f21 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; + var peg$f22 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; + var peg$f23 = function(sc) { return sc; }; + var peg$f24 = function(s) { return { name: "struct", args: { mini:s }}}; + var peg$f25 = function(s) { return { name: "target", args : { name:s}}}; + var peg$f26 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}; + var peg$f27 = function(a) { return { name: "stretch", args :{ amount: a}}}; + var peg$f28 = function(a) { return { name: "shift", args :{ amount: "-"+a}}}; + var peg$f29 = function(a) { return { name: "shift", args :{ amount: a}}}; + var peg$f30 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}}; + var peg$f31 = function(s) { return { name: "scale", args :{ scale: s.join("")}}}; + var peg$f32 = function(s, v) { return v}; + var peg$f33 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); }; + var peg$f34 = function(sg) {return sg}; + var peg$f35 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)}; + var peg$f36 = function(sc) { return sc }; + var peg$f37 = function(c) { return c }; + var peg$f38 = function(v) { return new CommandStub("setcps", { value: v})}; + var peg$f39 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})}; + var peg$f40 = function() { return new CommandStub("hush")}; var peg$currPos = 0; var peg$savedPos = 0; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -821,6 +823,30 @@ function peg$parse(input, options) { return s0; } + function peg$parsedot() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + s1 = peg$parsews(); + if (input.charCodeAt(peg$currPos) === 46) { + s2 = peg$c0; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e1); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + function peg$parsequote() { var s0; @@ -913,7 +939,7 @@ function peg$parse(input, options) { } function peg$parsestep() { - var s0, s1, s2, s3; + var s0, s1, s2, s3, s4; s0 = peg$currPos; s1 = peg$parsews(); @@ -929,8 +955,20 @@ function peg$parse(input, options) { } if (s2 !== peg$FAILED) { s3 = peg$parsews(); - peg$savedPos = s0; - s0 = peg$f2(s2); + peg$savedPos = peg$currPos; + s4 = peg$f2(s2); + if (s4) { + s4 = peg$FAILED; + } else { + s4 = undefined; + } + if (s4 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f3(s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } } else { peg$currPos = s0; s0 = peg$FAILED; @@ -966,7 +1004,7 @@ function peg$parse(input, options) { if (s6 !== peg$FAILED) { s7 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f3(s4); + s0 = peg$f4(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1014,7 +1052,7 @@ function peg$parse(input, options) { } s8 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f4(s4, s7); + s0 = peg$f5(s4, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1046,7 +1084,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f5(s2); + s0 = peg$f6(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1086,7 +1124,7 @@ function peg$parse(input, options) { if (s6 !== peg$FAILED) { s7 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f6(s4); + s0 = peg$f7(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1150,25 +1188,33 @@ function peg$parse(input, options) { } function peg$parseop_weight() { - var s0, s1, s2; + var s0, s1, s2, s3; s0 = peg$currPos; + s1 = peg$parsews(); if (input.charCodeAt(peg$currPos) === 64) { - s1 = peg$c18; + s2 = peg$c18; peg$currPos++; } else { - s1 = peg$FAILED; + s2 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e26); } } - if (s1 !== peg$FAILED) { - s2 = peg$parsenumber(); - if (s2 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f7(s2); + if (s2 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 95) { + s2 = peg$c10; + peg$currPos++; } else { - peg$currPos = s0; - s0 = peg$FAILED; + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e18); } } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsenumber(); + if (s3 === peg$FAILED) { + s3 = null; + } + peg$savedPos = s0; + s0 = peg$f8(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1178,25 +1224,24 @@ function peg$parse(input, options) { } function peg$parseop_replicate() { - var s0, s1, s2; + var s0, s1, s2, s3; s0 = peg$currPos; + s1 = peg$parsews(); if (input.charCodeAt(peg$currPos) === 33) { - s1 = peg$c19; + s2 = peg$c19; peg$currPos++; } else { - s1 = peg$FAILED; + s2 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e27); } } - if (s1 !== peg$FAILED) { - s2 = peg$parsenumber(); - if (s2 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f8(s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; + if (s2 !== peg$FAILED) { + s3 = peg$parsenumber(); + if (s3 === peg$FAILED) { + s3 = null; } + peg$savedPos = s0; + s0 = peg$f9(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1246,7 +1291,7 @@ function peg$parse(input, options) { } if (s13 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f9(s3, s7, s11); + s0 = peg$f10(s3, s7, s11); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1286,7 +1331,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f10(s2); + s0 = peg$f11(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1314,7 +1359,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f11(s2); + s0 = peg$f12(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1344,7 +1389,7 @@ function peg$parse(input, options) { s2 = null; } peg$savedPos = s0; - s0 = peg$f12(s2); + s0 = peg$f13(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1368,7 +1413,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f13(s2); + s0 = peg$f14(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1396,7 +1441,7 @@ function peg$parse(input, options) { s2 = peg$parseslice(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f14(s2); + s0 = peg$f15(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1422,7 +1467,7 @@ function peg$parse(input, options) { s3 = peg$parseslice_op(); } peg$savedPos = s0; - s0 = peg$f15(s1, s2); + s0 = peg$f16(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1447,7 +1492,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f16(s1); + s1 = peg$f17(s1); } s0 = s1; @@ -1496,7 +1541,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f17(s1); + s1 = peg$f18(s1); } s0 = s1; @@ -1545,7 +1590,56 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f18(s1); + s1 = peg$f19(s1); + } + s0 = s1; + + return s0; + } + + function peg$parsedot_tail() { + var s0, s1, s2, s3, s4; + + s0 = peg$currPos; + s1 = []; + s2 = peg$currPos; + s3 = peg$parsedot(); + if (s3 !== peg$FAILED) { + s4 = peg$parsesequence(); + if (s4 !== peg$FAILED) { + s2 = s4; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = peg$currPos; + s3 = peg$parsedot(); + if (s3 !== peg$FAILED) { + s4 = peg$parsesequence(); + if (s4 !== peg$FAILED) { + s2 = s4; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } + } else { + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f20(s1); } s0 = s1; @@ -1561,12 +1655,15 @@ function peg$parse(input, options) { s2 = peg$parsestack_tail(); if (s2 === peg$FAILED) { s2 = peg$parsechoose_tail(); + if (s2 === peg$FAILED) { + s2 = peg$parsedot_tail(); + } } if (s2 === peg$FAILED) { s2 = null; } peg$savedPos = s0; - s0 = peg$f19(s1, s2); + s0 = peg$f21(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1586,7 +1683,7 @@ function peg$parse(input, options) { s2 = null; } peg$savedPos = s0; - s0 = peg$f20(s1, s2); + s0 = peg$f22(s1, s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1609,7 +1706,7 @@ function peg$parse(input, options) { s6 = peg$parsequote(); if (s6 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f21(s4); + s0 = peg$f23(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1671,7 +1768,7 @@ function peg$parse(input, options) { s3 = peg$parsemini_or_operator(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f22(s3); + s0 = peg$f24(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1704,7 +1801,7 @@ function peg$parse(input, options) { s5 = peg$parsequote(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f23(s4); + s0 = peg$f25(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1749,7 +1846,7 @@ function peg$parse(input, options) { s7 = null; } peg$savedPos = s0; - s0 = peg$f24(s3, s5, s7); + s0 = peg$f26(s3, s5, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1782,7 +1879,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f25(s3); + s0 = peg$f27(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1811,7 +1908,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f26(s3); + s0 = peg$f28(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1840,7 +1937,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f27(s3); + s0 = peg$f29(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1869,7 +1966,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f28(s3); + s0 = peg$f30(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1911,7 +2008,7 @@ function peg$parse(input, options) { s5 = peg$parsequote(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f29(s4); + s0 = peg$f31(s4); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2003,7 +2100,7 @@ function peg$parse(input, options) { s9 = peg$parsemini_or_operator(); if (s9 !== peg$FAILED) { peg$savedPos = s7; - s7 = peg$f30(s5, s9); + s7 = peg$f32(s5, s9); } else { peg$currPos = s7; s7 = peg$FAILED; @@ -2020,7 +2117,7 @@ function peg$parse(input, options) { s9 = peg$parsemini_or_operator(); if (s9 !== peg$FAILED) { peg$savedPos = s7; - s7 = peg$f30(s5, s9); + s7 = peg$f32(s5, s9); } else { peg$currPos = s7; s7 = peg$FAILED; @@ -2040,7 +2137,7 @@ function peg$parse(input, options) { } if (s8 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f31(s5, s6); + s0 = peg$f33(s5, s6); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2086,7 +2183,7 @@ function peg$parse(input, options) { s4 = peg$parsecomment(); } peg$savedPos = s0; - s0 = peg$f32(s1); + s0 = peg$f34(s1); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2108,7 +2205,7 @@ function peg$parse(input, options) { s5 = peg$parsemini_or_operator(); if (s5 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f33(s1, s5); + s0 = peg$f35(s1, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2133,7 +2230,7 @@ function peg$parse(input, options) { s1 = peg$parsemini_or_operator(); if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f34(s1); + s1 = peg$f36(s1); } s0 = s1; if (s0 === peg$FAILED) { @@ -2166,7 +2263,7 @@ function peg$parse(input, options) { if (s2 !== peg$FAILED) { s3 = peg$parsews(); peg$savedPos = s0; - s0 = peg$f35(s2); + s0 = peg$f37(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2191,7 +2288,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f36(s3); + s0 = peg$f38(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2220,7 +2317,7 @@ function peg$parse(input, options) { s3 = peg$parsenumber(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f37(s3); + s0 = peg$f39(s3); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -2246,7 +2343,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f38(); + s1 = peg$f40(); } s0 = s1; diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index da941049..18764a34 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -98,6 +98,7 @@ DIGIT = [0-9] ws "whitespace" = [ \n\r\t\u00A0]* comma = ws "," ws pipe = ws "|" ws +dot = ws "." ws quote = '"' / "'" // ------------------ steps and cycles --------------------------- @@ -105,7 +106,8 @@ quote = '"' / "'" // single step definition (e.g bd) step_char "a letter, a number, \"-\", \"#\", \".\", \"^\", \"_\"" = unicode_letter / [0-9~] / "-" / "#" / "." / "^" / "_" -step = ws chars:step_char+ ws { return new AtomStub(chars.join("")) } + +step = ws chars:step_char+ ws !{ const s = chars.join(""); return (s === ".") || (s === "_") } { 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 } @@ -129,11 +131,11 @@ slice = step / sub_cycle / polymeter / slow_sequence // at this point, we assume we can represent them as regular sequence operators slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail / op_range -op_weight = "@" a:number - { return x => x.options_['weight'] = a } +op_weight = ws ("@" / "_") a:number? + { return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 } -op_replicate = "!"a:number - { return x => x.options_['reps'] = a } +op_replicate = ws "!" a:number? + { return x => x.options_['reps'] = (x.options_['reps'] ?? 1) + (a ?? 2) - 1 } op_bjorklund = "(" ws p:slice_with_ops ws comma ws s:slice_with_ops ws comma? ws r:slice_with_ops? ws ")" { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) } @@ -175,9 +177,13 @@ stack_tail = tail:(comma @sequence)+ choose_tail = tail:(pipe @sequence)+ { return { alignment: 'rand', list: tail, seed: seed++ }; } +// a foot separates subsequences, as an alternative to wrapping them in [] +dot_tail = tail:(dot @sequence)+ + { return { alignment: 'feet', list: tail, seed: seed++ }; } + // if the stack contains only one element, we don't create a stack but return the // underlying element -stack_or_choose = head:sequence tail:(stack_tail / choose_tail)? +stack_or_choose = head:sequence tail:(stack_tail / choose_tail / dot_tail)? { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } } polymeter_stack = head:sequence tail:stack_tail? @@ -287,4 +293,4 @@ Lt = [\u01C5\u01C8\u01CB\u01F2\u1F88-\u1F8F\u1F98-\u1F9F\u1FA8-\u1FAF\u1FBC\u1FC Lu = [\u0041-\u005A\u00C0-\u00D6\u00D8-\u00DE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178-\u0179\u017B\u017D\u0181-\u0182\u0184\u0186-\u0187\u0189-\u018B\u018E-\u0191\u0193-\u0194\u0196-\u0198\u019C-\u019D\u019F-\u01A0\u01A2\u01A4\u01A6-\u01A7\u01A9\u01AC\u01AE-\u01AF\u01B1-\u01B3\u01B5\u01B7-\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A-\u023B\u023D-\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E-\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9-\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0-\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1C90-\u1CBA\u1CBD-\u1CBF\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E-\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D-\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AE\uA7B0-\uA7B4\uA7B6\uA7B8\uFF21-\uFF3A] // Number, Letter -Nl = [\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF] \ No newline at end of file +Nl = [\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF] diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index b76e1479..9217ae24 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -107,6 +107,9 @@ export function patternifyAST(ast, code, onEnter, offset = 0) { if (alignment === 'rand') { return strudel.chooseInWith(strudel.rand.early(randOffset * ast.arguments_.seed).segment(1), children); } + if (alignment === 'feet') { + return strudel.fastcat(...children); + } const weightedChildren = ast.source_.some((child) => !!child.options_?.weight); if (weightedChildren) { const weightSum = ast.source_.reduce((sum, child) => sum + (child.options_?.weight || 1), 0); diff --git a/packages/mini/test/mini.test.mjs b/packages/mini/test/mini.test.mjs index 2f204f86..6bf1bbce 100644 --- a/packages/mini/test/mini.test.mjs +++ b/packages/mini/test/mini.test.mjs @@ -73,6 +73,10 @@ describe('mini', () => { 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 replication via repeated !', () => { + expect(minS('a ! ! b')).toEqual(['a: 0 - 1/4', 'a: 1/4 - 1/2', 'a: 1/2 - 3/4', 'b: 3/4 - 1']); + expect(minS('[]!! 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']); }); @@ -190,6 +194,16 @@ describe('mini', () => { it('supports patterned ranges', () => { expect(minS('[<0 1> .. <2 4>]*2')).toEqual(minS('[0 1 2] [1 2 3 4]')); }); + it('supports the . operator', () => { + expect(minS('a . b c')).toEqual(minS('a [b c]')); + expect(minS('a . b c . [d e f . g h]')).toEqual(minS('a [b c] [[d e f] [g h]]')); + }); + it('supports the _ operator', () => { + expect(minS('a _ b _ _')).toEqual(minS('a@2 b@3')); + }); + it('_ and @ are almost interchangeable', () => { + expect(minS('a @ b @ @')).toEqual(minS('a _2 b _3')); + }); }); describe('getLeafLocation', () => { From 68113937ff074ed5349bf0b8c442d375481317d5 Mon Sep 17 00:00:00 2001 From: Renzo Torr- <56176668+geikha@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:06:24 -0300 Subject: [PATCH 07/16] code format --- packages/core/signal.mjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index bdf01d9b..b4a27298 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -231,10 +231,10 @@ export const pickF = register('pickF', function (lookup, funcs, pat) { /** * The same as `pickF`, but if you pick a number greater than the size of the functions list, * it wraps around, rather than sticking at the maximum value. -* @param {Pattern} pat -* @param {Pattern} lookup a pattern of indices -* @param {function[]} funcs the array of functions from which to pull -* @returns {Pattern} + * @param {Pattern} pat + * @param {Pattern} lookup a pattern of indices + * @param {function[]} funcs the array of functions from which to pull + * @returns {Pattern} */ export const pickmodF = register('pickmodF', function (lookup, funcs, pat) { return pat.apply(pickmod(lookup, funcs)); @@ -247,7 +247,7 @@ export const pickmodF = register('pickmodF', function (lookup, funcs, pat) { * @param {*} xs * @returns {Pattern} * @example - * "".inhabit({a: s("bd(3,8)"), + * "".inhabit({a: s("bd(3,8)"), b: s("cp sd") }) * @example From 2f8111be0eb03ce1db36ca65f0fd50f3aba8c517 Mon Sep 17 00:00:00 2001 From: Renzo Torr- <56176668+geikha@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:47:03 -0300 Subject: [PATCH 08/16] update the .snap file --- test/__snapshots__/examples.test.mjs.snap | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index b3114ed5..7537c2ec 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -3693,6 +3693,56 @@ exports[`runs examples > example "pick" example index 3 1`] = ` ] `; +exports[`runs examples > example "pickF" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | s:hh ]", + "[ 1/4 → 1/2 | s:rim ]", + "[ 1/2 → 1/1 | s:bd ]", + "[ 1/1 → 5/4 | s:hh pan:1 ]", + "[ 1/1 → 3/2 | s:bd pan:0 ]", + "[ 5/4 → 3/2 | s:rim pan:1 ]", + "[ 3/2 → 7/4 | s:rim pan:0 ]", + "[ 3/2 → 2/1 | s:bd pan:1 ]", + "[ 7/4 → 2/1 | s:hh pan:0 ]", + "[ 2/1 → 9/4 | s:bd ]", + "[ 9/4 → 19/8 | s:rim ]", + "[ 19/8 → 5/2 | s:hh ]", + "[ 5/2 → 11/4 | s:bd ]", + "[ 11/4 → 23/8 | s:rim ]", + "[ 23/8 → 3/1 | s:hh ]", + "[ 3/1 → 13/4 | s:hh ]", + "[ 13/4 → 7/2 | s:rim ]", + "[ 7/2 → 4/1 | s:bd ]", +] +`; + +exports[`runs examples > example "pickF" example index 1 1`] = ` +[ + "[ 0/1 → 1/8 | note:c2 s:square pan:0 ]", + "[ 1/8 → 1/4 | note:c2 s:square pan:1 ]", + "[ 3/8 → 1/2 | note:c2 s:square pan:0 ]", + "[ 1/2 → 9/16 | note:d2 s:square ]", + "[ 11/16 → 3/4 | note:d2 s:square ]", + "[ 7/8 → 15/16 | note:d2 s:square ]", + "[ 1/1 → 9/8 | note:d2 s:square cutoff:800 ]", + "[ 11/8 → 3/2 | note:d2 s:square cutoff:800 ]", + "[ 3/2 → 25/16 | note:d2 s:square ]", + "[ 27/16 → 7/4 | note:d2 s:square ]", + "[ 15/8 → 31/16 | note:d2 s:square ]", + "[ 2/1 → 17/8 | note:c2 s:square pan:0 ]", + "[ 17/8 → 9/4 | note:c2 s:square pan:1 ]", + "[ 19/8 → 5/2 | note:c2 s:square pan:0 ]", + "[ 5/2 → 41/16 | note:d2 s:square ]", + "[ 43/16 → 11/4 | note:d2 s:square ]", + "[ 23/8 → 47/16 | note:d2 s:square ]", + "[ 3/1 → 25/8 | note:d2 s:square cutoff:800 ]", + "[ 27/8 → 7/2 | note:d2 s:square cutoff:800 ]", + "[ 7/2 → 57/16 | note:d2 s:square ]", + "[ 59/16 → 15/4 | note:d2 s:square ]", + "[ 31/8 → 63/16 | note:d2 s:square ]", +] +`; + exports[`runs examples > example "ply" example index 0 1`] = ` [ "[ 0/1 → 1/4 | s:bd ]", From 738cea00255e357d9596cdeea16a720c5d00b704 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Sat, 20 Jan 2024 22:47:31 +0000 Subject: [PATCH 09/16] Make splice cps-aware (#932) * make splice cps-aware * format * copypaste fix --- packages/core/cyclist.mjs | 2 +- packages/core/pattern.mjs | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/core/cyclist.mjs b/packages/core/cyclist.mjs index c835ca76..ae6b68fe 100644 --- a/packages/core/cyclist.mjs +++ b/packages/core/cyclist.mjs @@ -41,7 +41,7 @@ export class Cyclist { this.lastEnd = end; // query the pattern for events - const haps = this.pattern.queryArc(begin, end); + const haps = this.pattern.queryArc(begin, end, { _cps: this.cps }); const tickdeadline = phase - time; // time left until the phase is a whole number this.lastTick = time + tickdeadline; diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 6a7b210b..408b5398 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -340,9 +340,9 @@ export class Pattern { * silence * @noAutocomplete */ - queryArc(begin, end) { + queryArc(begin, end, controls = {}) { try { - return this.query(new State(new TimeSpan(begin, end))); + return this.query(new State(new TimeSpan(begin, end), controls)); } catch (err) { logger(`[query]: ${err.message}`, 'error'); return []; @@ -2341,14 +2341,19 @@ export const splice = register( 'splice', function (npat, ipat, opat) { const sliced = slice(npat, ipat, opat); - return sliced.withHap(function (hap) { - return hap.withValue((v) => ({ - ...{ - speed: (1 / v._slices / hap.whole.duration) * (v.speed || 1), - unit: 'c', - }, - ...v, - })); + return new Pattern((state) => { + // TODO - default cps to 0.5 + const cps = state.controls._cps || 1; + const haps = sliced.query(state); + return haps.map((hap) => + hap.withValue((v) => ({ + ...{ + speed: (cps / v._slices / hap.whole.duration) * (v.speed || 1), + unit: 'c', + }, + ...v, + })), + ); }); }, false, // turns off auto-patternification From 8052e10f0c1d0ebf7c3b64adeb6f2f8a339a28ca Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 00:39:26 +0100 Subject: [PATCH 10/16] implement fit with pat state --- packages/core/pattern.mjs | 16 +++++++++------- packages/core/repl.mjs | 11 ----------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 408b5398..e98c4f2b 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -427,7 +427,7 @@ export class Pattern { * @noAutocomplete */ withHaps(func) { - return new Pattern((state) => func(this.query(state))); + return new Pattern((state) => func(this.query(state), state)); } /** @@ -2377,12 +2377,14 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto * s("rhodes/4").fit() */ export const fit = register('fit', (pat) => - pat.withHap((hap) => - hap.withValue((v) => ({ - ...v, - speed: 1 / hap.whole.duration, - unit: 'c', - })), + pat.withHaps((haps, state) => + haps.map((hap) => + hap.withValue((v) => ({ + ...v, + speed: (state.controls._cps || 1) / hap.whole.duration, + unit: 'c', + })), + ), ), ); diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 9fb6b4b9..65a9ba01 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -142,19 +142,8 @@ export function repl({ // already defined.. } - const fit = register('fit', (pat) => - pat.withHap((hap) => - hap.withValue((v) => ({ - ...v, - speed: scheduler.cps / hap.whole.duration, // overwrite speed completely? - unit: 'c', - })), - ), - ); - evalScope({ loopAt, - fit, all, hush, setCps, From 0a82471112d43e1186ae131d55e7a1490ed5166e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 00:45:40 +0100 Subject: [PATCH 11/16] implement loopAt with pat state --- packages/core/pattern.mjs | 7 +------ packages/core/repl.mjs | 6 ------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index e98c4f2b..fc9dae04 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2359,15 +2359,10 @@ export const splice = register( false, // turns off auto-patternification ); -// this function will be redefined in repl.mjs to use the correct cps value. -// It is still here to work in cases where repl.mjs is not used - export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) { - return _loopAt(factor, pat, 1); + return new Pattern((state) => _loopAt(factor, pat, state.controls._cps).query(state)); }); -// the fit function will be redefined in repl.mjs to use the correct cps value. -// It is still here to work in cases where repl.mjs is not used /** * Makes the sample fit its event duration. Good for rhythmical loops like drum breaks. * Similar to `loopAt`. diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 65a9ba01..27c95c70 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -107,11 +107,6 @@ export function repl({ const setCps = (cps) => scheduler.setCps(cps); const setCpm = (cpm) => scheduler.setCps(cpm / 60); - // the following functions use the cps value, which is why they are defined here.. - const loopAt = register('loopAt', (cycles, pat) => { - return pat.loopAtCps(cycles, scheduler.cps); - }); - Pattern.prototype.p = function (id) { pPatterns[id] = this; return this; @@ -143,7 +138,6 @@ export function repl({ } evalScope({ - loopAt, all, hush, setCps, From aa1b9d11dc0ee35004dd6bdcbb87927b0e6a5dc7 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 00:59:31 +0100 Subject: [PATCH 12/16] inject scheduler into Pattern methods right before eval --- packages/core/repl.mjs | 95 ++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 27c95c70..9f3731c8 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -61,12 +61,62 @@ export function repl({ scheduler.setPattern(pattern, autostart); }; setTime(() => scheduler.now()); // TODO: refactor? + + const stop = () => scheduler.stop(); + const start = () => scheduler.start(); + const pause = () => scheduler.pause(); + const toggle = () => scheduler.toggle(); + const setCps = (cps) => scheduler.setCps(cps); + const setCpm = (cpm) => scheduler.setCps(cpm / 60); + + const injectPatternMethods = () => { + Pattern.prototype.p = function (id) { + pPatterns[id] = this; + return this; + }; + Pattern.prototype.q = function (id) { + return silence; + }; + + const all = function (transform) { + allTransform = transform; + return silence; + }; + try { + for (let i = 1; i < 10; ++i) { + Object.defineProperty(Pattern.prototype, `d${i}`, { + get() { + return this.p(i); + }, + }); + Object.defineProperty(Pattern.prototype, `p${i}`, { + get() { + return this.p(i); + }, + }); + Pattern.prototype[`q${i}`] = silence; + } + } catch (err) { + // already defined.. + } + + evalScope({ + all, + hush, + setCps, + setcps: setCps, + setCpm, + setcpm: setCpm, + }); + }; + const evaluate = async (code, autostart = true, shouldHush = true) => { if (!code) { throw new Error('no code to evaluate'); } try { updateState({ code, pending: true }); + injectPatternMethods(); await beforeEval?.({ code }); shouldHush && hush(); let { pattern, meta } = await _evaluate(code, transpiler); @@ -100,51 +150,6 @@ export function repl({ onEvalError?.(err); } }; - const stop = () => scheduler.stop(); - const start = () => scheduler.start(); - const pause = () => scheduler.pause(); - const toggle = () => scheduler.toggle(); - const setCps = (cps) => scheduler.setCps(cps); - const setCpm = (cpm) => scheduler.setCps(cpm / 60); - - Pattern.prototype.p = function (id) { - pPatterns[id] = this; - return this; - }; - Pattern.prototype.q = function (id) { - return silence; - }; - - const all = function (transform) { - allTransform = transform; - return silence; - }; - try { - for (let i = 1; i < 10; ++i) { - Object.defineProperty(Pattern.prototype, `d${i}`, { - get() { - return this.p(i); - }, - }); - Object.defineProperty(Pattern.prototype, `p${i}`, { - get() { - return this.p(i); - }, - }); - Pattern.prototype[`q${i}`] = silence; - } - } catch (err) { - // already defined.. - } - - evalScope({ - all, - hush, - setCps, - setcps: setCps, - setCpm, - setcpm: setCpm, - }); const setCode = (code) => updateState({ code }); return { scheduler, evaluate, start, stop, pause, setCps, setPattern, setCode, toggle, state }; } From 18ae82174dfa9f370e3f4dc76eb371742f1aaf2f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 01:13:32 +0100 Subject: [PATCH 13/16] fix: "can't redefine non-configurable property" --- packages/core/repl.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 9f3731c8..d040787d 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -88,16 +88,18 @@ export function repl({ get() { return this.p(i); }, + configurable: true, }); Object.defineProperty(Pattern.prototype, `p${i}`, { get() { return this.p(i); }, + configurable: true, }); Pattern.prototype[`q${i}`] = silence; } } catch (err) { - // already defined.. + console.warn('injectPatternMethods: error:', err); } evalScope({ From 6224cd40d44b8d434c10cae1e49389d7824057ba Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 01:21:13 +0100 Subject: [PATCH 14/16] mini repl max height option --- website/src/docs/MiniRepl.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 10eff483..3afb609e 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -27,6 +27,7 @@ export function MiniRepl({ punchcardLabels = true, claviature, claviatureLabels, + maxHeight, }) { const code = tunes ? tunes[0] : tune; const id = useMemo(() => s4(), []); @@ -154,7 +155,7 @@ export function MiniRepl({ )} )} -

+
{ if (!editorRef.current) { From 0cfec3a7bd06e3d89ac6434f44f1c62211aa7c59 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 01:21:21 +0100 Subject: [PATCH 15/16] show repls in community bakery --- website/src/components/Oven/Oven.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/components/Oven/Oven.jsx b/website/src/components/Oven/Oven.jsx index 7cb2e7a7..30822d6c 100644 --- a/website/src/components/Oven/Oven.jsx +++ b/website/src/components/Oven/Oven.jsx @@ -6,6 +6,7 @@ import { PatternLabel } from '@src/repl/panel/PatternsTab'; function PatternList({ patterns }) { return ( From 0695b4bee99edfd2574d6cee6675bb1ec494bc4a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 21 Jan 2024 01:29:31 +0100 Subject: [PATCH 16/16] clean + comment --- packages/core/repl.mjs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index d040787d..490ac98c 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -68,7 +68,12 @@ export function repl({ const toggle = () => scheduler.toggle(); const setCps = (cps) => scheduler.setCps(cps); const setCpm = (cpm) => scheduler.setCps(cpm / 60); + const all = function (transform) { + allTransform = transform; + return silence; + }; + // set pattern methods that use this repl via closure const injectPatternMethods = () => { Pattern.prototype.p = function (id) { pPatterns[id] = this; @@ -77,11 +82,6 @@ export function repl({ Pattern.prototype.q = function (id) { return silence; }; - - const all = function (transform) { - allTransform = transform; - return silence; - }; try { for (let i = 1; i < 10; ++i) { Object.defineProperty(Pattern.prototype, `d${i}`, { @@ -101,7 +101,6 @@ export function repl({ } catch (err) { console.warn('injectPatternMethods: error:', err); } - evalScope({ all, hush,