From 5490b01004540ac2fa0b08718cb682690b9d389b Mon Sep 17 00:00:00 2001 From: Ian Clester Date: Mon, 20 Mar 2023 14:59:43 -0400 Subject: [PATCH] Maintain random seed state in parser, not globally --- packages/mini/krill-parser.js | 14 +++++++---- packages/mini/krill.pegjs | 14 +++++++---- packages/mini/mini.mjs | 34 ++++---------------------- test/__snapshots__/tunes.test.mjs.snap | 1 + 4 files changed, 24 insertions(+), 39 deletions(-) diff --git a/packages/mini/krill-parser.js b/packages/mini/krill-parser.js index 34e3843c..d2c861f2 100644 --- a/packages/mini/krill-parser.js +++ b/packages/mini/krill-parser.js @@ -279,7 +279,7 @@ function peg$parse(input, options) { var peg$f8 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; var peg$f9 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; var peg$f10 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; - var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a } }) }; + var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; var peg$f12 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; var peg$f13 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); for (const op of ops) { @@ -289,8 +289,8 @@ function peg$parse(input, options) { }; var peg$f14 = function(s) { return new PatternStub(s, 'fastcat'); }; var peg$f15 = function(tail) { return { alignment: 'stack', list: tail }; }; - var peg$f16 = function(tail) { return { alignment: 'rand', list: tail }; }; - var peg$f17 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment); } else { return head; } }; + var peg$f16 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; + var peg$f17 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; var peg$f18 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; var peg$f19 = function(sc) { return sc; }; var peg$f20 = function(s) { return { name: "struct", args: { mini:s }}}; @@ -2185,10 +2185,13 @@ function peg$parse(input, options) { this.location_ = location(); } - var PatternStub = function(source, alignment) + var PatternStub = function(source, alignment, seed) { this.type_ = "pattern"; - this.arguments_ = { alignment : alignment}; + this.arguments_ = { alignment: alignment }; + if (seed !== undefined) { + this.arguments_.seed = seed; + } this.source_ = source; } @@ -2214,6 +2217,7 @@ function peg$parse(input, options) { this.options_ = options; } + var seed = 0; peg$result = peg$startRuleFunction(); diff --git a/packages/mini/krill.pegjs b/packages/mini/krill.pegjs index f4fd7772..9ca48624 100644 --- a/packages/mini/krill.pegjs +++ b/packages/mini/krill.pegjs @@ -19,10 +19,13 @@ This program is free software: you can redistribute it and/or modify it under th this.location_ = location(); } - var PatternStub = function(source, alignment) + var PatternStub = function(source, alignment, seed) { this.type_ = "pattern"; - this.arguments_ = { alignment : alignment}; + this.arguments_ = { alignment: alignment }; + if (seed !== undefined) { + this.arguments_.seed = seed; + } this.source_ = source; } @@ -48,6 +51,7 @@ This program is free software: you can redistribute it and/or modify it under th this.options_ = options; } + var seed = 0; } start = statement @@ -137,7 +141,7 @@ op_fast = "*"a:slice { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) } op_degrade = "?"a:number? - { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a } }) } + { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) } op_tail = ":" s:slice { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) } @@ -162,12 +166,12 @@ stack_tail = tail:(comma @sequence)+ // a choose is a series of pipe-separated sequence, one of which is // chosen at random, each cycle choose_tail = tail:(pipe @sequence)+ - { return { alignment: 'rand', list: tail }; } + { return { alignment: 'rand', 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)? - { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment); } else { return head; } } + { 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? { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); } diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs index af6549cf..75d124fe 100644 --- a/packages/mini/mini.mjs +++ b/packages/mini/mini.mjs @@ -7,13 +7,8 @@ This program is free software: you can redistribute it and/or modify it under th import * as krill from './krill-parser.js'; import * as strudel from '@strudel.cycles/core'; -/* var _seedState = 0; const randOffset = 0.0002; -function _nextSeed() { - return _seedState++; -} */ - const applyOptions = (parent, code) => (pat, i) => { const ast = parent.source_[i]; const options = ast.options_; @@ -44,27 +39,10 @@ const applyOptions = (parent, code) => (pat, i) => { break; } 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 - - // this is how it was: - /* - return strudel.reify(pat)._degradeByWith( - strudel.rand.early(randOffset * _nextSeed()).segment(1), - op.arguments_.amount ?? 0.5, - ); - */ - pat = strudel.reify(pat).degradeBy(op.arguments_.amount === null ? 0.5 : op.arguments_.amount); + pat = strudel.reify(pat)._degradeByWith( + strudel.rand.early(randOffset * op.arguments_.seed).segment(1), + op.arguments_.amount ?? 0.5, + ); break; } case 'tail': { @@ -114,9 +92,7 @@ export function patternifyAST(ast, code) { return strudel.stack(...aligned); } if (alignment === 'rand') { - // https://github.com/tidalcycles/strudel/issues/245#issuecomment-1345406422 - // return strudel.chooseInWith(strudel.rand.early(randOffset * _nextSeed()).segment(1), children); - return strudel.chooseCycles(...children); + return strudel.chooseInWith(strudel.rand.early(randOffset * ast.arguments_.seed).segment(1), children); } const weightedChildren = ast.source_.some((child) => !!child.options_?.weight); if (!weightedChildren && alignment === 'slowcat') { diff --git a/test/__snapshots__/tunes.test.mjs.snap b/test/__snapshots__/tunes.test.mjs.snap index 261255f0..0822ffbb 100644 --- a/test/__snapshots__/tunes.test.mjs.snap +++ b/test/__snapshots__/tunes.test.mjs.snap @@ -63,6 +63,7 @@ exports[`renders tunes > tune: arpoon 1`] = ` "[ 0/1 → 1/2 | s:bd bank:RolandTR909 gain:0.5 ]", "[ 1/2 → 1/1 | s:bd bank:RolandTR909 gain:0.5 ]", "[ 1/2 → 2/3 | s:hh bank:RolandTR909 gain:0.5 ]", + "[ 5/6 → 1/1 | s:hh bank:RolandTR909 gain:0.5 ]", ] `;