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 )]
( slurp
( .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 ))))]
( cons
nxt
( lazy-seq
( walk-chain chain nxt )))))
( defn generate [ path ]
( -> path
parse-musicxml
( .getTokens )
notes
make-chain
( 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 )))