Parsing array into interpretable string for genetic algorithm

I was wondering whether a solution exists to parse an array of strings and numbers into a string that can be executed by the interpreter. A very simple example like:

[2, 0.1, 440, "SinOscAr", "*", "!"]

would be parsed into:


The underlying idea is to create a genetic algorithm approach to sound creation, each array being an individual. And if I could avoid having to write a parser for the project, that would save me a lot of time :sweat_smile:


1 Like

Are you receiving the input, in your example [2, 0.1, 440, "SinOscAr", "*", "!"], as a String or a structured collection (for example an Array)? And is there a reason your output must be a string rather than the actual array of SinOsc’s?

Two thoughts on this:

.) Following Brian’s question: if you want to have different data in an Array and then produce a SynthDef therewith, you might want to wrap UGens in Functions, then you can take them over. See these discussions: {}.play on a UGen stored in variable?

.) You could also use the preProcessor method for Strings (more hassle)

.) You could also poke around with the ‘interpret’ method, but this is also often a complication.

I suppose the first approach could fit your demands. Here an example how to integrate operators like ‘+’ and ‘*’:

// in your application x,y could be items of an array

x = { |a, b| BinaryOpUGen('+', a, b) };

y = { |a, b| BinaryOpUGen('*', a, b) };

u = { x.(, * 0.1 }.play  


v = { y.(, * 0.1 }.play  

1 Like

One of the things that I like to say about programming is that all programming reduces to three questions:

  1. What information do I have? (Arrays that have been manipulated by a genetic algorithm.)
  2. What information do I want? (A SynthDef.)
  3. What operations will transform #1 into #2?

Particularly #3 is not a trivial question (and this is usually an iterative process) – but it all comes down to this.

One catch in this specific case is: If there should be a deterministic relationship between 1 and 2, then 1 needs to be unambiguous.

  • OK: Input A --> Output Z, and Input B --> Output Z. (In SC, rrand(1, 5) and 1 rrand: 5 are different inputs but compile to the same result.)
  • Not OK: Input A --> Output Y and Input A --> Output Z.

You might run into problems with the input design that you posted.

It looks like a kind of FORTH style reverse Polish notation – and if they’re already separated into items like this, then the parsing is finished. (Parsing = converting a flat code string into a data structure of tokens – but you already have the tokens.) It would be fairly easy to create a stack and then let the opcodes manipulate the stack:

  • Push 2
  • Push 0.1
  • Push 440
  • SinOsc pulls 440 and pushes the UGen instance.
  • * pulls the SinOsc instance and 0.1 and pushes the * result.
  • etc.

That wouldn’t necessarily give you a code string, but it would give you the UGen graph as a resulting data structure. (Or perhaps the "push"es are all strings.)

BUT: To be unambiguous, you can’t skip arguments.

SinOsc takes two arguments: frequency and phase. In that data structure, how do you know that 0.1 is not the SinOsc phase? Currently, there’s no information to disambiguate. That is: Input A [0.1, 440, "SinOscAr"] may correspond to Output Y with a residual of 0.1 to be used in a later operation, or to Output Z, 0.1). That’s exactly a situation that’s disallowed in compiler design.

So the data structure may need some revision.


1 Like

Maybe an alternative approach: if you unparse your DNA into valid supercollider syntax, you could write the unparsed code in a file, then load the file with .loadRelative or using the Require quark (

~conv = {
	arg bits=[];
	var str;

f=~conv.value([2, 0.1, 440, "", "*", "!"]);;

Not super-generic but if your array is well structured, it might work.

A more general solution might follow these lines. It’s extensible by adding to ~opcodes.

~stack = (
	pushItem: { |self, item|
		self[\stack] = self[\stack].add(item);
	popItem: { |self, item|
		var return = self[\stack].last;
		self[\stack] = self[\stack].drop(-1);
	topItem: { |self| self[\stack].last },
	resetToEmpty: { |self|
		self[\stack] =;

~opcodes = Dictionary[
	// entries are "regular expression string" -> { |stack, item| ... }
	// the function should push its result back onto the stack
	// assuming only freq as an argument
	"SinOscAr" -> { |stack, item|
		var freq = stack.popItem;
	// regexp requires + at the end of the []... well, OK
	"^[-*/%&|!<=>?+]+$" -> { |stack, item|
		var a = stack.popItem;
		var b = stack.popItem;
		stack.pushItem("(% % %)".format(a, item, b))
	\default -> { |stack, item|
	// more opcodes as needed

~findOpcode = { |item|
	var match = block { |break|
		~opcodes.keysDo { |k, v|
			if(k.respondsTo(\matchRegexp) and: { k.matchRegexp(item) }) {

~compile = { |array|
	var stack = ~stack.copy.resetToEmpty; { |item|
		item = item.asString;
		~findOpcode.(item).value(stack, item);

~compile.([2, 0.1, 440, "SinOscAr", "*", "!"]);
-> (( * 0.1) ! 2)

Note though that [1, 4, "-"] would be 4-1 rather than 1-4 – perhaps surprising to humans but legit if you’re generating the arrays algorithmically.



First of all, thanks to everyone for their answers, I really appreciate!

The only important part is that I start with a collection of tokens (operators, UGens, numbers), and with it I can create a synth that produces a sound (hopefully since the original arrays will be generated randomly).

You’re totally right. I’ll have a fixed number of arguments for each token (with a default value in case the stack is empty).

Yep! I was inspired by the HP 48 calculator that I used when I was at uni. (

This is an excellent starting point, thanks for taking the time!

Together with @jamshark70’s stack, I think we’ve got a good starting point.

I’ll keep you posted as the experiment continues!

1 Like