Skip to content

Instantly share code, notes, and snippets.

@dmorgan-github
Last active March 2, 2023 04:00
Show Gist options
  • Save dmorgan-github/d469788f3e3c5752793b88b61a75ec29 to your computer and use it in GitHub Desktop.
Save dmorgan-github/d469788f3e3c5752793b88b61a75ec29 to your computer and use it in GitHub Desktop.
SuperCollider mini dsl for durations and values
/*
Pbind(\degree, Pdv.parse("0 1 2 3"))
-> Pbind(\degree, Pseq([0 1 2 3], inf), \dur, 1)
Pbind(\degree, Pdv.parse("0 1 [2 3]"))
-> Pbind(\degree, Pseq([0 1 2 3], inf), \dur, Pseq([1, 1, 0.5, 0.5], inf))
Pbind(\degree, Pdv.parse("0 1 [2 [3, 4]]"))
-> Pbind(\degree, Pseq([0 1 2 3, 4], inf), \dur, Pseq([1, 1, 0.5, 0.25, 0.25], inf))
Pbind(\degree, Pdv.parse("0 1 [2 3, 4]"))
-> Pbind(\degree, Pseq([0 1 2 3, 4], inf), \dur, Pseq([1, 1, 1/3, 1/3, 1/3], inf))
Pbind(\degree, Pdv.parse("0 1 [2 3, 4]^2"))
-> Pbind(\degree, Pseq([0 1 2 3, 4], inf), \dur, Pseq([1, 1, 1/1.5, 1/1.5, 1/1.5], inf))
Pbind(\degree, Pdv.parse("0!4 1"))
-> Pbind(\degree, Pseq([0, 0, 0, 0, 1], inf), \dur, Pseq([0.25, 0.25, 0.25, 0.25, 1], inf))
// shuffle
Pbind(\degree, Pdv.parse("[0 1 2 3]$"))
-> Pbind(\degree, Pshuf([ 1, 3, 2, 0 ], inf), \dur, 0.25)
// choose
Pbind(\degree, Pdv.parse("[0 1 2 3]#"))
-> Pbind(\degree, Prand([0, 1, 2, 3], inf), \dur, 1)
*/
Pdv {
*new {
}
*rout {|list|
var gate = nil;
^Prout({|inval|
var parse;
parse = {|obj, div=1, stretch=1|
var val, rep, shuf;
var result = ();
val = obj['val'].value;
stretch = (obj['stretch'] ?? stretch).value.asFloat;
rep = (obj['rep'] ?? 1).value.asInteger;
if (val.isSequenceableCollection) {
var size = val.size;
val.do({|item|
parse.(item, div * size.reciprocal, stretch);
});
}{
if (obj['type'] == \value) {
if (val.isRest) {
div = Rest(div);
};
rep.do({|i|
inval[\g1] = gate;
inval['dur'] = div * rep.reciprocal * stretch;
inval = val.embedInStream(inval);
gate = nil
})
} {
parse.(val, div, stretch)
}
};
};
inf.do({
gate = true;
list.asArray.do({|val|
parse.(val);
});
});
inval;
});
}
*sequence {|list|
var parse;
parse = {|list, result|
list.do({|item|
var val = item['val'];
if (item['type'] == \group) {
var mylist = List.new;
mylist = parse.(val, mylist);
result.add(
item['val'] = if (item['shuf'] == true) {
{ mylist.asArray.scramble }
} {
if (item['choose'] == true) {
{ mylist.asArray.choose }
} {
mylist
}
};
);
} {
if (item['type'] == \alt) {
var mylist = List.new;
mylist = parse.(val, mylist);
result.add(
item['val'] = Routine({
var cnt = 0;
inf.do({|i|
if (item['shuf'] == true) {
mylist = mylist.asArray.scramble;
};
mylist.wrapAt(i).yield;
cnt = cnt + 1;
});
})
);
}{
result.add( item )
}
}
});
result;
};
^parse.(list, List.new);
}
*tokenize {|str|
var exec, match;
var getNextToken;
var hasMoreTokens;
var spec;
var cursor = 0;
// as pairs
spec = [
'number', "^[+-]?([0-9]*[.])?[0-9]+",
'stretch', "^\\^",
'rep', "^\!",
'rest', "^\~",
'shuf', "^\\$",
'choose', "^\#",
'[', "^\\[",
']', "^\\]",
'<', "^\<",
'>', "^\>",
nil, "^\\s+",
nil, "^\,",
];
hasMoreTokens = {
cursor < str.size;
};
match = {|regex, str|
var val = nil;
var m = str.findRegexp(regex);
if (m.size > 0) {
val = m[0][1];
cursor = cursor + val.size;
};
val;
};
getNextToken = {
var getNext;
var result = nil;
getNext = {
if (hasMoreTokens.()) {
spec.pairsDo({|k, v|
if (result.isNil) {
var val = match.(v, str[cursor..]);
if (val.notNil) {
if (k.isNil) {
getNext.()
}{
result = (
type: k,
val: val
);
}
}
}
});
};
};
getNext.();
if (result.isNil) {
"unexpected token %".format(str[cursor]).throw
};
result;
};
exec = {|list|
var exit = false;
while ({ hasMoreTokens.() and: { exit.not } }, {
var token = getNextToken.();
switch(token['type'],
// entities
'number', {
list.add( (val:token['val'].asFloat, type:\value) )
},
'rest', {
list.add( (val:\rest, type:\value) )
},
// modifiers
'stretch', {
list.last['stretch'] = getNextToken.()['val'].asFloat
},
'rep', {
list.last['rep'] = getNextToken.()['val'].asInteger;
},
'shuf', {
list.last['shuf'] = true;
},
'choose', {
list.last['choose'] = true;
},
// grouping delimiters
'[', {
var result;
list.add( () );
result = exec.(List.new);
list.last['val'] = result;
list.last['type'] = 'group'
},
']', {
exit = true
},
'<', {
var result;
list.add( () );
result = exec.(List.new);
list.last['val'] = result;
list.last['type'] = 'alt'
},
'>', {
exit = true
}
);
});
list;
};
^exec.(List.new);
}
*parse {|str|
var list, seq;
list = Pdv.tokenize(str);
seq = Pdv.sequence(list)
^Pdv.rout(seq);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment