Improve performance of ! (replicate) (#1084)
* Implement ! with weighted repeatCycles * reimplement repeatCycles without array filling
This commit is contained in:
parent
deed379dba
commit
34e9d73908
4 changed files with 31 additions and 17 deletions
|
|
@ -2310,7 +2310,13 @@ export const { iterBack, iterback } = register(
|
||||||
export const { repeatCycles } = register(
|
export const { repeatCycles } = register(
|
||||||
'repeatCycles',
|
'repeatCycles',
|
||||||
function (n, pat) {
|
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,
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,15 @@ function peg$parse(input, options) {
|
||||||
var peg$f6 = function(a) { return a };
|
var peg$f6 = function(a) { return a };
|
||||||
var peg$f7 = function(s) { s.arguments_.alignment = 'polymeter_slowcat'; return s; };
|
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$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$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$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$f12 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) };
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,14 @@ op_weight = ws ("@" / "_") a:number?
|
||||||
{ return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 }
|
{ return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 }
|
||||||
|
|
||||||
op_replicate = ws "!" a:number?
|
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 ")"
|
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 }}) }
|
{ return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,12 @@ const applyOptions = (parent, enter) => (pat, i) => {
|
||||||
pat = strudel.reify(pat)[type](enter(amount));
|
pat = strudel.reify(pat)[type](enter(amount));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'replicate': {
|
||||||
|
const { amount } = op.arguments_;
|
||||||
|
pat = strudel.reify(pat);
|
||||||
|
pat = pat._repeatCycles(amount)._fast(amount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'bjorklund': {
|
case 'bjorklund': {
|
||||||
if (op.arguments_.rotation) {
|
if (op.arguments_.rotation) {
|
||||||
pat = pat.euclidRot(enter(op.arguments_.pulse), enter(op.arguments_.step), enter(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;
|
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
|
// expects ast from mini2ast + quoted mini string + optional callback when a node is entered
|
||||||
export function patternifyAST(ast, code, onEnter, offset = 0) {
|
export function patternifyAST(ast, code, onEnter, offset = 0) {
|
||||||
onEnter?.(ast);
|
onEnter?.(ast);
|
||||||
const enter = (node) => patternifyAST(node, code, onEnter, offset);
|
const enter = (node) => patternifyAST(node, code, onEnter, offset);
|
||||||
switch (ast.type_) {
|
switch (ast.type_) {
|
||||||
case 'pattern': {
|
case 'pattern': {
|
||||||
resolveReplications(ast);
|
// resolveReplications(ast);
|
||||||
const children = ast.source_.map((child) => enter(child)).map(applyOptions(ast, enter));
|
const children = ast.source_.map((child) => enter(child)).map(applyOptions(ast, enter));
|
||||||
const alignment = ast.arguments_.alignment;
|
const alignment = ast.arguments_.alignment;
|
||||||
const with_tactus = children.filter((child) => child.__tactus_source);
|
const with_tactus = children.filter((child) => child.__tactus_source);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue