Genetic Programming for Byte Beats in ClojureScript (Part 2)
As I outlined in my previous post, I had set out to create a byte beat player for the web using ClojureScript and the Web Audio API. Ideally this would have some novel ways to generate new formulas. My main complaint with existing byte beat synth programs is that the interface is basically a text editor and a C compiler. You should be able to have fun with byte beats without having to understand what is actually going on in byte beat formulas.
To start, I needed to figure out how to play a byte beat formula in the browser. From past tinkering with the Web Audio API, I knew that there was an audio graph element called a ScriptProcessorNode, which could be used to create samples by evaluating an arbitrary function. The way this works is that your ScriptProcessorNode will execute a callback which is passed an audio buffer, and the callback fills up the buffer with sample values. Here is what my ClojureScript implementation looked like; this function returns the callback that will receive ScriptProcessorNode events:
sample-gen
is a function that would take one argument, essentially the “t” in byte beat formulas.
There’s a bit of math using rate-ratio
- this allows you to stretch or compress a
formula by manipulating its sample rate. This function mutates a global clock reference to increment
the byte beat “t” value; if I had to do it again I would try to do this with a closure.
Now that I had a way to play the byte beats, I wanted to try out some of the awesome existing byte beat
formulas.
At first I tried manually re-writing some of the famous ones in ClojureScript. Here’s
the ClojureScript version of the famous t * ((t>>12 | t>>8) & 63 & t>>4)
:
Manually coding these rapidly grew tedious, so I decided I needed a way to parse the C expressions and convert them into ClojureScript expressions. A bit of searching lead me to Instaparse, an awesome library for generating parsers for language grammars. It works in the browser through the instaparse-cljs port. Arithmetic is a classic instructional example for CFGs, so I was able to get oriented quickly. Through some trial and error I figured out how to get the operator precedence right for the byte beat grammar. Here is what I came up with:
Now I was able to parse and play all the cool byte beat formulas people have come up with. It’s pretty fantastic that ClojureScript and Instaparse let you do all this in the browser!
In the next post I’ll get into how I used genetic programming operations with the byte beat formula syntax trees to generate formulas.
Comments