diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 0e378d78..03ce2e2d 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2310,7 +2310,13 @@ export const { iterBack, iterback } = register( export const { repeatCycles } = register( 'repeatCycles', function (n, pat) { - return slowcat(...Array(n).fill(pat)); + return new Pattern(function (state) { + const cycle = state.span.begin.sam(); + const source_cycle = cycle.div(n).sam(); + const delta = cycle.sub(source_cycle); + state = state.withSpan((span) => span.withTime((spant) => spant.sub(delta))); + return pat.query(state).map((hap) => hap.withSpan((span) => span.withTime((spant) => spant.add(delta)))); + }).splitQueries(); }, true, true, diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index 7762242d..1cdd3486 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -295,7 +295,15 @@ function peg$parse(input, options) { 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$f9 = function(a) { return x => {const reps = (x.options_['reps'] ?? 1) + (a ?? 2) - 1; + x.options_['reps'] = reps; + console.log("reps: ", reps) + x.options_['ops'] = x.options_['ops'].filter(x => x.type_ !== "replicate"); + x.options_['ops'].push({ type_: "replicate", arguments_ :{ amount:reps }}); + x.options_['weight'] = reps; + console.log("options: ", x.options_); + } + }; 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' }}) }; diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index 35d7bdc4..c1349ca5 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -135,7 +135,14 @@ op_weight = ws ("@" / "_") a:number? { return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 } op_replicate = ws "!" a:number? - { return x => x.options_['reps'] = (x.options_['reps'] ?? 1) + (a ?? 2) - 1 } + { return x => {// A bit fiddly, to support both x!4 and x!!! as equivalent.. + const reps = (x.options_['reps'] ?? 1) + (a ?? 2) - 1; + x.options_['reps'] = reps; + x.options_['ops'] = x.options_['ops'].filter(x => x.type_ !== "replicate"); + x.options_['ops'].push({ type_: "replicate", arguments_ :{ amount:reps }}); + x.options_['weight'] = reps; + } + } 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 }}) } diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index 8c893273..8d2276fb 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -27,6 +27,12 @@ const applyOptions = (parent, enter) => (pat, i) => { pat = strudel.reify(pat)[type](enter(amount)); break; } + case 'replicate': { + const { amount } = op.arguments_; + pat = strudel.reify(pat); + pat = pat._repeatCycles(amount)._fast(amount); + break; + } case 'bjorklund': { if (op.arguments_.rotation) { pat = pat.euclidRot(enter(op.arguments_.pulse), enter(op.arguments_.step), enter(op.arguments_.rotation)); @@ -67,26 +73,13 @@ const applyOptions = (parent, enter) => (pat, i) => { return pat; }; -function resolveReplications(ast) { - ast.source_ = strudel.flatten( - ast.source_.map((child) => { - const { reps } = child.options_ || {}; - if (!reps) { - return [child]; - } - delete child.options_.reps; - return Array(reps).fill(child); - }), - ); -} - // expects ast from mini2ast + quoted mini string + optional callback when a node is entered export function patternifyAST(ast, code, onEnter, offset = 0) { onEnter?.(ast); const enter = (node) => patternifyAST(node, code, onEnter, offset); switch (ast.type_) { case 'pattern': { - resolveReplications(ast); + // resolveReplications(ast); const children = ast.source_.map((child) => enter(child)).map(applyOptions(ast, enter)); const alignment = ast.arguments_.alignment; const with_tactus = children.filter((child) => child.__tactus_source);