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 000000000..7cb2e7a75 --- /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 effc593c1..3eab0a2a5 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 000000000..b6961f601 --- /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 b6961f601..4410e283a 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 3eab0a2a5..a5cbcb62c 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 4410e283a..40c1c54fe 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 a5cbcb62c..adbcc7f03 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 253458ceb..bdf01d9bf 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 ac9e83096..b482d96c3 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 da941049c..18764a34b 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 b76e14790..9217ae249 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 2f204f864..6bf1bbcef 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 bdf01d9bf..b4a272981 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 b3114ed5f..7537c2ecd 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 c835ca768..ae6b68fee 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 6a7b210be..408b53985 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 408b53985..e98c4f2bb 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 9fb6b4b9a..65a9ba01b 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 e98c4f2bb..fc9dae047 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 65a9ba01b..27c95c709 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 27c95c709..9f3731c8b 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 9f3731c8b..d040787d3 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 10eff4832..3afb609e7 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 7cb2e7a75..30822d6cc 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 d040787d3..490ac98ce 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,