1/18は西宮でダンス公演

映像・音響・ダンス・オブジェによる即興パフォーマンス
ダンスの時間スペシャル「Earthen Bodies(陶製の身体)」

日時:2007.01.18(木) 開場19:00 開演19:30
場所:兵庫県立芸術文化センター

ダンス:森美香代、ヤザキタケシ、安川晶子、サイトウマコト
オブジェ:オブジェ:大西文博(丹文窯)
映像・音楽:赤松正行+IAMAS/DSP/MIRAGEチーム

実力派コンテンポラリー・ダンサー4人組と丹波立杭焼きのオブジェ、そしてIAMAS精鋭チームによるコラボレーション公演。IAMASからは画像解析技術をベースにアグレッシブな映像と音響の即興演奏を展開します。乞う!ご期待。

earthenbodies.jpg

send/receive/valueを探せ

パッチ・コードを使わずにメッセージをやりとりできるsendとreciveは便利なのですが、使い過ぎるとどこからどこへメッセージが送られているか、訳が分からなくなります。特に大規模なパッチを書いた時や他の人が書いたパッチを読み解く時に困りますね

そんな時は、sendまたはreceiveのオブジェクト・ボックスをダブル・クリック。これで同じ名前を使っているsend/receiveオブジェクトがポップアップ・メニューに表示されます。このメニュー項目のいずれかを選ぶと、そのパッチ(またはサブ・パッチ)が一番手前に開くようになっています。次の図は、actionという名前を指定したreceiveオブジェクトをダブル・クリックしたところ。

sendreceive-popup-menu.gif

メニュー項目の後半の括弧内は、そのオブジェクトが属しているパッチの名前で、鍵括弧付きならサブ・パッチの名前です。このメニューには同じ名前を持つvalueオブジェクトも表示され、valueをダブル・クリックしても同じメニューが表示されます。ただし、send/receiveとvalueは別物なので、sendに送ったメッセージがvalueに格納されるわけでも、valueに送ったメッセージがreceiveから出てくるわけでもありません。

ちなみに、ここで言う名前はオブジェクトのアーギュメントとして指定する名前のことで、ObjectメニューのName…で付けるオブジェクト名ではありません。それから、パッチが開くのはいいんだけど、そのオブジェクトが選択されるわけではないので、パッチ内のどこにあるかは、EditメニューFind…を使わなければなりません。それくらい自動選択してくれればいいのにね。

Find…に関して言えば、Multiオプションをオンにしておくと、サブ・パッチを含めて現在開いているパッチをすべて次々と検索してくれるので、この方法も便利に使えますね。

なお、valueに似たpvにはポップアップ・メニュー機能はありません。pvは同一パッチ内でしか有効でないので、Findで探してくれ、ってことでしょうか。同じように、同一パッチ内で動作するpvarやpattrなども、この機能はありません。しかし、パッチを超えてシグナルをやりとりできるsend~やreceive~も、この機能を持っていないので、ちょっと片手落ちですね。

BootCampとParallels Desktop

Intel-MacでWindowsを起動するBootCampやParallels Desktopで、Windows用Max/MSP/Jitterを利用するには、現状ではBootCampを使うしかないようです。BootCampでの動作は細かな所までチェックしていないんだけど、特に大きな問題なくMaxが動いています。私はiLokキーを利用していますが、Challenge &Response方式でも大丈夫かな。

一方のParallelsでは、コピー・プロテクションのPACEが仮想技術に対応していないので、Maxが起動しないそうです。ということは、近く登場するVMWareでもダメということになります。こーゆー本質的でない部分で動作しないのは悲しいですね。ちなみに、コピー・プロテクションがないRuntimeは起動します。

もちろん、Intel-MacならMac OS XでMaxを動かせば良いのですが、たまにWindowsでパッチの動作を確認したい場合やWindows版しかないオブジェクトを試したい場合がありますからね。そんなちょっとした用途なら、コンピュータを再起動するBootCampは面倒で、アプリ起動だけのParallelesで済ませたいわけで、PACEには早急に対応して欲しいところです。

もうすぐIAMAS一般入試

来週から、赤松がDSPコースを担当しているIAMAS(アカデミー)の一般入試の出願が始まります。このサイトのニュースを見て申し込みました、と書いてもらうと特典があります、てなわけないですが、ユニークな人にぜひトライして欲しいです。

詳しくは、IAMAS入学案内をご覧になってください。

ここで書くのもどうかな?と思いますけど、以前の入試で気がついたら出願期間が終わっていたという方もいらっしゃったので、ご案内する次第です。

UBオブジェクト開発講座 休題

UBオブジェクト開発講座は、3回分が終わったところで一休みです。後から見直すと、他の記事との景観が合いませんね〜特に第3回は記号多過ぎ分量多過ぎでございました(苦笑)。また、投稿逆順に並ぶブログ形式と連載形式も合いませんね。個人サイトに書くほうが良いかもしれませんが、情報が分散するのもイヤなので、DSPマガジン亡き現在、このサイトに集約しておこうと思うわけです。

内容としても、多くの人にとっては興味がないというかチンプンカンプンだとは思うのですが、とりあえず書いておけば、いつか誰かの役に立つかもといった程度なので、軽く流しておいてください。また、この後の展開も、例えばデバッグとかOS APIとかいろいろと考えられるわけですが、さてさて、どうなんでしょうか?

UBオブジェクト開発講座(3) ソース・コードの概要

第3回UBオブジェクト開発講座は、サンプルとして提供されているmaximumオブジェクトを題材に、そのソース・コードの概要を説明します。これは、以前に公開した「Maxオブジェクト開発技法」から主要部を抜き出し、MaxMSP UB SDK用にアップデートしたものです。

日本語コメントを付けたソース・コードは、こちらからダウンロードしてください。
maximum-jcommented.zip

以下は要点のみをザザっと俯瞰しています。

■処理の概要

Maxオブジェクトのソース・コードは、大きく3つの部分から構成されています。

(1) メイン関数 main()【必須】

Max起動時やパッチを開いた時など、オブジェクトが読み込まれた時に呼び出され、クラスとして必要な初期化などの設定を行います。具体的には、以下の2つの処理が必須ですが、必要に応じてその他の処理を行っても構いません。
・クラスの設定を行う。setup()【必須】
・メッセージ処理関数を登録する。【ほぼ必須】

(2) メッセージ処理関数 maximum_bang()など【ほぼ必須】

オブジェクトにメッセージが送られた時に対応する関数が呼び出されます。メッセージ処理関数の引数は、その登録によって異なります。

(3) オブジェクト生成関数 maximum_new()【必須】

オブジェクト生成時に呼び出され、インスタンスとして必要な初期化などの設定を行います。具体的には、以下の3つの処理が必須ですが、必要に応じてその他の処理を行っても構いません。
・オブジェクトを生成する。newobject()【必須】
・アーギュメントの処理、インレット、アウトレットの作成などを行う。
(右から左への順序で。第1インレットはnewobject()が自動的に作成する。)
・生成したオブジェクトへのポインタを関数の戻り値として返す。【必須】

なお、maximumでは必要がありませんが、オブジェクト生成関数において、メモリの確保やデバイスのオープンなどを行った場合は、オブジェクト消滅関数を登録(setup()の3番目の引数で指定)し、その関数でメモリの解放やデバイスのクローズなどの処理を行うようにします。

■メッセージ処理関数の登録

メッセージ処理関数を登録するには、以下の関数を用います。これらはext_proto.hに定義されています。

void addbang(method f); // bangメッセージ処理関数の登録
void addint(method f); // 整数メッセージ処理関数の登録
void addfloat(method f); // 実数メッセージ処理関数の登録
void addinx(method f, short n); // 第nインレットでの整数メッセージ処理関数の登録
void addftx(method f, short n); // 第nインレットでの実数メッセージ処理関数の登録

fはメッセージ処理関数へのポインタ、nはインレット番号(0始まり、第2インレットは1)

void addmess(method f, char *s, short type, ...); // 任意のメッセージ処理関数の登録

sはメッセージ文字列、typeはアーギュメントのデータ・タイプで、アーギュメントの数に応じて並べ、最後は0で終えます。詳しくは、次の「メッセージ処理関数への引数」最後の部分を参照してください。

オブジェクトがメッセージを受け取る時に、登録されたメッセージ処理関数に従って、メッセージやアーギュメントがチェックされ、一致しなければ自動的にエラーとなります。

■メッセージ処理関数への引数

メッセージ処理関数の種類によって、以下のように受け取る引数は異なります。

bangメッセージ処理関数は、次の引数を受け取ります。

void maximum_bang(t_maximum *x)

xはオブジェクト構造体へのポインタを表します。
bangメッセージはアーギュメントを持ちませんから、これ以外の引数はありません。

整数メッセージ処理関数は、次の引数を受け取ります。

void maximum_int(t_maximum *x, long n)

xはオブジェクト構造体へのポインタ、nは送られた整数を表します。

リスト・メッセージ処理関数は、次の引数を受け取ります。

void maximum_list(t_maximum *x, t_symbol *s, short ac, t_atom *av)

sはメッセージのシンボル(list)、acはリストの要素数、avはリストの最初の要素へのポインタを表します。

「jack n m」というメッセージの処理関数は以下のようになります。ここでは、nとmは整数で、nは省略不可、mは省略可能とします。

void maximum_jack(t_maximum *x, long n, long m)

xはオブジェクト構造体へのポインタ、nとmは送られた整数を表します。

なお、このメッセージ処理関数を登録するには、以下のように記述します。

addmess((method)maximum_jack, "jack", A_LONG, A_DEFLONG, 0);

■データ・タイプ

Maxが用いるデータの種類を表すデータ・タイプは、ext_mess.hに以下のように定義されています。

#define A_NOTHING 0 // 無(データはないことを示す)
#define A_LONG 1 // 整数
#define A_FLOAT 2 // 実数
#define A_SYM 3 // シンボル
#define A_OBJ 4 // オブジェクト、アーギュメントの配列
#define A_DEFLONG 5 // デフォルト値が0である整数
#define A_DEFFLOAT 6 // デフォルト値が0.0である実数
#define A_DEFSYM 7 // デフォルト値が""であるシンボル
#define A_GIMME 8 // アーギュメントの配列、t_atomの配列であることをチェック
#define A_CANT 9 // タイプチェック不能/不要であるアーギュメント
#define A_SEMI 10 // ;(セミコロン)
#define A_COMMA 11 // .(コンマ)
#define A_DOLLAR 12 // $(ドルマーク)
#define A_DOLLSYM 13 // $(ドルマークのシンボル)
#define A_GIMMEBACK 14 // アーギュメントの配列、関数でチェックして戻す

■データ構造

Maxのデータ(整数、実数、シンボル)はすべてt_atom(Atom)構造体で表され、データの種類を表すデータ・タイプと実際のデータ値の2つの要素から構成されています。データ値は共用体として、異なるタイプのデータが納められるようになっています。

union word // データ値の共用体
{
long w_long;
float w_float;
struct symbol *w_sym;
struct object *w_obj;
};

typedef struct atom // データの構造体
{
short a_type; // データ・タイプ
union word a_w; // データ値
} t_atom, Atom;

例:t_atom *data の場合、
データの値を参照するには、データ・タイプを確認した上で、データの値を取り出します。例えば、データが整数である場合は、以下のようになります。データ・タイプが明確であれば、データ・タイプの確認は省略しても構いません。

if (data->a_type == A_LONG)
value = data->a_w.w_long;

データに値を代入する場合は、データ・タイプを設定した上で、実際の値を代入します。例えば、整数を代入するには以下のようになります。

data->a_type = A_LONG;
data->a_w.w_long = 100;

UBオブジェクト開発講座(2) オリジナル・オブジェクトの作成

UBオブジェクト開発講座の第2回は、オリジナルのオブジェクトを作成する方法で、要は既存のサンプル・プロジェクトの複製を作り、必要な箇所を変えれば、ハイ出来上がり、というわけです。ここでの説明は「Copying An Example Project」の抄訳を元に、多少の補足を加えています。

Step 1: Finderでmaximumフォルダの複製を作り、フォルダ名を変える。ここではgoofyという名前とする。goofyフォルダは、c74supportフォルダと同じ階層のフォルダ(例えば、example-externsフォルダ)に納めるのが良い。

Step 2: goofyフォルダを開き、Xcodeのプロジェクト・ファイル名を変える。ここでは、goofy.xcodeprojという名前とする。

Step 3: 既に作成しているC言語のソース・ファイルがあれば、それをプロジェクト・フォルダにコピーする。なければ、maximum.cを自分が用いる名前に変える。ここでは、goofy.cという名前とする。

Step 4: Info.plistファイルをダブル・クリックする。Property List Editorが起動して、Info.plistファイルが開かれるので、以下の項目を変更する。
– CFBundleExectuableを作成するオブジェクトの名に変更する。ここでは、goofyとする。
– CFBundleIdentifierをJavaスタイルでの識別子として名前を変更する。ドメイン名を所有しているなら、それを用いる。ここでは、org.akamatsu.goofyとする。

Step 5: Info.plistファイルを保存し、Property List Editorを終了する。

Step 6: プロジェクト・ファイル(goofy.xcodeproj)をダブル・クリックする。Xcodeが起動し、プロジェクトが開かれる。

Step 7: ソース・リストから、不要なファイルを削除する。ここではmaximum.cを削除する。削除を確認するダイアログが現れるので、「参照を削除」ボタンをクリックする。

Step 8: 自分のソース・ファイル(goofy.c)をプロジェクトに追加する。具体的には、Finderからソース・ファイルをドラッグし、左側のリストのSourceフォルダにドロップすれば良い(右側のリストにはドロップできない)。ファイル追加に関するダイアログが現れるので、そのままOKボタンをクリックする

Step 9: プロジェクト・メニューから「アクティブターゲット’maximum’を編集」を選ぶ。

Step 10: 「”ターゲット”maximum””の情報」ウィンドウが開かれるので、一般タブを選び、名前を変更する。ここではgoofyという名前にする。

Step 11: ビルド・タブを選び、構成メニューから「すべての構成」を選ぶ。そして、コレクション・メニューから「パッケージング」を選び、プロダクト名を変更する。ここではgoofyという名前にする。

Step 12: 以上で設定は完了。ビルド・ボタンをクリックすれば、オブジェクト・ファイルが作られる。

Step 13: オブジェクト・ファイルが作成できれば、Maxを起動してオブジェクトの動作を確認する。Defaultフォルダにgoofy.help(あるいはgoofy-test.patなど)といったテスト用のパッチ・ファイルを作ると良い。

実際のオブジェクト開発では、ソース・コードをいかに記述するかが肝心カナメとなるわけですが、これについてはUBオブジェクト開発講座(3)にて説明。

UBオブジェクト開発講座(1) SDKのインストールとサンプルのビルド

細かなことはさておき、ササっとUB(ユニバーサル・バイナリー)オブジェクトを開発する方法を概観してみます。より詳しい説明はCycling ’74のWEBサイトに 「Max/MSP Universal Binary SDK Documentation」が掲載されていますので、参照してください。ちなみに、Windows用のオブジェクトを開発した経験がないので、誰か書いてくれるとウレシイな。

さてさて、UBオブジェクト開発講座の第1回はSDK(ソフトウェア・デベロップメント・キット)のインストールとサンプルのビルドまで、です。これは「Getting Started」の抄訳を元に多少の補足をしています。

Step 1: Xcodeをインストールする

・UBオブジェクトの開発には、Xcode 2.2.1以降とMac OS X 10.4が必要である。
・XcodeはMac OS XのインストールDVDに付属している他、最新版はApple Computer社の開発者用サイトからダウンロードできる。

Step 2: SDKをコピーする

・ Cycling ’74社のWebサイトからMaxMSP UB SDKをダウンロードする。
・MaxMSP UB SDKフォルダをハードディスクの任意の場所にコピーする。

Step 3: フレームワークをコピーする

・MaxMSP UB SDKフォルダのCopyContentsToLibraryFrameworksフォルダの中身をLibrary/Frameworks/フォルダにコピーする。
(Libraryフォルダは日本語環境では起動ディスクの「ライブラリ」フォルダのこと。)

Step 4: サンプルをビルドする

・サンプルのプロジェクト・ファイルをダブル・クリックする。例えば、MaxMSP UB SDKフォルダのexample-externsフォルダにあるmaximumフォルダのmaximum.xcodeprojファイルをダブル・クリックする。
・Xcodeが起動し、プロジェクト・ウィンドウが開く。
・Xcodeのプロジェクト・ウィンドウのビルド・アイコンをクリックして、プロジェクトをビルドする。
・ビルドが成功すれば、maximumフォルダにbuildフォルダが作られ、その中のDefaultフォルダにmaximum.mxoというオブジェクト・ファイルが作られる。
・何らかのエラーが発生する場合は、MaxMSP UB SDKの構成やフレームワークのコピーが間違っていることが考えられるので、再確認する。
・オブジェクト・ファイルが作成できれば、Maxを起動してオブジェクトの動作を確認する。Defaultフォルダにmaximum.help(あるいはmaximum-test.patなど)といったテスト用のパッチ・ファイルを作ると良い。

Step 5: 自分のプロジェクを変換する

・サンプルのプロジェクトを複製し、それを元にユニバーサル・バイナリ化したい自分のプロジェクト、あるいは新しく制作するプロジェクトを作ると良い。詳しくは、UBオブジェクト開発講座(2)にて説明。

scaleとzmapの違い

scaleもzmapも、入力範囲と出力範囲を指定し、その範囲に従って数値変換してくれるオブジェクトですね。zmapは直線変換のみで、scaleは指数変換が可能です。もっとも、scaleのデフォルトの指数係数は1.0で直線変換なので、zmapは要らないじゃん、って気もするのですが、でもscaleはスケーリングで、zmapはマッピングなのです。文字通りですが、この違いが何かと言うと…

scaleはスケーリング(比率計算)なので、入力範囲を超える数値が入力された場合は、出力範囲を超える数値が出力されます。一方、zmapでは、入力範囲外の数値が入力された場合には、出力範囲内に収まるようにクリッピングされます。つまり、zmapでは出力範囲外の数値や出力されません。ということは、数値変換はしなくてもクリッピングのためにzmapを使っても良いわけですね。

scale-vs-zmap.jpg

それから、入力範囲または出力範囲の指定で大小関係が逆である(第1アーギュメントが第2アーギュメントよりも大きな値である、または、第3アーギュメントが第4アーギュメントよりも大きな値である)場合に、scaleはそのままの比率に従って変換を行いますが、zmapは大小関係が正しくなるようにアーギュメントの値を読み替えて変換します。

当然のことながら、どちらのオブジェクトを使うかは適所適材ですから、それぞれの特徴をつかんでおくことが大切ね、っとこれまた学内ネタでしたが、こーゆー小ネタをブログに書くのはどうなんでしょうね?? もちろん、ワークショップ自体はもっと大きな枠でやっていて、そこから小ネタにしやすいことだけを書いているわけなのですが….

sfplay~のプリロード完了取得

今月は学内ワークショップを担当していたり、知人がMaxで仕事をしていたりで、何かとMax絡みの小ネタが多いのですが、その中から今日の課題は、sfplay~でプリロードが完了したことを知るにはどうするか?です。

sfplay~は、ディスクからオーディオ・ファイルを再生するオブジェクトですが、実際にはバッファリングのためにオーディオ・ファイルの一部をメモリに読み込みます。この読み込みが完了した時点を知りたいわけです。なぜ知りたいかと言えば、例えばプリロードが完了するまでに別の要求が発生する場合があるとか、数千回のプリロードの進行状態を知りたいとか、ですね。通常は次々とメッセージを投げておけば順次実行されますが、それでは困る場合に必要になります。

さて、sfplay~のヘルプを見ると、右アウトレットの役目として「bang when cue, file, seek, or list of cues is finished.」と書かれていますが、プリロードが終わった時点でbangが出力されるわけではありません。MSPのリファレンス・マニュアルでも「When the file is done playing, or when playback is stopped with a 0 message, a bang is sent out. 」となっていて、ダメっぽいです。

で、解決はsfplay~だけでは無理で、
解決策:sflist~にpreloadメッセージを送る。
でした。

sflist~はキュー・リスト管理専用のオブジェクトですね。sflist~がpreloadメッセージを受け取り、プリロードが完了すると、sflist~はアウトレットから、preload < キュー番号> < ファイル名>….といったメッセージを出力します。従って、このメッセージを捉えれば良いことになります。

次のパッチでは、オーディオ・ファイルのプリロードが終わり次第すぐに、そのオーディオ・ファイルを再生します。実際の処理は、sflist~の出力からrouteオブジェクトでpreloadメッセージのアーギュメントを取り出し、zl sliceオブジェクトでプリロードされたキュー番号を取り出し、sfplay~への再生開始メッセージとして送る、って流れ。この時、sflist~もsfplay~もアーギュメントに同じ名前を与え、キューを共有するように指定することが必須ね。

preloadplay.gif

ダウンロードはこちらから。preloadplaypat.zip

ちなみに、sflist~が出力するpreloadメッセージのアーギュメントには、キュー番号とファイル名に続いて実数、実数、整数、実数の4つの数値があります。これらは再生開始位置、再生終了位置、再生方向、再生速度のハズです。「ハズ」と書かざるを得ないのは、sflist~の出力はヘルプにもリファレンスにも記載されていないからです(苦笑)。