Processing日記(5)
長嶋 洋一
(一部 SuperCollider日記かも)
2012年3月14日(水)
なんと前回(Part4)からちょうど7ヶ月ぶりである(^_^;)。 SuperCollider日記の方は、 今月初旬、それでも半年ぶりだがちょっとだけ進んだものの、Processingは完全に放置していた(^_^;)。 もちろん、 ジャミーズ娘+など、 色々なプロジェクトを進めていたのでサボッていた訳ではないのだけれど。メディア造形学科の後期入試は定員5人に110人出願(22倍)。前期の実技の2科目それぞれ180分、そして後期の実技240分、 と全ての実技試験監督中「絶対に座らない」と決めたポリシーを守って計10時間、立ち続けて心の中で応援した。 来週の判定会議を経て合格発表、これで本年度の入試シーズンも終了である。 明日は卒業式ということで、学生委員会の他に予定もなく、ぽっかりと空いたので、ここで思い出したようにProcessingである。
ちょうど、 こんなページ を作ったところだったのを思い出したので、まだやっていなかった、 「ProcessingでGainerを使う」 というのを試してみよう、という気になった。 小林茂さんがGainerのサイトで、MaxとFlashとProcessingとを対等にサポートしているので、まずは Gainerのサイト に行くことになるが、とりあえず道具立てをMaxで確認してみると、 以下のようにちゃんと4個のグリップでそれぞれ対応するスライダーが動いた。 Gainerのポートはここではいつもの「b」でなく「a」である事を確認した。
そこで、 Gainerのサイト に行ってみると、ちゃんと Processingのチュートリアル がある。 まずは ソフトウェア・ライブラリ ということで、 ダウンロード のページに行く。 このMacでは、すでにMaxでGainerが動いているので、同じ「USBドライバ」のインストールは不要である。 そこで、「Gainer(最新版) ソフトウェア・ライブラリ」の「Processing (1.1.0 RC5) 」をクリックして 「gainer_lib_processing_v1-1-0rc5.zip」をダウンロードして解凍する。 その中身は以下のようになっている。 さすがProcessing、内部的にはJavaベースなのであった。
ここで セットアップ:ライブラリのインストール に従って、Processingのフォルダ等に必要なものをコピーするのだという。 なんと最後には「設定完了したら、ターミナル画面を閉じ、すぐに電源を切ってください(再起動ではだめです)」とあった。 これはなかなか厳しい(^_^;)。
「Processingは/Applications/Processing/にインストールされているとします。」 とあったが、以下のように、Processing.appがあるだけで、どうも環境が違うようである。
探してみると、 「/Applications/Processing/lib/keywords.txtのバックアップをとります 」 ということだったが、以下のように、「/lib/」も「keywords.txt」も無かった(^_^;)。 しかしこの下に「/libraies/」があったので、 このコンピュータの場合には、どうやら 「/Applications/Processing/」 は 「/Users/nagasm/Documents/Processing/」 に対応しているようである。
そこで、「keywords.txt」のバックアップは無視して、 「libraries → /Applications/Processing/libraies/」 に従ってこの下にある「gainer」フォルダをコピーし、 「reference → /Applications/Processing/reference/libraries/」 というのは悩んだ末に「/Applications/Processing/」の直下にコピーし、 「lib → /Applications/Processing/lib/」 というのも同様に「/Applications/Processing/」の直下にコピーした。 また 「examples/gainer_examples → /書類/Processing/」 というのは、「oscP5」にならって「gainer」の下にその中身を配置した。 結果として、以下のようになった。
「次に、シリアル通信を使えるようにします。Processingの配布パッケージに設定用のコマンドが含まれていますので、それを実行します」 とあり、 「/Applications/Processing/libraries/serial/macosx_setup.command」 とあったが、こんなものはどこにも無い(^_^;)。 コンピュータ全体を検索しても見当たらないので、既にMaxでUSBSerialが動いているので、 たぶん動くのではないか・・・と推定して、この部分を無視することにした。 当然、電源オフも再起動もナシでそのままである。
そうなれば、もうとりあえずはサンプルである。 以下のように、「examples」の中に「LED」というのを発見した。 とりあえず「LED.pde」をダブルクリックしてみるとProcessingが起動し、 走らせてみると、ちゃんと「マウスのクリックに対応してGainer上のLEDが点滅」してくれた。 これはつまり、「ProcessingがGainerと繋がった(^_^)」という事である。
void setup() { size(500, 500); frameRate(20); background(255); } void draw() { fadeToWhite(); stroke(mouseX, 0, mouseY); ellipse(mouseX, mouseY, 10, 10); } void fadeToWhite() { noStroke(); fill(255, 10); rectMode(CORNER); rect(0, 0, width, height); }
ただし、Javaアプレットに書き出してみたが、ブラウザ上のアプレットとしては動作しなかった。 Gainerを使う場合には、Processing上で、ということだろうか。 そういえば、遠い記憶で、MAFのワークショップで、小林さんが紹介してくれた「funnel」が、 Web上からリアルワールドを制御していたような気がする。 あれはArduinoだったが、Gainerではどうなのかなぁ。
さらに、「examples」の中に「DualAxis」というのを発見した。 見てみると、Gainerのアナログ入力を2チャンネル使って、 その値で3次元空間内の正方形の板を、2軸で回転させる、というものらしい。 実行してみると以下のようになった。 これでクリアになったのは、 「gainer = new Gainer(this);」 でGainerを初期化して、あとは「gainer.peekAnalogInput();」と「float ax = gainer.analogInput[0];」などで値が取れる、ということである。 どこでGainerの「モード1」を指定しているのかは不明だが、 少なくともこれで、このシステム(センサ)の4チャンネルの情報はイタダキである。
import processing.gainer.*; Gainer gainer; PFont myFont; float rSize; // rectangle size void setup() { size(300, 300, P3D); myFont = loadFont("CourierNewPSMT-24.vlw"); textFont(myFont, 24); rSize = width/4; noStroke(); fill(204, 204); frameRate(30); gainer = new Gainer(this); } void draw() { background(0); gainer.peekAnalogInput(); float ax = gainer.analogInput[0]; float ay = gainer.analogInput[1]; float pitch = asin((ax-128)/128); float roll = asin((ay-128)/128); text("pitch: " + pitch ,10,140); text("roll: " + roll ,10,170); //float dt = TWO_PI/255; translate(width/2, height/2); rotateX(pitch); rotateY(roll); //rotateX(dt*mx); //rotateY(dt*my); rect(-rSize, -rSize, rSize*2, rSize*2); }
こうなれば、もう後はここまでのProcessingの復習である。 たしかスクリーンの外側の描画は無視されたので、 ズボラな発想であるが、4系統のセンサ入力ということで、
という安易な構想を立ててみた。 どことなく、 ジャミーズ娘+ のスクリーンとも通じるところがありそうだ。 そこで過去のProcessing日記を発掘して作ってみたのが、以下である。 ジョイスティックの電圧出力値はそれぞればらついているので、 トライアンドエラーでスケーリングしているが、ちゃんとそれぞれの握り具合で、 四隅からの円が刻々と拡大縮小した。
- スクリーンを正方形にする
- 正方形の4つの頂点を中心とする円を描く
- その円の半径が、それぞれのセンサ出力に対応
import processing.gainer.*; Gainer gainer; int r, r0, r1, r2, r3; void setup() { size(500,500); fill(255); gainer = new Gainer(this); } void draw() { background(0); gainer.peekAnalogInput(); r0 = (int) 8.8 * ( gainer.analogInput[0] - 56); ellipse(0, 0, r0, r0); r1 = (int) 9.6 * ( gainer.analogInput[1] - 76); ellipse(0, 499, r1, r1); r2 = (int) 8.2 * ( gainer.analogInput[2] - 67); ellipse(499, 0, r2, r2); r3 = (int) 15.9 * ( gainer.analogInput[3] - 99); ellipse(499, 499, r3, r3); }
さて、ここまで出来てくれば、次にはさらに「それぞれのマウスの握り具合に対応した音が出る」という機能も実装したい。 Max/MSP/jitterで作ればモノの数分であるが、ここはSuperColliderの出番だろう。 すでに SuperCollider日記の 「2011年8月21日(日)」のところで、 ProcessingからOSC経由でSuperColliderを鳴らす、というのを実現していたことを発掘した。 このサンプルをここでのプログラムと組み合わせることで、
というシステムが実現されることになる。 仕組みとしては、これはまさに「サウンド・インスタレーション」の一般的な構造そのものである(^_^)。
- Gainerでセンサ入力
- そのセンサの値に対応してProcessingでリアルタイム描画
- 同時にProcessingはその値をOSCで送出
- SuperColliderがこのOSCメッセージを受けてサウンドを生成
SuperCollider日記では、 手探りでの実験のために、同時にMaxも走らせていたが、ここでは敢えて、Maxでのデバッグ無しに挑戦しよう。 まず、とりあえずは前の例と同じ、 「OSCを受けてサウンドを鳴らし、postウインドウにメッセージをモニタ表示するSuperColliderプログラム」 というのを、ピッチの対応だけちょっと変更して以下のように走らせておく。
( SynthDef( \p55synth, { arg freq= 440; var signal, env; env = EnvGen.ar(Env.perc, doneAction:2); signal = SinOsc.ar([freq, freq+1], 0, 0.8) * env; Out.ar(0, signal); } ).load(s); r = OSCresponder( nil, '/test', { arg time, resp, msg; [msg].postln; Synth( \p55synth, [ \freq, 400 + msg[1] ] ); } ).add; )
そしてあとは、さっきのGainerをセンシングするProcessing描画プログラムに前の例のProcessingのOSC部分を組み込めばいいわけである。 うまく行けば音が出るし、ProcessingでトラブってもSuperColliderの方は無関係に走っているので、これはまさに試行錯誤パラダイスである。 とりあえずMaxにOSCで送るポートも、受け手はいないが残しておこう。 するとものの数分で、以下のようなProcessingプログラムで、リアルタイムCGはそのまま走りながら、 とりあえずGainerの第1チャンネルの握りに対応してピッチが見事に制御できた(^_^)。
import processing.gainer.*; import oscP5.*; import netP5.*; Gainer gainer; OscP5 oscP5; NetAddress myBroadcastLocation1, myBroadcastLocation2; int r, r0, r1, r2, r3; void setup() { size(500,500); fill(255); oscP5 = new OscP5(this,8000); // myBroadcastLocation1 = new NetAddress("127.0.0.1",7000); myBroadcastLocation2 = new NetAddress("127.0.0.1",57120); gainer = new Gainer(this); } void draw() { background(0); gainer.peekAnalogInput(); r0 = (int) 8.8 * ( gainer.analogInput[0] - 56); ellipse(0, 0, r0, r0); r1 = (int) 9.6 * ( gainer.analogInput[1] - 76); ellipse(0, 499, r1, r1); r2 = (int) 8.2 * ( gainer.analogInput[2] - 67); ellipse(499, 0, r2, r2); r3 = (int) 15.9 * ( gainer.analogInput[3] - 99); ellipse(499, 499, r3, r3); OscMessage myOscMessage2 = new OscMessage("test"); myOscMessage2.add(r0); myOscMessage2.add(r1); myOscMessage2.add(r2); myOscMessage2.add(r3); oscP5.send(myOscMessage2, myBroadcastLocation2); }
このままで1チャンネルを4チャンネルに増設したら、騒々しいだけである。 ここから、SuperColliderの音源を4チャンネルごとに異なるテイストのサウンドとして、 さらにProcessingのグラフィクスもチャンネルごとに変えていけば、 まさにグリップ版の ジャミーズ娘+ はすぐそこである。 半日仕事としてはまずまず進んだので、今日はここまでとしよう。 明日は卒業式、美味しいワインが楽しみである。
→ さらに数年後にチラッとProcessingしました
「日記」シリーズ の記録