Clojure (overtone + quil)によるコーディングとコードを音楽にするライブコーディング環境の試作

www.youtube.com
github.com

Parensymphonyはコーディングとコードが音楽になるライブコーディング環境の試作品です.ある授業の課題として作り,パフォーマンスをしました.動画を見ていただけるとわかるように,コーディングの操作に音がつきます.また,評価されたコードの構造からフレーズを生成していき,最終的に重なった音楽になります.動画中では,書いたコードで太鼓のパターン生成も行っています.つまり,コードが楽譜とプログラム二つの意味を持っていることになります.
ちなみに名称の由来はCommon LispJavaScriptトランスレータライブラリであるParenscriptからいただきました.恐らくParenthesisとscriptからつけられた名称だと思います.

なぜつくったのか

ライブコーディングで音楽をする作品には色々な環境,作品があります.Clojure(overtone)を用いたものには以下のような作品,ユニットが存在しています.
Sam Aaron - Hacking Overtone - Live @ Arnolfini on Vimeo
Repl Electric - Live Coding
しかし,これらはLispコードを評価し,その結果として音楽や映像が出力されるものです.コーディング過程やコードそのものが映像,音楽表現になるものを見たことがありませんでした.僕はLispのコードを初めて来たときにこのプログラミング言語はなんと格好良いのだろうと思っておりましたので,Lispコードが主役のものを見てみたかったのです.丸括弧を入力するとジャーンと和音がなって格好良く括弧が現れるというものが僕が最初に夢想したものです.
また,S式は構文木を表しているわけですけれども,そこから音楽的な構造にならないかとも考えました.詳しくは分かりませんが,実際に楽譜を木構造としてみる音楽理論が存在するようです.(CiNii 論文 -  音楽理論GTTMに基づく木構造を用いたメロディ生成手法
Lispのコードはprogramとしてもdataとしても解釈できます.そこでprogram = data = scoreを目指しました.

環境

今回はClojureで作りました.SuperCollider,Processingのラッパーであるovertoneとquilを使用しています.
Overtone - Collaborative Programmable Music
quil/quil · GitHub

ちなみにCommon Lispにもcl-colliderというSuperColliderのクライアントが存在するようですね.ただ,グラフィクス等を扱う良いライブラリがないのでClojureを使うことになりました.
byulparan/cl-collider · GitHub

実装

エディタ

エディタ部分は実装する知識,時間がなかったので,一つのフレームにつき,一つのS式を編集するという簡単なものです.ここに関しては,Emacsを用いてグローバルキーフックをかけるという方法も考えられましたが,ちょっと面倒そうなのと,やはり映像表現を自由に行いたかったので,quilの上に作りました.
ただ,結局コードを用いた映像表現に関しては文字のアニメーション表現等は経験がなく,今回は実装できませんでした.無理に実装してもゴタゴタしてつまらないだけでしょうし,各フレームが音に合わせてフラッシュするという単純なものにしました.

overtoneのチュートリアルで紹介されているplucked-stringのみを使用しています.フレーズはペンタトニックスケールを用いて構成されています.
括弧やスペース,タブを入力すると和音,その他のキーは単音が鳴ります.単音はフレーズが設定されており,入力するごとに順番に鳴り,スペースが入力されると別のフレーズに切り替わります.和音は完全にランダムです.本来はコード進行をつけようとしていたのですが,ペンタトニックスケールに合うような進行がよくわかりませんでした.
音が重なって聞こえにくくならないようにエディタの各フレームでは音の高さが変えられています.例えば,左上のフレームの単音はC2がルートのペンタトニックスケールで構成され,和音はその一つ上の高さになっています.

フレーズの生成

弦楽器でペンタトニックスケールは何でも合って凄いですね.
まず,スケールの山を作ります.

 (let [penta (scale :c3 :pentatonic)]
    (concat penta (reverse penta)))
-> (48 50 53 55 57 60 62 65 65 62 60 57 55 53 50 48)

そこからランダムに歯抜けにした無限シーケンスを作ります.

;;たとえば2つごとに抜きます.
(cycle (take-nth 2 notes))
-> (48 53 57 62 65 60 55 50 48 53 57 62 65 60 55 50  ...)

最初のいくつかを切り捨てて完成です.

;;例えば三番目以降を取得.
(nthrest phrase 3)
-> (62 65 60 55 50 48 53 57 62 65 60 55 50 48 53 57  ...)

途中にreverseを仕込んで反転させても面白いのですが,統一感がなくなったりしたのでやめました.このようにして生成されたフレーズがキー入力で鳴ったり,コードからの自動生成時に使用されます.

コードから音楽の生成

式の要素を順番に見ていき,文字列の長さ分だけフレーズを割り当てます.フレーズは各要素ごとにランダムに選びなおされます.要素の間には休符が入れられます.コードは以下のような感じ.

(defn gen-pattern [key-index n]
  (cond
    (or (number? n) (symbol? n)
        (keyword? n) (char? n)) (take (count (str n)) (get-phrase key-index))
    (empty? n) nil
    :else (concat (gen-pattern key-index (first n))
                  '(rest)
                  (gen-pattern key-index (rest n)))))

現状では要素の文字の長さとS式の構造によって休符をつけることのみしかしていません.もっとコードの情報をうまく使えると良いですね.

パフォーマンス

どのようなプログラムを書くか

環境自体が完成しても,パフォーマンスができなければ意味がありません.当初は競技プログラミングや4Clojureの簡単な課題を解くことも考えたのですが,音楽に全く関係ありませんし,4つコードでできることも限られています.また,Lisp(Clojure)についての事前知識がなければ何をやっているかわかりません.
今回はFizzBuzz(FibBuzz FibBuzz in Clojure · GitHub)から太鼓のフレーズを生成してみたところ,非常にいい感じになったのでこれを使いました.FizzBuzzならば,プログラミングを行っている人ならばわかる人も多いでしょう.
今回は非常にうまくはまってくれましたが,これ以外のものを考えるとなると難しいです.
overtoneを用いた作曲アプローチとしてleipzig(ctford/leipzig · GitHub)といった作曲ライブラリのようにノートのシーケンスを用いる方法があります.音の長さ,や高さをリストで与えることで演奏します.[1/3 1/3 1/3]のような感じで音符を与えるなどするのですが,このようにリストを書くようなプログラムは見ていてあまり面白くありません.
今回のように,なんらかのアルゴリズムを記述し,そのアルゴリズムを用いて生成された音楽に新たな要素を加えるというようなものが一番面白いと思います.書いたアルゴリズムがどんなに美しくてもそれが音楽として面白いかはまた別の話ですけれども…
竹内関数による音楽生成は非常に面白い例ですね.
竹内関数で音楽生成 - aikeの日記

タイピング

タイピングすることによって音楽ができるようにもなっていますが,自動演奏されるフレーズとの兼ね合いを考えてタイピングの速度を変える必要があります.あんまり早いと焦ってしまうので遅い方が良いのではないかと思います.

今後の課題

きちんとしたエディタを実装する

言わずもがな.Emacsキーバインド,Pareditあたりは必須です.

一般化

現在のParensymphonyは一つのパフォーマンスのために作られたものになっています.より一般化し,様々なパフォーマンスに対応できるようなフレームワークにすることが最終的な目標になるのだろうと思います.

コードを用いた映像表現

Lispコードをより格好良く見せる.

音楽知識の習得

言わずもがな.より良いフレーズの生成のために.

ゴアトランスを作りたい.

DTMで作れるようになってから.

シンセサイザーに関する知識の習得

自分の欲しい音が作れるようにならないと話になりません.サンプルを探してみてもなかなか欲しいものにはたどり着けませんでした.

非同期制御

お気づきだと思いますが,コードを評価するたびに.音楽が一度止まっています.ここら辺を改良するには,Clojureの非同期的な制御を行わなければならないのですが,僕が学習できていなかったのと,安定性を考えて一度止めて再度再生するようにしています.
かなり気になる部分ですので,改良は必須です.

感想

Clojure自体は初めてでしたが,楽しい言語でした.無限シーケンスが音楽的なことをするのに非常に便利でした.overtoneができるのも分かりますね.しかし,Clojureは関数型的な特性が強くて,そこら辺に手間取る事が多かったです.Common Lispで実装することも考えています.
音楽の知識,経験が足らず,大変でしたが,最終的にLispならではのものができたと思います.どのくらい時間がかけられるかわかりませんがより進化させたいとは思っています.なんにせよ,まずは知識不足を埋めることが一番の課題でしょうか.日々精進あるのみですね.