From f858d89f7b1d8f2771cdfa6c4fb7e3c41272d014 Mon Sep 17 00:00:00 2001 From: Bradford Powell Date: Fri, 29 Jul 2022 18:54:53 -0400 Subject: [PATCH] implement random choice in mini notation this will require update to krill-parser.js (aggregated in later commit) to work properly --- packages/mini/krill.pegjs | 22 ++++++++++++++++------ packages/mini/mini.mjs | 9 +++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index e266c395..6302614d 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -8,6 +8,7 @@ This program is free software: you can redistribute it and/or modify it under th // a sequence = a serie of elements placed between quotes // a stack = a serie of vertically aligned slices sharing the same overall length // a slice = a serie of horizontally aligned elements +// a choose = a serie of elements, one of which is chosen at random { @@ -81,7 +82,8 @@ DIGIT = [0-9] // ------------------ delimiters --------------------------- ws "whitespace" = [ \n\r\t]* -comma = ws "," ws; +comma = ws "," ws +pipe = ws "|" ws quote = '"' / "'" // ------------------ steps and cycles --------------------------- @@ -91,7 +93,7 @@ step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_" / ":" step = ws chars:step_char+ ws { return chars.join("") } // define a sub cycle e.g. [1 2, 3 [4]] -sub_cycle = ws "[" ws s:stack ws "]" ws { return s} +sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s} // define a timeline e.g <1 3 [3 5]>. We simply defer to a stack and change the alignement timeline = ws "<" ws sc:single_cycle ws ">" ws @@ -135,14 +137,22 @@ single_cycle = s:(slice_with_modifier)+ { return new PatternStub(s,"h"); } // a stack is a serie of vertically aligned single cycles, separated by a comma +stack_tail = tail:(comma @single_cycle)+ + { return { alignment: 'v', list: tail }; } + +// a choose is a serie of pipe-separated single cycles, one of which is chosen +// at random each time through the pattern +choose_tail = tail:(pipe @single_cycle)+ + { return { alignment: 'r', list: tail }; } + // if the stack contains only one element, we don't create a stack but return the // underlying element -stack = c:single_cycle cs:(comma v:single_cycle { return v})* - { if (cs.length == 0 && c instanceof Object) { return c;} else { cs.unshift(c); return new PatternStub(cs,"v");} } +stack_or_choose = head:single_cycle tail:(stack_tail / choose_tail)? + { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment); } else { return head; } } // a sequence is a quoted stack -sequence = ws quote s:stack quote - { return s; } +sequence = ws quote sc:stack_or_choose quote + { return sc; } // ------------------ operators --------------------------- diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index 684616ff..2a7bd077 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -10,6 +10,12 @@ import { addMiniLocations } from '@strudel.cycles/eval/shapeshifter.mjs'; const { pure, Pattern, Fraction, stack, slowcat, sequence, timeCat, silence, reify } = strudel; +var _seedState = 0; + +function _nextSeed() { + return _seedState++; +} + const applyOptions = (parent) => (pat, i) => { const ast = parent.source_[i]; const options = ast.options_; @@ -84,6 +90,9 @@ export function patternifyAST(ast) { if (alignment === 'v') { return stack(...children); } + if (alignment === 'r') { + return strudel.chooseInWith(strudel.rand.early(0.0001 * _nextSeed()).segment(1), children); + } const weightedChildren = ast.source_.some((child) => !!child.options_?.weight); if (!weightedChildren && alignment === 't') { return slowcat(...children);