Skip to content

Commit

Permalink
Support for multiple mininotation operators WIP (#350)
Browse files Browse the repository at this point in the history
* support for multiple operators
* fix false test failures by sorting by part
* snapshot
  • Loading branch information
yaxu committed Jan 9, 2023
1 parent 45842b1 commit f57fe18
Show file tree
Hide file tree
Showing 6 changed files with 478 additions and 468 deletions.
69 changes: 39 additions & 30 deletions packages/mini/krill-parser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 21 additions & 16 deletions packages/mini/krill.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -119,32 +119,37 @@ slice = step / sub_cycle / polymeter / slow_sequence

// slice modifier affects the timing/size of a slice (e.g. [a b c]@3)
// at this point, we assume we can represent them as regular sequence operators
slice_modifier = slice_weight / slice_bjorklund / slice_slow / slice_fast / slice_replicate / slice_degrade
slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade

slice_weight = "@" a:number
{ return { weight: a} }
op_weight = "@" a:number
{ return x => x.options_['weight'] = a }

slice_replicate = "!"a:number
{ return { replicate: a } }
op_replicate = "!"a:number
{ return x => x.options_['reps'] = a }

slice_bjorklund = "(" ws p:slice_with_modifier ws comma ws s:slice_with_modifier ws comma? ws r:slice_with_modifier? ws ")"
{ return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r } } } }
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 }}) }

slice_slow = "/"a:slice
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } }
op_slow = "/"a:slice
{ return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }

slice_fast = "*"a:slice
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } }
op_fast = "*"a:slice
{ return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }

slice_degrade = "?"a:number?
{ return { operator : { type_: "degradeBy", arguments_ :{ amount:a } } } }
op_degrade = "?"a:number?
{ return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a } }) }

// a slice with an modifier applied i.e [bd@4 sd@3]@2 hh]
slice_with_modifier = s:slice o:slice_modifier?
{ return new ElementStub(s, o);}
slice_with_ops = s:slice ops:slice_op*
{ const result = new ElementStub(s, {ops: [], weight: 1, reps: 1});
for (const op of ops) {
op(result);
}
return result;
}

// a sequence is a combination of one or more successive slices (as an array)
sequence = s:(slice_with_modifier)+
sequence = s:(slice_with_ops)+
{ return new PatternStub(s, 'fastcat'); }

// a stack is a series of vertically aligned sequence, separated by a comma
Expand Down
96 changes: 46 additions & 50 deletions packages/mini/mini.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,78 +17,74 @@ function _nextSeed() {
const applyOptions = (parent, code) => (pat, i) => {
const ast = parent.source_[i];
const options = ast.options_;
const operator = options?.operator;
if (operator) {
switch (operator.type_) {
case 'stretch': {
const legalTypes = ['fast', 'slow'];
const { type, amount } = operator.arguments_;
if (!legalTypes.includes(type)) {
throw new Error(`mini: stretch: type must be one of ${legalTypes.join('|')} but got ${type}`);
const ops = options?.ops;
if (ops) {
for (const op of ops) {
switch (op.type_) {
case 'stretch': {
const legalTypes = ['fast', 'slow'];
const { type, amount } = op.arguments_;
if (!legalTypes.includes(type)) {
throw new Error(`mini: stretch: type must be one of ${legalTypes.join('|')} but got ${type}`);
}
pat = strudel.reify(pat)[type](patternifyAST(amount, code));
break;
}
return strudel.reify(pat)[type](patternifyAST(amount, code));
}
case 'bjorklund':
if (operator.arguments_.rotation) {
return pat.euclidRot(
patternifyAST(operator.arguments_.pulse, code),
patternifyAST(operator.arguments_.step, code),
patternifyAST(operator.arguments_.rotation, code),
);
} else {
return pat.euclid(
patternifyAST(operator.arguments_.pulse, code),
patternifyAST(operator.arguments_.step, code),
);
case 'bjorklund': {
if (op.arguments_.rotation) {
pat = pat.euclidRot(
patternifyAST(op.arguments_.pulse, code),
patternifyAST(op.arguments_.step, code),
patternifyAST(op.arguments_.rotation, code),
);
} else {
pat = pat.euclid(patternifyAST(op.arguments_.pulse, code), patternifyAST(op.arguments_.step, code));
}
break;
}
case 'degradeBy':
// TODO: find out what is right here
// example:
/*
case 'degradeBy': {
// TODO: find out what is right here
// example:
/*
stack(
s("hh*8").degrade(),
s("[ht*8]?")
)
*/
// above example will only be in sync when _degradeBy is used...
// it also seems that the nextSeed will create undeterministic behaviour
// as it uses a global _seedState. This is probably the reason for
// https://github.com/tidalcycles/strudel/issues/245
// above example will only be in sync when _degradeBy is used...
// it also seems that the nextSeed will create undeterministic behaviour
// as it uses a global _seedState. This is probably the reason for
// https://github.com/tidalcycles/strudel/issues/245

// this is how it was:
/*
// this is how it was:
/*
return strudel.reify(pat)._degradeByWith(
strudel.rand.early(randOffset * _nextSeed()).segment(1),
operator.arguments_.amount ?? 0.5,
op.arguments_.amount ?? 0.5,
);
*/
return strudel.reify(pat).degradeBy(operator.arguments_.amount === null ? 0.5 : operator.arguments_.amount);
pat = strudel.reify(pat).degradeBy(op.arguments_.amount === null ? 0.5 : op.arguments_.amount);
break;
}
default: {
console.warn(`operator "${op.type_}" not implemented`);
}
}
}
console.warn(`operator "${operator.type_}" not implemented`);
}
if (options?.weight) {
// weight is handled by parent
return pat;
}
// TODO: bjorklund e.g. "c3(5,8)"
const unimplemented = Object.keys(options || {}).filter((key) => key !== 'operator');
if (unimplemented.length) {
console.warn(
`option${unimplemented.length > 1 ? 's' : ''} ${unimplemented.map((o) => `"${o}"`).join(', ')} not implemented`,
);
}

return pat;
};

function resolveReplications(ast) {
ast.source_ = strudel.flatten(
ast.source_.map((child) => {
const { replicate, ...options } = child.options_ || {};
if (!replicate) {
const { reps } = child.options_ || {};
if (!reps) {
return [child];
}
delete child.options_.replicate;
return Array(replicate).fill(child);
delete child.options_.reps;
return Array(reps).fill(child);
}),
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/mini/test/mini.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import '@strudel.cycles/core/euclid.mjs';
import { describe, expect, it } from 'vitest';

describe('mini', () => {
const minV = (v) => mini(v).firstCycleValues;
const minS = (v) => mini(v).showFirstCycle;
const minV = (v) => mini(v).sortHapsByPart().firstCycleValues;
const minS = (v) => mini(v).sortHapsByPart().showFirstCycle;
it('supports single elements', () => {
expect(minV('a')).toEqual(['a']);
});
Expand Down
8 changes: 4 additions & 4 deletions test/__snapshots__/examples.test.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2265,20 +2265,20 @@ exports[`runs examples > example "orbit" example index 0 1`] = `
exports[`runs examples > example "pan" example index 0 1`] = `
[
"[ 0/1 → 1/4 | s:bd pan:0.5 ]",
"[ 1/4 → 1/2 | s:hh pan:0.5 ]",
"[ 1/2 → 3/4 | s:bd pan:0.5 ]",
"[ 1/4 → 1/2 | s:hh pan:0.5 ]",
"[ 3/4 → 1/1 | s:hh pan:0.5 ]",
"[ 1/1 → 5/4 | s:bd pan:1 ]",
"[ 5/4 → 3/2 | s:hh pan:1 ]",
"[ 3/2 → 7/4 | s:bd pan:1 ]",
"[ 5/4 → 3/2 | s:hh pan:1 ]",
"[ 7/4 → 2/1 | s:hh pan:1 ]",
"[ 2/1 → 9/4 | s:bd pan:0.5 ]",
"[ 9/4 → 5/2 | s:hh pan:0.5 ]",
"[ 5/2 → 11/4 | s:bd pan:0.5 ]",
"[ 9/4 → 5/2 | s:hh pan:0.5 ]",
"[ 11/4 → 3/1 | s:hh pan:0.5 ]",
"[ 3/1 → 13/4 | s:bd pan:0 ]",
"[ 13/4 → 7/2 | s:hh pan:0 ]",
"[ 7/2 → 15/4 | s:bd pan:0 ]",
"[ 13/4 → 7/2 | s:hh pan:0 ]",
"[ 15/4 → 4/1 | s:hh pan:0 ]",
]
`;
Expand Down

0 comments on commit f57fe18

Please sign in to comment.