Euclidean rhythm generator in Clojure
My first Clojure function is a Euclidean Rhythm generator, and I felt like sharing it. I found a post doing a similar thing, albeit in LISP. They called it "exploratory programming", and so will I.
Why Euclidean rhythms and why Clojure? Well, Overtone! Having played with SuperCollider before and having developed a curiosity towards Clojure, Overtone seemed like a great segway into the latter.
For a while I have been wanting to experiment with quantifying, expressing and generating musically interesting rhythms. After a bit of research a recent paper turned up: The Euclidean Algorithm Generates Traditional Musical Rhythms. How cool is that? So I wanted to have my own implementation, as well as make a Clojure exercise out of it.
Euclidean rhythms, basically
A Euclidean rhythm is loosely defined as a sequence of beats and silences, where the beats are distributed as equidistantly as possible. With discrete and relatively short sequences this produces interestingly sounding results.
The rhythm is described as a function E(k, n) where k is the number of beats and n is the number of divisions (k < n). For example: E(3, 5) := [1 0 1 0 1].
The solution to ER works as follows, with examples:

Start with a sequence of n 1's and (k  n) 0's:
[1 1 1 0 0 0 0 0]

Remove as many same elements from the tail, and append them to as many other elements in the front as we can:
[[1 0] [1 0] [1 0] 0 0]

Repeat as many times as is sensible:
[[1 0 0] [1 0 0] [1 0]] [[1 0 0 1 0] [1 0 0]]

When repetitions no longer produce a new flat sequence, stop:
[1 0 0 1 0 1 0 0]
Implementation
Using the powers of Clojure as we discover them, we can be a tiny bit more concise than Ruin & Wesen. The entire code is available as a Gist.
It feels like this should be a oneliner in Clojure, and maybe it can be. But for now we start modest (and maintain some early debuggability). This solution was discovered experimentally, better ones must exist out there so please do share.
The starting sequence is easy. This will generate a sequence like [[1] [1] [0] [0] ...]
.
(concat (repeat k [1]) (repeat ( n k) [0]))
Vectors or lists? So far I don't know! For the exercise it does not matter. Vectors are simpler to type, lists are what the core functions return. Seeing a mix of them seems normal.
We could start by popping elements off the end and so on, but let's not. A better way is to "zip" part of the "tail" with the head of the sequence. Then we need a way to get that "tail":
(defn splitseq [s]
"Extract a tail of same elements: [1 1 0 0 0] > [[1 1] [0 0 0]]"
(let [l (last s)]
(splitwith #(not= l %) s)))
This says: walk the sequence as long as the element is not equal to the last one, then split. Now, the fun part: repeatedly zipping the sequence until we're nice and Euclidean.
I can has zip()?
Clojure has no direct equivalent of Python's zip
, but map
will accept multiple sequences. If the elements are themselves sequences and the function is concat
, we have our zip:
tutorial.core> (map concat [[1] [2] [3]] [[4] [5] [6]])
((1 4) (2 5) (3 6))
If the sequences are of different length, map
will stop at the end of the shortest one and ignore the rest (Python's map
, on the other hand, will pad the shorter sequences with None
s). Lucky for us, this is exactly the behavior we need to satisfy step 2 of the solution. The length of the merged sequence will equal the number of elements that are being removed from the end.
Let's recurse!
Obviously, once our recombined list is down to 2 or 3 elements no new flat sequences will appear (if they do they will be shifted copies of each other  prove that if you like). Using Clojure's multiple signatures let's define these as base cases:
(defn recombine
([a b] [a b])
([a b c] [a b c])
I.e., with only 2 or 3 arguments just return the sequence.
Note that we pass the sequence as unpacked arguments instead of the sequence object itself. The only reason is that we can use the multiple signature mechanism for base cases instead of a far less elegant if
statement.
Now, the real work:
([a b c & more]
(let [s (concat [a b c] more)
[head tail] (splitseq s)
recombined (map concat head tail)
rlen (count recombined)]
let
's get a little procedural for a moment:
s
is the reconstructed sequence in questiontail
is the "same element" tail,head
is the rest of the sequencerecombined
is head and tail zipped togetherrlen
is the length of therecombined
part
There is a third base case: if the sequence becomes purely periodic (i.e. [1 0] [1 0] [1 0] [1 0]
). According to our definition of splitseq
, splitwith
will return all tail and no head. Let's account for that:
(if (empty? head)
s
Empty head! That does happen. Finally, the recursive step.
(apply recombine (concat
recombined
(drop rlen (droplast rlen s))))))))
In other words, if a sequence is periodic just return it, otherwise construct a single pass of the recombined sequence (recombined
plus the middle portion of the original sequence, rlen
elements chopped off both ends) and recombine that.
Does it work?
tutorial.core> (recombine [1] [1] [0] [0])
[(1 0) (1 0)]
tutorial.core> (recombine [1] [1] [1] [0] [0])
[(1 0) (1 0) [1]]
Yes, it works.
Wrap up
(defn splitseq [s]
"Extract a tail of same elements: [1 1 0 0 0] > [[1 1] [0 0 0]]"
(let [l (last s)]
(splitwith #(not= l %) s)))
(defn recombine
([a b] [a b])
([a b c] [a b c])
([a b c & more]
(let [s (concat [a b c] more)
[head tail] (splitseq s)
recombined (map concat head tail)
rlen (count recombined)]
(if (empty? head) ;; even pattern
s
(apply recombine (concat
recombined
(drop rlen (droplast rlen s))))))))
(defn E [k n]
(let [seed (concat (repeat k [1]) (repeat ( n k) [0]))]
(flatten (apply recombine seed))))
tutorial.core> (E 3 5)
(1 0 1 0 1)
tutorial.core> (E 3 8)
(1 0 0 1 0 0 1 0)
Voila.