Clojure/Overtoneで遊んでみる
SICPばかりでもなんなので、Clojureで音楽が作れるっぽいOvertoneライブラリと戯れてみる。
Overtoneプロジェクト:
参考にさせていただいたブログ:
Overtone: Clojureで音楽を書こう : サルノオボエガキ
とりあえずdependenciesを足して、イントロビデオを見て、lein replでコードをコピペして弄ってみる。
(use 'overtone.live)
と(use 'overtone.inst.piano)
で当面は十分そう。
ピアノ音を鳴らす関数がそのまんまのpiano。
(piano)
あるいは(piano 50)
などのように使う。
(piano)
で出る音が(piano 60)
と同一で、mid2Cのようだ。そこから数が上がる・下がるにつれ半音ずつずれていく。
「ドミソ」のコードは以下のようになる。
(doseq [note [60 64 67]] (piano note))
時間を指定して鳴らすには(at XXX (piano 60))
といった構文を使う。
以下のコードで「ドレミ」と1秒ずつずれて鳴る。
(let [time (now)] (doseq [i (range 3)] (at (+ time (* i 1000)) (piano (+ 60 i)))))
基本的には通常のClojureの構文であらかたコントロールできてしまう印象。
とりあえず、音のリストを受け取り、順番に鳴らしていく関数。全ての音符が同じ長さで鳴る(というか等間隔で鳴る)。
(defn play-me [notes] (let [time (now)] (doseq [[i note] (map vector (range) notes)] (at (+ (* 1000 i) time) (piano note)))))
あとは色々試すだけ。
(play-me [60 55 60 65 64 60 62 60 60])
とか
(play-me [60 55 60 65 64 60 62 64 64])
とか。
移調するのも(map #(- % 2) notes)
などで出来てしまうのが楽しい。
やはり音符の長さは指定したい。ということでplay-meを微調整:
(defn play-me ([notes] (play-me notes (range))) ([notes length] (let [time (now)] (doseq [[i note] (map vector length notes)] (at (+ time (* i 1000)) (piano note)))))) (def notes [60 55 60 65 64 60 62 60 60]) (def length [1 1 1 1 1 1 1.5 0.5 1]) (def cum-length (reductions + 0 length)) (play-me notes cum-length)
あとは休符をどうするかだなー。もっと遊びながら考えていきたい。