Wishful Coding

Didn't you ever wish your computer understood you?

Generative Music

It’s been a long time since I played with Overtone. What I’ve always wanted to do is generate music automatically. Today I ran into jFugue, which makes this really easy, listen to this:

</param> </param> </embed>

Markov generated music by pepijndevos

I just took some music from wikifonia, constructed a Markov-chain and did a random note-walk.

This could work just as well with Overtone, but I used jFugue because it comes with a parser for MusicXML files.

To run the code below, you need to have jFugue on the classpath. Then just pipe a couple of notes from generate into play.

(ns ponger.core
(:require clojure.string))

(defn inflate-mxl [file]
(let [z (java.util.zip.ZipFile. file)]
(.getInputStream z
(.nextElement (.entries z))))))

(defn parse-musicxml [file]
(let [parser (org.jfugue.parsers.MusicXmlParser.)
renderer (org.jfugue.MusicStringRenderer.)]
(.addParserListener parser renderer)
(.parse parser (inflate-mxl file))
(.getPattern renderer)))

(defn notes [tokens]
(filter #(re-matches #"[A-GR].*" %) tokens))

(defn voices [tokens]
(let [[f [_ & r]] (split-with (complement #(.startsWith % "V")) tokens)]
(when (seq f)
(cons f (voices r)))))

(defn make-chain [tokens]
(into {}
(for [[k slice] (group-by first (partition 2 1 tokens))]
[k (map last slice)])))

(defn walk-chain [chain start]
(let [nxt (rand-nth
(get chain start
(apply concat (vals chain))))]
(walk-chain chain nxt)))))

(defn generate [path]
(-> path
(walk-chain nil)))

(defn play [token-seq]
(let [player (org.jfugue.StreamingPlayer.)]
(doseq [token token-seq]
(.stream player token))))

(defn save [token-seq path]
(.saveMidi (org.jfugue.Player.)
(clojure.string/join " " token-seq)
(java.io.File. path)))
Pepijn de Vos