2011-12-25

fill-queueでお手軽非同期処理

この記事はClojure Advent Calendar 2011の25日目の記事として書いています。
あんまりホリデイっぽくないので、Overtoneの記事と入替えて読むとちょうどいいですよ。

前にClojureのシーケンス操作関数の使い方一覧を書いたけど、最後に例示を挙げられなかったものがふたつ残りました。
seq-onは「何かをシーケンスとして扱いたいとき」というわり合い特殊なものなので良いとして、fill-queueはもう少し便利に使えそうなものなので何とか例示ができないかなーと思って簡単なファイルの変更監視スクリプトを書いてみました。

まずはfill-queueのdocを見てみましょう。
user=> (doc fill-queue)
-------------------------
clojure.contrib.seq/fill-queue
([filler-func & optseq])
  filler-func will be called in another thread with a single arg
  'fill'.  filler-func may call fill repeatedly with one arg each
  time which will be pushed onto a queue, blocking if needed until
  this is possible.  fill-queue will return a lazy seq of the values
  filler-func has pushed onto the queue, blocking if needed until each
  next element becomes available.  filler-func's return value is ignored.
nil

どうやら別スレッドで実行させる関数filler-funcを指定して、その関数でゴニョゴニョした値をqueueシーケンスとして受け取れるということらしい。filler-func内から値を返すときは引数fillに渡す。
非同期処理をシーケンスの流儀で取り扱えるっていうやつみたいですね。

これだけだとイメージが沸かないので使用例をぐぐってみたらこんな記事が見つかりました。
The Infolace Story: Simple webhooks with Clojure and Ring
この海外記事を読むとRingサーバー処理になにかフックさせるときに使ってる。途中の図がわかりやすい。

これでも使用例としてはいいんですけど、もうちょっと手元でいじれる例が欲しいのでファイルの最終更新日時を監視するスクリプトを書いて見ました。



watching-loopがfiller-funcで実行される本体です。ループで1秒ごとにファイルの最終更新日時を監視、変わっていたらfillにプッシュ。スレッド名を出力するコードを入れてるので別スレッドで実行されてることがはっきりしますね。
実行するとこんな感じ。


$ echo happy > test.txt
$ clj watch-file-status.clj test.txt
watching... (seq-test.txt)
main thread: main
watching-loop thread: pool-2-thread-1
;; $ echo chrismas! >> test.txt
modified: seq-test.txt
datetime: 2011-12-25 11:29:28
;; Ctrl-C
$ cat test.txt 
happy
chrismas!


これでfill-queueの使用例を書くことができました。前々から気になってたのをアウトプットできてスッキリ。
もうクリスマスがどうとか言ってる時期じゃないよ! 大掃除、棚卸しが大事だよ! リア充が爆発したら掃除が大変だよ!

ではみなさん良い年末を。俺は年賀状を書きます。

2011-12-10

Overtone: Clojureで音楽を書こう


この記事はClojure Advent Calendar 2011の10日目の記事として書いています。

12月1日からクリスマス25日まで毎日1ネタ、Clojureの記事を書くというこの企画。
せっかくなので前々から興味のあったOvertoneというライブラリの紹介をしてみようと思います。
Home // Overtone
overtone/overtone - GitHub

Overtoneは"Programmable Music"を目標とするシンセサイザーです。普通のシンセサイザーの操作とは違い、Clojureコードで音を作り音楽を書くことができます。
プログラマブル・シンセサイザーとしてはSuperColliderというのが前からあるそうで、それをClojureでラップした作りのようですね。
この記事では導入の仕方と簡単な音の作り方、最後にとあるクリスマスソングをOvertoneで書いてみたいと思います。


Overtoneを使ってみる
leiningenを使うとけっこう簡単に始められます(公式ドキュメントではcakeでのやり方も書いてある)。

$ lein new overtone-chrismas
$ cd overtone-chrismas

project.cljにOvertoneの設定をこんな感じに書き足します。

deltam's gist: 1454843 — Gist


$ lein deps
$ lein repl

あとはこのREPL上でやっていきます。



音を作る
正直言ってまだよく分かってません。Overtoneは薄いラッパのようでSuperColliderのコマンドを知らないと分かりにくい。とりあえずREADMEGetting Startedから使えそうなコードを持ってきて試してみました。

Internal Serverを立ち上げる
まずシンセサイザー用のサーバを立ち上げます。公式サイトによると内部サーバを起動する方法と外部サーバを使う方法があるみたいですが、ここでは内部サーバのほうを使います(外部サーバはSuperColliderのサーバに繋げる方法みたいなので別途インストールが必要。実際めんどい)。
こんな感じで内部サーバの準備をします。

user=> (use 'overtone.live)

; 内部サーバが起動するのでちょっと待つ
; いろいろメッセージが出た後にロゴが出てくる。
          _____                 __
         / __  /_  _____  _____/ /_____  ____  ___
        / / / / | / / _ \/ ___/ __/ __ \/ __ \/ _ \
       / /_/ /| |/ /  __/ /  / /_/ /_/ / / / /  __/
       \____/ |___/\___/_/   \__/\____/_/ /_/\___/

                          Programmable Music.


Hello deltam, may this be the start of a beautiful music hacking session...
nil
user=>


ビープ音を鳴らす

注意:以下のプログラムは実行するときは、ヘッドホンや音量に気をつけましょう。打ち間違えてノイジーな音が耳を直撃!なことになりますよー。
あと内部サーバ起動のときに音声の出力先を決めてるらしく、途中からヘッドホンのコードを抜き差しすると音が聞こえなくなったりしました。


README.mdにあるサンプルを写経。

user=> (demo 4 (pan2 (sin-osc 440)))

4秒間(demo 4)、ステレオ音声で(pan2)、440ヘルツの音(sin-osc 440)を鳴らすというコードです。いろいろ数値を変えてどんな音になるのか試してみましょう!

definstってやつを使うと楽器が定義できます。単純にビープ音を鳴らす楽器を定義しました。これだと(stop)を実行するまで止まらないので注意です。

user=> (definst beep [freq 440] (sin-osc freq))
#
user=> (beep)
29
user=> (stop)
nil
user=> (beep 200)
29
user=> (stop)
nil

これでだいたい音の作り方がわかりました!


クリスマスソングを書いてみよう
上記の方法だと周波数を指定しないと音を鳴らせません。もっと単純にピアノのように曲を書けないかなーと思って調べてみたんですが、よく分かりません。
ライブコーディングのムービーを見てみるとovertone.inst.pianoを使って曲を書いてるんですが、実際に使おうとすると「プラグインがないよー」と言われて使えない。たぶんSuperColliderにプラグインを追加して外部サーバに指定してOvertoneを立ち上げれば何とか成るのかな、と思うけど面倒臭いよね。

なので今回は単純にドレミ音階の周波数をまとめて定義して、それで曲を書いてみることにしました。
課題曲はクリスマスの定番、「ジングルベル」(参考楽譜、ついでに歌詞)。

deltam's gist: 1454843 — Gist

ロードして演奏してみます。


user=> (use 'overtone-chrismas.core :reload-all)

          _____                 __
         / __  /_  _____  _____/ /_____  ____  ___
        / / / / | / / _ \/ ___/ __/ __ \/ __ \/ _ \
       / /_/ /| |/ /  __/ /  / /_/ /_/ / / / /  __/
       \____/ |___/\___/_/   \__/\____/_/ /_/\___/

                          Programmable Music.


Hello deltam, may this be the start of a beautiful music hacking session...
nil
user=> (play-jingle-bells)
nil

楽譜の読み方も分からぬまま適当に写したので、ちょっと間延びした感じだけどちゃんとジングルベルの曲になってます。
曲が演奏できるようになると楽しくなってきますね!

まずは一番単純な方法で曲を書いて見ましたが、この方法だと音がぶつ切りになっていまいちです。Examplesを見るとちゃんと綺麗に音を鳴らす方法もあるので、興味が湧いた人は読むといいと思うよ! examples/basic.cljから読むと良いよ!

ライブコーディングのムービーをみると”ドギャーン”とか”ピポポ”とかいろんな音が作れるみたい。


Quick Intro to Live Programming with Overtone from Sam Aaron on Vimeo.



では予定がある人は良いクリスマスを! 無い人はOvertoneで遊ぼうぜ!