gnupack EmacsのDoing Vfork: resource temporarily unavailableを解決する

ノートPCに最新のgnupackのEmacsをいれました。しかし、diredやshell-modeを使おうとするとDoing Vfork: resource temporarily unavailableと表示され、使えない問題があり困ったので解決する方法のメモです。デスクトップの方にインストールしたときは普通に使えたのでよくわかりませんね。

イッチョカマーの徒然草: Cygwin+Emacs Problem
基本的にはこのサイトの通りに、rebaseallしてlibncursesを再インストールでいけるみたいです。少し補足が必要なので記載しておきます。

1

gnupackフォルダにstartup_rebaseallが存在するので、実行します。多分右クリックで管理者として実行する必要があります。rebaseallが何をしてくれているのかは不明。ちょっと調べましたけど実行しろとしか書かれていませんね…

2

次にcygwinのHPからcygwinのsetupファイルをダウンロードします。
Cygwin Installation
どうやらgnupackは32bit版を使用しているようですのでそれダウンロードしたら起動し、rootディレクトリをgnupack\cygwin\cygwinに設定してlibncursesを再インストールします。rootディレクトリの設定が間違っていなければ、自動的にインストール済みライブラリなどが認識されるとはずです。もしもディレクトリ指定が間違っているとそこに新たにcygwinがインストールされてしまうので注意が必要です。

終わり

これで恐らくエラーが消えます。

Distance Estimated 3D Fractalsを理解するためのロードマップ

mandelbulbやmandelboxをご存知でしょうか?これらのフラクタルはDistance Estimation という手法を用いて描画されることが多いです。この手法を用いることで、複雑なフラクタル形状を高速で綺麗に描画することができます。
最近この手法を勉強していました。クライン群に関しては以下の二つのようなものを描画することができます。といっても僕がこれらのDistance Estimationのアルゴリズムを考案したわけではないので、まだまだなのですが…これらに関してはそのうち文章にまとめたいと思います。
3D kissing-Schottky orbit spheres
kissing-Schottky limit set

さて、これらを理解するために、ネット上には多くのテキストが存在しますが、僕個人がこの順番だったら楽だったろうなぁというものをまとめておきます。僕もまだなんとなく理解できた、程度ですし、色々な文章を何度も読み返す必要はあると思います。

(独学とは再帰なり)

素数夜曲 by 吉田 武

日々精進あるのみですね。

GLSL、レイマーチングについて学ぶ

wgld.org | GLSL |

glslの基本とレイマーチングの基本が学べます。

http://www.demoscene.jp/?p=811

Distance functionについての項目でレイマーチングについてとてもわかりやすい図が載っているので一度目を通すべきです。

フラクタルの描画について学ぶ

Distance Estimated 3D Fractals (Part I) | Syntopia
Syntopiaでは8回にわたってDistance estimationを用いたフラクタル描画に関しての連載があります。非常に参考になるのですが、ところどころ展開が急で面食らうと思います。とりあえずpart1~3を読むのが良いと思います。
レイマーチング等の基本とカラーリングの話、そしてKaleidoscopic IFSについての解説があります。Kaleidoscopic IFSはある面での反転等を行うことによって構築するフラクタル図形です。

distance estimationについて

distance estimation

平面において、ある数式で表される図形から、ある点までの距離を測るにはどうすれば良いのか解説しています。
{ |\epsilon| \geq \frac{|f(x)|}{|\nabla f(x)|}
}
の関係式が重要です。

distance rendering for fractals

リンク先が変わったようです↓

distance to fractals

マンデルブロ集合をdistance estimationを用いた方法で描画する解説です。

mandelbulb

ここまで来たらSyntopiaのpart4から読んでいくと良いと思います。僕は唐突にヤコビアンがでてきてびっくりしましたが、{|\nabla f(x)|}を求めるためだと考えればなんとなく納得できます。ここら辺は色々なやり方や、論文があるため、一筋縄ではいかないと思います。あまり深入りしない方が良いのではないでしょうか…
Distance Estimated 3D Fractals (IV): The Holy Grail | Syntopia

Syntopiaでも紹介されていますが、そのほかは以下の二つ辺りを読むのがよいかと。mandelbulbまでがなんとなくわかれば残りのSyntopiaの他のパートも比較的楽に読めます。
mandelbulb
Mandelbulb: The Unravelling of the Real 3D Mandelbrot Fractal

その他

What is a Mandelbox - Mandelbox

mandelboxを考案した人のページ。一部表示されていない動画はこれです
2d Mandelbox fold from Tom Lowe on Vimeo

GLSL Sandbox Gallery Shadertoy BETA

これらのサイトで組んでみたり、shadertoyで既存のコードを検索し、値をいじることで理解が深まる場合もあります。

Fragmentarium

Syntopiaの方がつくったGLSLベースのレイトレーサで、シェーダのコードを含むexampleが豊富です。漁ってみればものすごく参考になるのではないでしょうか

おわり

他にも本やFractal Forums、論文など様々なテキストが存在します。もしも理解に詰まったら、あまり固執しすぎずに別のテキストを読んだり、コードを読んだりしてみると良いのではないでしょうか。一人前のフラクタルレンダラ―への道は長いですね。
あとはライティングや色付けに関する勉強ができていないので勉強したいです。そこら辺の理解ができたらまたまとめようと思います。

Travis CIでCommon Lisp Webアプリを自動デプロイするメモ

TravisCIを用いてcavemans2で作成したCommon Lisp製Webアプリのテストを回し、サーバーに自動デプロイするまでのメモです。

自動テスト

まずは自動テストを試します。
4. Roswell as a Testing Environment (Travis CI and Coverall) · snmsts/roswell Wiki · GitHub
Roswellを用いることで簡単にテストすることができます。TravisCIでCommon Lispをネイティブにサポートしようとする動きもあるようですが、どちらにせよRoswellを用いるのが一番簡単なのではないでしょうか。

language: common-lisp
sudo: required

install:
  - curl -L https://raw.githubusercontent.com/snmsts/roswell/release/scripts/install-for-ci.sh | sh

script:
  - ros -s prove -e '(or (prove:run :quri-test) (uiop:quit -1))'

が基本で、quri-testをテストを含むプロジェクト名に書き換えればテストが走ります。
テストフレームワークにはfukamachi/prove · GitHubが使用されています。現状、テストコードは全く書いていません。テストに関する勉強も必要ですね。

このままではテストを回すたびにRoswellや処理系等のインストールが走るので時間がかかります。そこで、TravisCIは処理系等をキャッシュしたりできるようです。
Caching Dependencies and Directories - Travis CI
sudo: falseを指定し、適切にパスを設定すれば以前インストールされた処理系などでテストが走り、時間短縮になります。このやり方もRoswellのwikiに載っているので参照してみてください。

自動デプロイ

ここの記事を参考にしました。
neemzy - Deploy to your own server through SSH with Travis CI - A blog by Tom Panier, web developer

テストが通るのを確認したら自動デプロイの作業に入ります。基本的にはテストが通った後にSSHのパスワード認証でサーバーにログインし、デプロイ用のシェルスクリプトを実行するだけです。

環境変数の設定

デプロイ先のホストや、ユーザー名を環境変数として設定します。travisCIのWebサイトでも設定できるみたいですが、さすがにパスワードとかをおいておくのはアレですかね。そのために、それらの環境変数を暗号化します。これは、gemで入るtravis encryptコマンドを使用します。僕はWindows環境で用意するのが大変そうだったのでVPSに入れて実行しました。

yum install gem
yum install ruby-devel
gem install travis

で入ります。ruby-develなしではtravisのビルドが通りませんでした。
後はいくつかの環境変数を暗号化し、.travis.ymlに環境変数として貼り付けます。上記のサイトには書いていなかったのですがリポジトリのユーザー名とリポジトリ名を入れなければ暗号化できませんでした。ここら辺は詳しくわかりません。

travis encrypt -r soma-arc/travis-test DEPLOY_HOST=123.45.67.8
travis encrypt -r soma-arc/travis-test DEPLOY_PATH=~/common-lisp/project
travis encrypt -r soma-arc/travis-test DEPLOY_USER=hogehoge
travis encrypt -r soma-arc/travis-test DEPLOY_PASS=foobar

それぞれ実行すると長い文字列が得られます。それらを以下のように貼り付けると、環境変数として使用できます。

env:
    global:
        - secure: "長い文字列"
デプロイ処理の記入

あとはテスト終了後の処理を書きます。デプロイはmasterブランチにプッシュされたときだけ行って欲しいので$TRAVIS_BRANCHを見ています。

addons:
    apt:
        packages:
            - sshpass

after_success:
    - if [[ "$TRAVIS_BRANCH" == "master" ]]; then
        export SSHPASS=$DEPLOY_PASS;
       sshpass -e ssh -o "StrictHostKeyChecking"=no $DEPLOY_USER@$DEPLOY_HOST $DEPLOY_PATH/deploy.sh 1>/dev/null 2>/dev/null;
      fi

sshpassはあらかじめパスワード等を指定してログインできるコマンドだそうです。
デプロイ先のdeploy.shを実行することでデプロイします。-o "StrictHostKeyChecking"=noはホストを知らない場合に出るホスト鍵のチェックプロンプトを抑制するためにつけています。
これに関してはknown hostを加えればいらなくなるのかと思い、

addons:
    ssh_known_hosts: $DEPLOY_HOST
    apt:
        packages:
            - sshpass

を加えてみたのですが、どうにもログインに失敗しているみたいで駄目でした。
また、

1>/dev/null 2>/dev/null

をつけることでいらない入出力は切り捨てています。

デプロイ用のスクリプトの用意
#!/bin/sh
killall sbcl
cd ~/common-lisp/travis-test
git pull
nohup ~/.roswell/bin/clackup --server :woo --port 80 app.lisp 1>/dev/null 2>/dev/null &
chmod a+rwx deploy.sh

を使って実行属性をつけるのと、読み書きもできるようにしておきます。
Linuxコマンド集 - 【 chmod 】 ファイルやディレクトリのアクセス権を変更する:ITpro

~/common-lispに配置しましたが、アプリのリポジトリに配置してしまった方が良いかもしれませんね。
現在動いているサーバーはkillallで落としています。本来ならばフォークして云々とかがあるのかもしれませんが、そこら辺の知識が全くないので、とりあえずsbclを強制終了し、git pullで更新した後に再びclackupでアプリを起動しています。
killallはCentOS7の場合yum install psmiscで入れる必要があります。
また、clackupは~/.roswell/binにパスを通していたはずなのですが、通らなかったので絶対パスを通しています。
nohupはsshログアウトした後もプロセスを残すために使用します。
ログアウトしてもバックグラウンド ジョブを継続する方法

最後の&はプロセスをバックグラウンドで実行するためにつけます。
clackupでも入出力を切り捨てていますが、こうしないとサーバーからの応答を延々と待ち続けてしまい、ログアウトされません。当然TravisCIの実行もここで止まり続けてしまうので注意が必要です。

最終的な.travis.yml
language: common-lisp
sudo: false

install:
  - curl -L https://raw.githubusercontent.com/snmsts/roswell/release/scripts/install-for-ci.sh | sh

cache:
    directories:
        - $HOME/.roswell

script:
  - ros -s prove -e '(or (prove:run :travis-test-test) (uiop:quit -1))'

env:
    global:
        - secure: "......"
        - secure: "......"
        - secure: "......"
        - secure: "......"
        - PATH=~/.roswell/bin:$PATH
        - ROSWELL_INSTALL_DIR=$HOME/.roswell

addons:
    apt:
        packages:
            - sshpass

after_success:
    - if [[ "$TRAVIS_BRANCH" == "master" ]]; then
        export SSHPASS=$DEPLOY_PASS;
        sshpass -e ssh -o "StrictHostKeyChecking"=no $DEPLOY_USER@$DEPLOY_HOST $DEPLOY_PATH/deploy.sh 1>/dev/null 2>/dev/null;
      fi

これでmasterにpushがあった時にテストが走り、成功すればデプロイ用のコマンドが実行されます。

公開鍵認証

公開鍵認証する方法もあるみたいです。これもいつかそのうち…
Travis-CI でコミットして GitHub にプッシュする - 公開鍵認証を利用してみる | そんなこと覚えてない

おわり

Linuxコマンドに関する知識が乏しかったため、自動デプロイは結構つっかかりました。しかし、自動テスト自体は非常に簡単でした。僕はRoswell登場以前の状況は分かりませんが、Roswellのおかげですね。
現状あまりセキュアではありませんが、これで自動デプロイ環境が整いました。便利ですね、ありがとうございます。

Common LispのWebアプリをVPSで動かすまでのメモ

Mathe Vital Japan*1に代わるようなクライン群に関するウェブサイトを開発しようとしています。裏側をCommon Lispで作ってみようと思い、とりあえず原型ができた感じなのでVPSで動かしてみました。
僕はUnixもサーバー周りも初心者なのでメモにしておこうと思います。

VPSドメインの契約

VPSはConoHaのメモリ1GBの一番安いものにしました。どうやら登録時に、1000円分のクーポンがもらえる登録フォームもあるみたいなのですが失念していました。悲しい。
ドメインはお名前.comで取得ました。アカウントの作成に迷いましたが、初めてのドメイン取得と同時にアカウントを作成するようになっています。
VPSドメインの契約を済ませたらVPSIPアドレスドメインを紐つけます。以下の記事を参考にしました。
お名前.comでドメインを取得してConoHaで公開するまで - Qiita

ログイン

OSはCentOS64bitの7.1、6.7、6.6をそれぞれ試しました。パッケージが新しいのでCentOS7.1の方がちょっと楽だと思います。SSHクライアントにはTeraTermを使用しました。ConoHaではWebコンソールが使用できますが、Webコンソールから操作を行うと何故かネット周りでトラブルがあり使えませんでした。例えばgitでgithubからcloneできないとか、pingやtracerouteが返ってこないとか…

ログインしたら一応パッケージのアップデートをしてgit、gccを入れておきます。

yum update
yum install git
yum install gcc

Emacsのインストール

最初からVimが入っていますが使い慣れないので最新版のEmacsを入れます。
CentOSに最新のemacsをインストールする方法 - エンジニア?プログラマ?
24.5がstableなのでインストールします。ビルドオプションはGUI関連のものだと思います。

roswellのインストール

snmsts/roswell · GitHub

yum install libcurl-devel
yum install autoconf
git clone https://github.com/snmsts/roswell.git
cd roswell
./bootstrap
./configure
make
make install

CentOS6系だとyumでインストールできるautoconfのバージョンが低いと言われるので最新版をビルドする必要があります。
autoconf のインストール - ひたすら事務

sbclのインストール

yum install zlib-devel
ros install sbcl

インストール中は止まりますが心配はないはずです。プログレスバーが全く動かないのは端末の仕様ですかね…
sbclのビルドにはzlib-develが必要です。
error in install sbcl · Issue #65 · snmsts/roswell · GitHub
最初、インストールが失敗したというエラーに気付かず、最新のsbclがビルドされたものと勘違いしていました。sbcl-binはイントールされており、普通に使えていたので気付きませんでした。もしインストールに失敗したら

ros delete sbcl

で消してからでないと再インストールできませんでした。

clackupコマンドのインストール

ros install clack
export PATH=$PATH:~/.roswell/bin

clackupコマンドをインストールしたらパスを通します。この方法は一時的なもので、再ログイン時にはリセットされてしまうそうです。永続的に追加するにはユーザーの.bash_profileをいじるそうです。
パス(PATH)の確認と設定方法は? - Pocketstudio.jp Linux Wiki

ファイアウォールの設定

CentOS6ならiptables
iptablesの設定方法|さくらインターネット公式サポートサイト
CentOS7ならfirewalld
CentOS7 firewalldの設定方法

iptablesはデフォルトでは何も設定されていないみたいなので特に設定しなくてもhttpでアクセスできますがそのままでは危ないですね。

wooのロード

サーバーのwooにはlibevというライブラリが必要です。CentOS7ならyumで入るはずですがCentOS6の場合はビルドが必要です。
ほぼ毎日更新してた、ごくうブログ:[Linux] CentOS5でメールサーバ構築(qmail + tcpserver + libev + vpopmail + qmail-conf + daemontools)
ここを参考にビルドします。

cd /usr/local/src/
wget http://dist.schmorp.de/libev/libev-4.20.tar.gz
tar xvfz libev-4.04.tar.gz
cd libev-4.04
./configure 
make
make install

これだけでは共有ライブラリは参照されないみたいなのでここを参考にパスを通します。
Tomorrow is always fresh with no mistake in it.@備忘録 - ライブラリのパスを設定する
僕は/etc/ld.so.conf.d/にlibevがおいてあるライブラリのパスを書いたファイルを置き、ldconfigで読み込みなおしました。

アプリケーションの起動

Roswell時代のCommon LispのWebアプリケーション運用 - 八発白中

clackのアプリケーションをgitなどで取ってきたらアプリケーションのルートに入って

clackup --port 80 app.lisp

でライブラリが色々ロードされてサーバーが立ち上がります。デフォルトではHunchentootが起動します。他のサーバーは--serverオプションで起動します。これでブラウザからipアドレス、もしくはドメインをを入力すればページにアクセスできるはずです。

この時、ずっと/usr/local/srcにclone等をして作業していましたが、asdfがアプリケーションのシステムを読み込めなかったとエラーが出るときがありました。~/common-lisp/というディレクトリを作成し、ここにアプリケーションを置くとロードしてくれました。asdfのパス設定の関連でしょうかね。

気になる事

Hunchentootで立ち上げると時折エラーが発生しているようです。止まる事はないのですが気になりますね。

[2015-09-10 17:09:56 [ERROR]] Error while processing connection: couldn't read from #<SB-SYS:FD-STREAM
                                                                                      for "socket 133.130.58.156:80, peer: 133.26.34.248:52675"
                                                                                      {1003825813}>:
                                                                   Connection reset by peer

wooは結局動かすことができませんでした。サーバーは立ち上がるのですが、アクセスすると以下のようなエラーが出ます。

Unhandled TYPE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                  {1002C1F513}>:
  The value 4162984581 is not of type (SIGNED-BYTE 32).

デスクトップのCentOS6.6ではlocalhostですが接続に成功したのでVPSCentOSもバージョンを入れ替えて試してみましたがどれもエラーが出てしまいました。何が悪いのかはまだわかりませんが、大量のアクセスがあるような事も速度が必要になる事もないのでとりあえずHunchentootで動かすことにしました。

追記(2015/9/17)

作者の深町さんにコメントを頂き、このプルリクエストで解決していることがわかりました。
* Fix error on ntoa : support for 64 bit address by kayhman · Pull Request #35 · fukamachi/woo · GitHub

おわり

これで一応外部からページにアクセスすることができるようになりました。それとセキュリティ面等で考慮することは色々ありそうで、これから少しずつ勉強していく必要がありますね。ひとまず、次の課題はTravisCIによる自動デプロイを試してみる事とサイトのコンテンツの開発ですね。
日々精進あるのみです。

*1:今時ジャバアプレットですよ…

クライン群をテーマにしたビジュアルパフォーマンスソフトを作ってみた

最近クライン群をテーマにしてVJっぽいことをするプログラムを開発していました。とりあえず動くようになってデモを作成したのでちょっと記事にしておきます。

www.youtube.com
github.com

BSoD2.0という映像パフォーマンスソフトを実際にクラブで試してみようというイベントのために開発を始めました。20分という長丁場だったのですが、そこそこ楽しめてもらえたようなので良かったです。
現場にはRolandのビデオミキサー、V-4EXがあり、映像にエフェクトがかけられたのですが、本番で使い方に戸惑い結局使えませんでした。鏡映とか面白そうだったんだけどなぁ。

中身

本当はCommon Lispで作成したかったのですが、1週間しか時間がなかったのと早いコードが書けなかったので諦め、既にジャバで組んであったクライン群のプログラムをパフォーマンス的な味付けを加えて一つにまとめました。
現在は3つのシーンで構成されており、Korg NanoKONTROL2とマウスで操作するようになっています。
現状、MIDIコントローラのボタンのマッピングも酷いですし、NanoKONTROL2がないと全く操作できないので他の人が使えるようにはなっていません。

放物型交換子群

soma-arc/KleinianWalker · GitHub

書籍、インドラの真珠において、おばあちゃんの放物型交換子群として載っている生成元のレシピから生成される群の極限集合と別の図形を変換させた軌道を描くソフトウェアです。マウスによる操作で蝶が動きます。
パラメータによっては計算に時間がかかるのでリアルタイムで極限集合をアニメーションさせるようなことはできませんでした。蝶が右に移動すると次のパラメータに移るようになっています。

こちらのサイトの方に影響を受けて作成しました。僕のとはクオリティが段違いですね。
http://bugman123.com/Fractals/index.html

接触ショットキー


4つの円盤が連なるものです。高速回転で万華鏡っぽくなったり、極限集合の位置をトレースしてカメラが動くなどの機能があります。

一点穴あきトーラス群(Once Punctured Torus Group)

soma-arc/JOPTG · GitHub

まだ完成してはいませんがOPTiというソフトウェアを再実装したものです。
得られる絵が多様なので実質パフォーマンスのメイン部分と言える感じになっています。
これは二つの制御点から一転穴あきトーラス群の極限集合を計算しています。この極限集合は平行移動で重なるので、放物型交換子群に比べ、計算量が少なく、割と高速に動きます。
欠点はパラメータと最大探索レベルを間違えると計算が終わらなくなってしまうという危険性があることです。動画でもところどころ止まっていますね…
パラメータが変なところにいくと非離散的な群が生成され、図が崩れます。

ここら辺の詳しい話は数学的なのでインドラの真珠などの書籍を参照してください。これはもうクライン群とは言えなくなってしまうので数学的には意味をなさないのですが、点で描画するとなかなか綺麗になります。

他にはDataRacketからとってきたloud情報に合わせてパラメータが動いたり、回転を加えたりできます。点による描画にすると、意図せずして、IFS(反復関数系)によるフラクタルのようになりました。本当はこれにモーションブラ―やガウシアンフィルタをかけたりすることでより美しくなるのです。


今後の展開

今回はジャバの2D機能だけで描画していますので、OpenGLベースで作成したいですね。

  • シーンを増やす

三次元形状やシェーダを活用した表現も行いたいです。

  • エフェクト

シーンの切り替え時にノイズエフェクトをかける等のエフェクトを実装。

  • CUDAサポート

高速であれば表現の幅が広がりますね。問題はNVidiaGPUを積んだノートPCを持っていないと外でデモれない事ですね…

  • 音への反応の改良

特にアシッドフレーズにうまく反応するようなプログラムが書きたいです。

Common Lisp + DataRacketで音を使った作品を作る

Data Racket | Ethno Tekhを使用すれば解析された音声データをOSC(Open Sound Control)で簡単に受け取ることができます。

Common Lispにはcl-oscというOSCをデコードするライブラリがあります。OSC自体はUDPプロトコルなので、UDP通信するためのコードを書かなくてはなりません。cl-oscのサンプルではsbclに依存したコードが載っています。僕が使っていた処理系はClozureCLなので、処理系ポータブルな通信ライブラリusocketを使用してOSCを受信するコードを紹介します。

usocketを用いてUDP通信を行うサンプルコードを書いている方がいたので、参考にさせてもらいました。
Short guide to UDP/IP Client/Server programming in Common Lisp using usockets · GitHub

OSCを受信するサンプル

(ql:quickload '(:usocket :osc))

(defparameter *port* 9000)

(defun create-server (port)
  (usocket:socket-connect nil nil
			  :protocol :datagram
			  :element-type '(unsigned-byte 8)
			  :local-host "127.0.0.1"
			  :local-port port))

(defparameter *osc-sock*
  (create-server *port*))

(defun start-receiving (socket buffer)
  (format t "start server~%")
  (unwind-protect
      (multiple-value-bind (buffer size client received-port)
	  (loop do
		(usocket:socket-receive socket buffer 1024)
		(let ((message (osc:decode-bundle buffer)))
		  (format t "received -=>~S~%" (osc:decode-bundle buffer))
		  (if (string= (car message) "stop") (return)))))
    (usocket:socket-close socket)
    (format t "exit~%")))

(start-receiving *osc-sock*
		 (make-array 1024 :element-type '(unsigned-byte 8)))

起動して、DataRacketからOSCが入ってくると以下のように出力されます。

received -=>("/audio/bright" 0.017748356)
received -=>("/audio/noise" 0.32115465)
received -=>("/audio/loud" 0.43585107)
received -=>("/audio/fft" 0.31239712 0.270671 0.5963343 0.5104574 0.4887981 0.5261438 0.55091 0.21614692 0.20689762 0.17976543 0.08880567 0.13944802 0.124899484 0.12268175 0.13263442 3.1389509E-4 0.045346215 0.031639766 0.014442262 0.008829511 0.025995951 0.012009757 0.0 0.0 0.0)

cl-oscの仕事はdecode-bundleでデコードすることのみです。
気になるのが終了時の処理ですね。外側から

(usocket:socket-close *osc-sock*)

を呼び出してやるとエラーが発生してしまいます。以下のようにサーバーを止めるクライアントを作成し、stopメッセージを送る関数を作成してみました。

(defun send-stop-msg (port)
  (usocket:with-client-socket (sock nil
				    "127.0.0.1"
				    port
				    :protocol :datagram
				    :element-type '(unsigned-byte 8))
    (let ((stop-msg (osc:encode-message "stop")))
      (usocket:socket-send sock stop-msg (length stop-msg))
      (usocket:socket-close sock))))

実践

これでCommon Lispで音に反応するプログラムを作る準備が整いましたね。
今回はcl-glutを利用した、以下のような簡単なサンプルを用意してみました。
DataRacket + Common Lispなサンプル · GitHub

www.youtube.com

cl-glut-examplesのglut-teapotを改造したもので、teapotの大きさが音に合わせて変わります。マウスドラッグで回転します。サーバーはrun関数が呼び出される際に起動され、ウィンドウが閉じられた際に終了するようになっています。

windows8.1、64bitのClozureCL64bitで動作確認しています。恐らくスレッド対応している処理系なら動くはず。windowsの場合、処理系のbitに合わせたfreegluit.dllが必要です。

DataRacketの使い方は、起動した後に適切な設定をするだけです。windowsの場合、録音デバイスをステレオミキサー等に設定し、DataRacket側のdeviceも適切に設定します。僕の場合、devicead_portaudio Windows DirectSoundに設定すると音をとってくれました。

パラメータをいじる

OSCが受信されるたびに、loudからティーポットの大きさ、FFT結果から色のパラメータを変化させています。

(defun process-msg (message)
  (if (string= "/audio/loud" (car message)) (setf *scale* (+ 0.2 (* 3 (second message)))))
  (if (string= "/audio/fft" (car message))
      (progn
	(setf *diffuse-r* (+ 0.3 (* 2 (second message))))
	(setf *diffuse-g* (+ 0.3 (* 2 (elt message 5))))
	(setf *diffuse-b* (+ 0.3 (* 2 (elt message 10)))))))

上記のprocess-msg関数あたりをいじくりまわしてみると面白いのではないでしょうか。実行しつつパラメータを動かした結果を見ることができるので非常に楽しいですね。

おわりに

実際に作ってみるとわかるのですが、取得した値をどう利用するのかというのはとても難しいです。キック等のパターンはある程度とれたりしますが、正確に音と同期させるのは難しく、アクセント程度にしかならない場合も多いです。この辺はBPM検出したりすると良いという話など色々ありますが、製作者の工夫次第でしょうね。

ジャバでOSC(Open Sound Control)を扱うメモ

DataRacketというソフトウェアがあります。これは音声データをリアルタイムに解析し、各種データをOSC(Open Sound Control)プロトコルで送信してくれるという優れものです。このソフトを使うことで簡単に音に反応するようなプログラムが作れます。

さて、ジャバでOSCを扱うライブラリにJavaOSCが存在します。このライブラリを使用すればジャバで簡単にOSCを扱うことができます。

サンプルコードが見つかりにくかったので使用法と共にメモしておきます。

受信

受信は以下のようなコードでできます。当然ですが終了時にreceiverをcloseするのを忘れるとreceiverが残り続けるので注意してください

OSCPortIn receiver = null;
try {
    //9000番ポートで受信
    receiver = new OSCPortIn(9000);
} catch (SocketException e2) {
    e2.printStackTrace();
}
OSCListener loudListener = new OSCListener() {
	public void acceptMessage(Date time, OSCMessage message) {
	    System.out.println("loud received!");
	    System.out.println(message.getAddress());
	    for(Object ob : message.getArguments()){
		      System.out.println((float) ob);
	    }
	}
};
OSCListener fftListener = new OSCListener() {
	public void acceptMessage(Date time, OSCMessage message) {
	    System.out.println("FFT received!");
	    System.out.println(message.getAddress());
	    for(Object ob : message.getArguments()){
		      System.out.println((float) ob);
	    }
	}
};
receiver.addListener("/audio/loud", loudListener);
receiver.addListener("/audio/fft", fftListener);
receiver.startListening();

リスナーを定義し、receiverに加えるだけですね。addListenerの第一引数はデータに指定されているアドレスです。今回はDataRacketからloudとfftを取得しています。message.getArguments()には受け取ったデータが詰まっています。loudに入っている値は一つですがfftには複数の値が入っています。また、DataRacketから送信される値はfloat型なので取得時にキャストしてやります。

送信

あまり使わないかもしれませんが送信も。

OSCPortOut sender =  null;
try {
    //ローカルホスト、9001番ポートへ送信
    sender = new OSCPortOut(InetAddress.getLocalHost(), 9001);
} catch(Exception ex){
    ex.printStackTrace();
}
Object args[] = new Object[1];
args[0] = "hello";
OSCMessage msg = new OSCMessage("/sayhello", args);
try {
    sender.send(msg);
} catch (Exception e) {
    e.printStackTrace();
}
sender.close();

"/sayhello"アドレスに"hello"というメッセージを送っています。

Midi2OSC

JavaOSCを使用してMIDIメッセージをOSCに変換して送信するプログラムを作成しました。
soma-arc/Midi2OSC · GitHub

見た目からして酷いですし人様に使ってもらうようなものではないのですが、Common LispMIDIコントローラを使用するために作成しました。Common LispMIDIファイルを扱うライブラリは見つけられたのですが、MIDIポートに接続してコントローラからの値をリアルタイムに取得するようなライブラリは見つからなかったので、ジャバで受け取ってOSCで送信してしまうことにしました。ジャバならポータブルになるでしょうしね。
使用すると/midi/midiチャンネル/コントロールidというアドレスに対してコントローラの値が送信されます。あとはCommon Lisp側でcl-osc、usocketを用いてoscの受信、デコードをするだけです。これは次の記事になるかと。