mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-15 15:48:29 +00:00
add poc for krill parsing
This commit is contained in:
parent
74355e86da
commit
2062e4233e
1916
repl/krill-parser.js
Normal file
1916
repl/krill-parser.js
Normal file
File diff suppressed because it is too large
Load Diff
207
repl/krill.pegjs
Normal file
207
repl/krill.pegjs
Normal file
@ -0,0 +1,207 @@
|
||||
// Some terminology:
|
||||
// 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
|
||||
|
||||
|
||||
{
|
||||
var PatternStub = function(source, alignment)
|
||||
{
|
||||
this.type_ = "pattern";
|
||||
this.arguments_ = { alignment : alignment};
|
||||
this.source_ = source;
|
||||
}
|
||||
|
||||
var OperatorStub = function(name, args, source)
|
||||
{
|
||||
this.type_ = name;
|
||||
this.arguments_ = args;
|
||||
this.source_ = source;
|
||||
}
|
||||
|
||||
var ElementStub = function(source, options)
|
||||
{
|
||||
this.type_ = "element";
|
||||
this.source_ = source;
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
var CommandStub = function(name, options)
|
||||
{
|
||||
this.type_ = "command";
|
||||
this.name_ = name;
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
start = statement
|
||||
|
||||
// ----- Numbers -----
|
||||
|
||||
number "number"
|
||||
= minus? int frac? exp? { return parseFloat(text()); }
|
||||
|
||||
decimal_point
|
||||
= "."
|
||||
|
||||
digit1_9
|
||||
= [1-9]
|
||||
|
||||
e
|
||||
= [eE]
|
||||
|
||||
exp
|
||||
= e (minus / plus)? DIGIT+
|
||||
|
||||
frac
|
||||
= decimal_point DIGIT+
|
||||
|
||||
int
|
||||
= zero / (digit1_9 DIGIT*)
|
||||
|
||||
minus
|
||||
= "-"
|
||||
|
||||
plus
|
||||
= "+"
|
||||
|
||||
zero
|
||||
= "0"
|
||||
|
||||
DIGIT = [0-9]
|
||||
|
||||
// ------------------ delimiters ---------------------------
|
||||
|
||||
ws "whitespace" = [ \n\r\t]*
|
||||
comma = ws "," ws;
|
||||
quote = '"' / "'"
|
||||
|
||||
// ------------------ steps and cycles ---------------------------
|
||||
|
||||
// single step definition (e.g bd)
|
||||
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}
|
||||
|
||||
// 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
|
||||
{ sc.arguments_.alignment = "t"; return sc;}
|
||||
|
||||
// a slice is either a single step or a sub cycle
|
||||
slice = step / sub_cycle / timeline
|
||||
|
||||
// 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_fixed_step
|
||||
|
||||
slice_weight = "@" a:number
|
||||
{ return { weight: a} }
|
||||
|
||||
slice_bjorklund = "(" ws p:number ws comma ws s:number ws")"
|
||||
{ return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s } } } }
|
||||
|
||||
slice_slow = "/"a:number
|
||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:a } } } }
|
||||
|
||||
slice_fast = "*"a:number
|
||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } }
|
||||
|
||||
slice_fixed_step = "%"a:number
|
||||
{ return { operator : { type_: "fixed-step", 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);}
|
||||
|
||||
// a single cycle is a combination of one or more successive slices (as an array). If we
|
||||
// have only one element, we skip the array and return the element itself
|
||||
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
|
||||
// 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");} }
|
||||
|
||||
// a sequence is a quoted stack
|
||||
sequence = ws quote s:stack quote
|
||||
{ return s; }
|
||||
|
||||
// ------------------ operators ---------------------------
|
||||
|
||||
operator = scale / slow / fast / target / bjorklund / struct / rotR / rotL
|
||||
|
||||
struct = "struct" ws s:sequence_or_operator
|
||||
{ return { name: "struct", args: { sequence:s }}}
|
||||
|
||||
target = "target" ws quote s:step quote
|
||||
{ return { name: "target", args : { name:s}}}
|
||||
|
||||
bjorklund = "euclid" ws p:int ws s:int
|
||||
{ return { name: "bjorklund", args :{ pulse: parseInt(p), step:parseInt(s) }}}
|
||||
|
||||
slow = "slow" ws a:number
|
||||
{ return { name: "stretch", args :{ amount: a}}}
|
||||
|
||||
rotL = "rotL" ws a:number
|
||||
{ return { name: "shift", args :{ amount: "-"+a}}}
|
||||
|
||||
rotR = "rotR" ws a:number
|
||||
{ return { name: "shift", args :{ amount: a}}}
|
||||
|
||||
fast = "fast" ws a:number
|
||||
{ return { name: "stretch", args :{ amount: "1/"+a}}}
|
||||
|
||||
scale = "scale" ws quote s:(step_char)+ quote
|
||||
{ return { name: "scale", args :{ scale: s.join("")}}}
|
||||
|
||||
comment = '//' p:([^\n]*)
|
||||
|
||||
// ---------------- grouping --------------------------------
|
||||
|
||||
group_operator = cat
|
||||
|
||||
// cat is another form of timeline
|
||||
cat = "cat" ws "[" ws s:sequence_or_operator ss:(comma v:sequence_or_operator { return v})* ws "]"
|
||||
{ ss.unshift(s); return new PatternStub(ss,"t"); }
|
||||
|
||||
// ------------------ high level sequence ---------------------------
|
||||
|
||||
sequence_or_group =
|
||||
group_operator /
|
||||
sequence
|
||||
|
||||
sequence_or_operator =
|
||||
sg:sequence_or_group ws (comment)*
|
||||
{return sg}
|
||||
/ o:operator ws "$" ws soc:sequence_or_operator
|
||||
{ return new OperatorStub(o.name,o.args,soc)}
|
||||
|
||||
sequ_or_operator_or_comment =
|
||||
sc: sequence_or_operator
|
||||
{ return sc }
|
||||
/ comment
|
||||
|
||||
sequence_definition = s:sequ_or_operator_or_comment
|
||||
|
||||
// ---------------------- statements ----------------------------
|
||||
|
||||
command = ws c:(setcps / setbpm / hush) ws
|
||||
{ return c }
|
||||
|
||||
setcps = "setcps" ws v:number
|
||||
{ return new CommandStub("setcps", { value: v})}
|
||||
|
||||
setbpm = "setbpm" ws v:number
|
||||
{ return new CommandStub("setcps", { value: (v/120/2)})}
|
||||
|
||||
hush = "hush"
|
||||
{ return new CommandStub("hush")}
|
||||
|
||||
// ---------------------- statements ----------------------------
|
||||
|
||||
statement = sequence_definition / command
|
||||
38
repl/package-lock.json
generated
38
repl/package-lock.json
generated
@ -25,6 +25,8 @@
|
||||
"@web/test-runner": "^0.13.3",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"chai": "^4.3.4",
|
||||
"peggy": "^1.2.0",
|
||||
"pegjs": "^0.10.0",
|
||||
"postcss": "^8.4.6",
|
||||
"prettier": "^2.2.1",
|
||||
"snowpack": "^3.3.7",
|
||||
@ -6067,6 +6069,30 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/peggy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/peggy/-/peggy-1.2.0.tgz",
|
||||
"integrity": "sha512-PQ+NKpAobImfMprYQtc4Egmyi29bidRGEX0kKjCU5uuW09s0Cthwqhfy7mLkwcB4VcgacE5L/ZjruD/kOPCUUw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"peggy": "bin/peggy"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pegjs": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
|
||||
"integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0=",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"pegjs": "bin/pegjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
@ -13113,6 +13139,18 @@
|
||||
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"peggy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/peggy/-/peggy-1.2.0.tgz",
|
||||
"integrity": "sha512-PQ+NKpAobImfMprYQtc4Egmyi29bidRGEX0kKjCU5uuW09s0Cthwqhfy7mLkwcB4VcgacE5L/ZjruD/kOPCUUw==",
|
||||
"dev": true
|
||||
},
|
||||
"pegjs": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
|
||||
"integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0=",
|
||||
"dev": true
|
||||
},
|
||||
"pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
"build": "snowpack build && cp ./public/.nojekyll ../docs",
|
||||
"test": "web-test-runner \"src/**/*.test.tsx\"",
|
||||
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\""
|
||||
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"peggy": "peggy -o krill-parser.js --format es ./krill.pegjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
@ -27,6 +28,7 @@
|
||||
"@web/test-runner": "^0.13.3",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"chai": "^4.3.4",
|
||||
"peggy": "^1.2.0",
|
||||
"postcss": "^8.4.6",
|
||||
"prettier": "^2.2.1",
|
||||
"snowpack": "^3.3.7",
|
||||
|
||||
@ -6,15 +6,11 @@ import * as Tone from 'tone';
|
||||
import useCycle from './useCycle';
|
||||
import type { Hap, Pattern } from './types';
|
||||
import { tetris } from './tunes';
|
||||
import _mini from './mini';
|
||||
|
||||
const { Fraction, TimeSpan } = strudel;
|
||||
|
||||
const fr = (v: number) => new Fraction(v);
|
||||
const ts = (start: number, end: number) => new TimeSpan(fr(start), fr(end));
|
||||
const parse = (code: string): Pattern => {
|
||||
const { sequence, pure, reify, slowcat, fastcat, cat, stack, silence } = strudel; // make available to eval
|
||||
return eval(code);
|
||||
};
|
||||
const { sequence, pure, reify, slowcat, fastcat, cat, stack, silence } = strudel; // make available to eval
|
||||
const mini = _mini; // for eval (direct import wont work somehow)
|
||||
const parse = (code: string): Pattern => eval(code);
|
||||
|
||||
const synth = new Tone.PolySynth().toDestination();
|
||||
synth.set({
|
||||
|
||||
34
repl/src/mini.ts
Normal file
34
repl/src/mini.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import * as krill from '../krill-parser';
|
||||
import * as strudel from '../../strudel.mjs';
|
||||
|
||||
export function patternifyAST(ast: any): any {
|
||||
switch (ast.type_) {
|
||||
case 'pattern':
|
||||
return strudel.sequence(...ast.source_.map(patternifyAST));
|
||||
case 'element':
|
||||
if (typeof ast.source_ !== 'object') {
|
||||
return ast.source_;
|
||||
}
|
||||
return patternifyAST(ast.source_);
|
||||
}
|
||||
}
|
||||
export default (str: string) => patternifyAST(krill.parse(`"${str}"`));
|
||||
|
||||
/*
|
||||
TODO:
|
||||
export interface Arguments {
|
||||
alignment: string;
|
||||
}
|
||||
|
||||
export interface ElementStub {
|
||||
type_: string;
|
||||
source_: string;
|
||||
options_?: any;
|
||||
}
|
||||
|
||||
export interface PatternStub {
|
||||
type_: string; // pattern
|
||||
arguments_: Arguments;
|
||||
source_: ElementStub[];
|
||||
}
|
||||
*/
|
||||
Loading…
x
Reference in New Issue
Block a user