Arantium Maestum

プログラミング、囲碁、読書の話題

Clojure/Overtoneで遊んでみる

SICPばかりでもなんなので、Clojureで音楽が作れるっぽいOvertoneライブラリと戯れてみる。

Overtoneプロジェクト:

github.com

参考にさせていただいたブログ:

Overtone: Clojureで音楽を書こう : サルノオボエガキ

とりあえずdependenciesを足して、イントロビデオを見て、lein replでコードをコピペして弄ってみる。

github.com

(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)

あとは休符をどうするかだなー。もっと遊びながら考えていきたい。