このセクションでは、大部分のオブジェクトでは使う必要はありませんが、先進的なプログラマにとっては興味深いと思われる機能について説明します。 。
これらのルーチンは、クラスのインスタンスを生成し、これらに「型指定のない-untyped-」メッセージを送ることを可能にします。これは、既存のオブジェクトでも、新しく定義されたオブジェクトでも可能です。「型指定のない」メッセージとは、タイプリストに定数 A_CANT を持つものです。これは、オブジェクトのインレットに接続されたメッセージボックスによってユーザが直接送ることはできません。
newinstance |
||
既存のMax クラスの新しいインスタンスを生成する場合に、newinstance を使います。 | ||
t_object *newinstance (t_symbol *className, short argc, t_atom *argv); | ||
className | 生成されるインスタンスのクラス名を指定するシンボル. | |
argc | argvのアーギュメントの数 | |
argv | t_atoms の配列; クラスのインスタンス生成関数へのアーギュメント. | |
この関数は、指定されたクラスの新しいインスタンスを生成します。newinstace を使うことは、Max で新しいオブジェクトボックスにオブジェクト名をタイプすることと同じです。違いは、どのパッチャーウィンドウにもオブジェクトボックスは表示されず、パッチコードの接続なしに直接オブジェクトに対してメッセージを送ることができるという点です。メッセージは、型チェックを行ったもの(typedmess を使います)でも、型チェックを行わないもの(getfnファミリのメンバを使います)でも可能です。 newinstance は生成されたオブジェクトへのポインタを返しますが、クラスが存在しない場合やインスタンス生成時に他の種類のエラーが生じた場合には0を返します。この関数は、tables のような既存のオブジェクトを、新しいオブジェクトの中で「プライベート」に利用したい場合に役立ちます。プライベートに定義されたクラスを使っている例として、coll オブジェクトのソースコードを参照して下さい。 |
typedmess |
||
型指定を行ったメッセージを、Max オブジェクトに直接送信する場合に、typedmess を使います。 | ||
void *typedmess (void *receiver, t_symbol *message, short argc, t_atom *argv); | ||
receiver | メッセージを受け取るMax オブジェクト. | |
message | メッセージセレクタ |
|
argc | argvが持つメッセージのアーギュメントの数. | |
argv | t_atoms の配列; メッセージのアーギュメント. | |
typedmess はMax オブジェクト(receiver)にメッセージとアーギュメントを送信します。receiver で指定したオブジェクトがメッセージに応答できない場合、typedmess はその結果を返します。あるいは、Max ウィンドウにエラーメッセージが表示され、0が返されます。メッセージは文字列ではなく、t_symbol でなければならない点に注意して下さい。このため、typedmess に渡す前に、文字列に対して gensym を呼び出さなければなりません。また、typedmess が、クラスのアーギュメントリストで A_CANT と定義される「型指定なしの」メッセージを送信することができない点も覚えておいて下さい。この場合には、代わりに下記の getfnなどを使う必要があります。 例:オブジェクトbang_me に bang メッセージを送る場合 void *bangResult; bangResult = typemess(bang_me,gensym(“bang”),0,0L); |
下記の3つのルーチンは、オブジェクトに対して、型チェックを行わないメッセージを送信します。この場合、あなた自身がメッセージ、アーギュメントを正しく送信する役割を担います。これが正しく行われないと、Max ウィンドウのエラーメッセージどころか、システムエラーが生じてしまいます。これらの関数はnewinstance によって作られたオブジェクトと併用するために役立ちます。
getfn |
||
Max オブジェクトに対して、型チェックを行わないメッセージを、エラーチェックを行なって送信する場合に、 getfn を使います。 | ||
method getfn (t_object *obj, t_symbol *msg); | ||
obj | メッセージのレシーバ | |
msg | メッセージセレクタ | |
getfn は、レシーバのメッセージリストによってメッセージセレクタ msg にバインドされたメソッドへのポインタを返します。メソッドが見つからない場合は、Max ウィンドウにエラーメッセージが表示され、0が返されます。 |
egetfn |
||
常に動作しているMax オブジェクトに対して、型チェックを行わないメッセージを送信する場合に、egetfn を使います。 | ||
f method egetfn (t_object *obj, t_symbol *msg); | ||
obj | メッセージのレシーバ | |
msg | メッセージセレクタ | |
egetfn は、レシーバのメッセージリストによってメッセージセレクタ msg にバインドされたメソッドへのポインタを返します。メソッドが見つからない場合は、何も行なわない(do_nothing) 関数へのポインタが返されます。 |
zgetfn |
||
Max オブジェクトに対して、型チェックを行わないメッセージを、エラーチェックを行なわずに送信する場合に、 zgetfn を使います | ||
method zgetfn (t_object *obj, t_symbol *msg); | ||
obj | メッセージのレシーバ | |
msg | メッセージセレクタ | |
zgetfn は、レシーバのメッセージリストによってメッセージセレクタ msg にバインドされたメソッドへのポインタを返します。メソッドが見つからない場合は、0を返しますが、Max ウィンドウへのエラーメッセージの表示は行いません。 |
ext_mess.h で定義されているマクロ、mess0、mess1、mess2、などは、型チェックなしのメッセージを送信する場合に役立ちます。ここでは、newinstance と 型チェックなしのメッセージを使う例を示します。
この例では、bob オブジェクトの info メソッドが joe クラスのインスタンスを生成し、それに対して (おそらく何かを行うであろう)info メッセージを送り、joe のインスタンスを消滅させます。
void bob_info(Bob *x, void *p, void *b) { void *joe; joe = newinstance(gensym("joe"),0,0L); /* joe を生成します */ mess2(joe,gensym("info"),p,b); /* 型チェックなしのメッセージを送信します */ freeobject(joe); /* joe にサヨナラのキスを送ります */ }
これらの関数を使って、名前を持った table オブジェクトにアクセスすることができます。Table は、下図のようにユーザがアーギュメント付きで生成すると、名前を持つようになります。
Table オブジェクト自体でなくその名前を知るための筋書きはこうです。シンボルを渡すと、それが生成関数へのアーギュメントであっても、他のメッセージであっても、結果は「norris という名前のtableのデータを使って何かを行う」というものになります。
table_get |
||
名前を持った table オブジェクトの中のデータへのハンドルを取得する場合に、table_get を使用します。 | ||
short table_get (t_symbol *tableName, long ***dstHandle, long *dstSize); | ||
tableName | 探索するTable オブジェクトの名前を持ったシンボル | |
dstHandle | ハンドルへのアドレス:該当の名前のテーブルオブジェクトが見つかると、ハンドルにそのテーブルのデータが返されます | |
dstSize | テーブルの要素の数 (long で表されるサイズ) | |
これは、table から40番目の要素を取り出す例です。 long **storage,size,value; if (!table_get(gensym("somename"),&storage,&size)) { if (size > 40) value = *((*storage)+40); } |
table_dirty |
||
table オブジェクトのデータが変更されたかどうかをマークする場合に、table_dirty を使います。 | ||
short table_dirty (t_symbol *tableName); | ||
tableName | Table オブジェクトの名前を持ったシンボル | |
tableName で与えられた名前をもつtable オブジェクトに対し、table_dirty はそのdirty ビットをセットします。そのため、ユーザは table を閉じようとするとき、それを保存するかどうかを尋ねられます。 tableNameに関連づけられる table がない場合、table_dirty は0以外の値を返します。 |
Maxはシンプルな組み込みテキストエディタオブジェクト Ed を持っています。これは、他のオブジェクトと連携してテキストの表示や編集を行うことができます。下記のルーチンによってテキストエディタを作ることができます。
テキストウィンドウが閉じられようとする場合に、連携するオブジェクトは最大3つのメッセージを受け取ることができます。第1のメッセージは okclose で、これはユーザがウィンドウ内でテキストを変更した場合に送られます。これは、すべての “dirty” ウィンドウが閉じられようとするときに送信される標準のokclose メッセージです。しかし、テキストエディタウィンドウ・オブジェクトは自分自身で何かをする代わりに、あなたにそのメッセージを送ります。この okclose メッセージに対応するメソッドを書く方法については、ウィンドウメッセージに関するセクションを参照して下さい。必ずしもこのメソッドを書かなければならないわけではありません。書かれていない場合は、ウィンドウの動作はウィンドウの w_scratch ビット(Chapter 10 で述べています)の設定によって決められます。これがセットされている場合、dirty ウィンドウが閉じられる場合の確認を行いません(そして、テキストエディタにokclose メッセージが送られることもありません)。第2のメッセージは、edcloseです。これは、連携するオブジェクトの初期化の際に追加されるメソッドを必要とします。第3のメッセージは、edSave です。これによって、保存される前にテキストにアクセスしたり、あなた自身が保存を行うことができます。
edclose |
||
edclose は次の2つのケースで、連携するオブジェクトに送られます。
|
||
バインディング |
||
addmess (myObject_edclose, "edclose", A_CANT, 0); | ||
宣言 |
||
void myobject_edclose (Myobject *obj, char **text, long size); | ||
text | 編集されたテキストへのハンドル | |
size | ハンドルのサイズのバイト数. | |
このメソッドでは、エディタは編集ウィンドウのテキストをあなたに渡します。ウィンドウのw_scratch ビットがセットされている場合、ウィンドウのテキストがユーザに変更されたかどうかを知りたいと思うかもしれません。テキストエディットオブジェクト t_ed は ext_edit.h で定義されています。次のようなコードを使うと、エディタのウィンドウが持つ dirty ビットをチェックすることができます。(x->m_edit があなたのテキストエディタオブジェクトへのポインタであると仮定します) if (x->m_edit->e_wind->w_dirty) /* すでに変更されている */ テキストが変更された場合には、edclose メッセージのtext アーギュメントを使って、あなたのオブジェクトの状態を更新することができます。 edclose メッセージを受け取ると、テキストエディタウィンドウは消滅するため、これをあなたのオブジェクトの内部状態に記録しておくことは重要です。テキストエディタを指すオブジェクトのフィールドに、この時点で0をセットするというのは、良いアイディアです。 |
edsave |
||
edsave メッセージは、オブジェクトがテキスト編集ウィンドウのファイルへの保存をカスタマイズすることを可能にします。 | ||
バインディング |
||
addmess (myObject_edsave, "edsave", A_CANT, 0); | ||
宣言 |
||
void *myobject_edsave (myObject *x, char **text, long size, char *filename, short vol); | ||
text | テキストバッファへのハンドル. | |
size | テキストバッファの長さ. | |
filename | ファイル名のC文字列。 ファイルは先に作成されている必要があります。 | |
vol | ファイルの場所を指定するボリューム参照ナンバ. | |
テキストエディタウィンドウが保存されようとするとき、オブジェクトはこのメッセージを受け取ります。メソッドは、指定したファイルに、希望するフォーマットで保存することができます。保存せずに、単にテキストにアクセスしたい場合には、この関数から0を返すと、通常のファイル保存手続きが使われます。そうでない場合は0以外の値を返します。 |
ed_new |
||
新しいテキスト編集ウィンドウを作る場合には、ed_new を使います。 | ||
t_ed *ed_new (t_object *assoc); | ||
assoc | テキスト編集ウィンドウと連携するオブジェクト。通常は、あなたのオブジェクトへのポインタです。 | |
この関数は新しいテキスト編集ウィンドウを生成します。テキストエディタが即座に表示されます。assoc はあなたのオブジェクトへのポインタでなければなりません。これによって、非常に重要な edclose メッセージを受け取ることが可能になります。ed_new の結果は、オブジェクト内に保存しておかなければなりません。これには2つの理由があります。第1は、ウィンドウにテキストをセットする場合に ed_settext を呼び出せるようにするため、第2は、あなたのオブジェクトがdblclick メッセージを受信したときにウィンドウを前面に表示するed_vis を呼び出せるようにするためです。 |
ed_settext |
||
テキスト編集ウィンドウの内容をセットする場合に、ed_settext を使います。 | ||
void ed_settext (t_ed *ew, Handle textHandle, long textSize); | ||
ew | テキスト編集ウィンドウオブジェクト | |
textHandle | ウィンドウに置くテキストへのハンドル | |
textSize | textHandle の持つ文字数 | |
ed_settext はテキスト編集ウィンドウに、textHandle が持つ文字列をセットします。ウィンドウは新しい文テキストを表示するために更新されます。 |
ed_vis |
||
テキスト編集ウィンドウを前面に表示させる場合に、ed_vis を使います。 | ||
void ed_vis (t_ed *ew); | ||
ew | テキスト編集ウィンドウオブジェクト | |
テキスト編集ウィンドウに標準の動作を実装したい場合には、dblclick メッセージを受け取った後にのみウィンドウが表示されるようにしておきます。テキスト編集ウィンドウは、ed_new によって作られた時に即座に表示されるもので、あなたのオブジェクト生成関数で作られるものではありません。正確には、オブジェクトが生成される際に、エディタを保存するスロットを0で初期化します。そして、オブジェクトのdblclick メソッドで新しいエディタの作成や既存のエディタを前面に表示する必要があるかどうかを判断することができます。 これは、dblclick メソッドの例です。ここでは、があなたのオブジェクトがテキストエディタを保持しておくフィールドが x->m_edit であると仮定しています。 void myobject_dblclick(Myobject *x) { if (x->m_edit) ed_vis(x->m_edit); else { x->m_edit = ed_new(x); /* ed_settext によって、ここでエディタのテキストをセットします */ } } |
C言語のような形で書かれたの様々な式を使い、それに対してオブジェクトのユーザが入力をできるようにしたい場合、オブジェクトの中でMax のexpr オブジェクトの「心臓部」を利用する事ができます。例えば、if オブジェクトはexpr ルーチンを用いて条件式を評価し、その後、メッセージを送信するかどうかを決定します。下記の関数はexpr へのインターフェイスを提供します。Binbuf、Clock、Qelem などと同様に、Expr の型もvoid型へのポインタになる点に注意して下さい。Expr を使用する上で必要となる定数や、他の宣言は、ext_expr.h で見ることができます。。
expr_new |
||
新しい expr オブジェクトを作る場合に、exrp_new を使います。 | ||
Expr *expr_new (short argc, t_atom *argv, t_atom *types); | ||
argc | argv のアーギュメントの数 | |
argv | exprの生成のために用いられるアーギュメント。詳細は下記の例を参照。 | |
types | 既存の9個のt_atom からなる配列。expr で作られる変数アーギュメントの全ての型が収められています。型はそれぞれのt_atom の a_type フィールドに返されます。アーギュメントが存在しない場合には、A_NOTHING が返されます。 | |
expr_new は argv の中のアーギュメントから expr オブジェクトを生成し、argv に含まれる全てのexprスタイルのアーギュメントの型(例えば、 $i1など)を、typesが参照する配列の個々のatomの中に返します。 types には、前もって9個のAtom からなる配列が存在している必要があります。expr_new は、このすべてに値を書き込みます。アーギュメントが存在しない場合には、タイプ A_NOTHING がセットされます。例として、argv が次のようなものを参照していると仮定してください。 |
atoms: | ||||
$i1 | (A_SYM) | |||
+ | (A_SYM) | |||
$f3 | (A_SYM) | |||
+ | (A_SYM) | |||
3 | (A_LONG) | |||
expr を呼び出すと, typesの内容は次のようなものになるでしょう。 | ||||
Index | Argument | Type | Value | |
0 | 1 ($i1) | A_LONG | 0 | |
1 | 2 | A_NOTHING | 0 | |
2 | 3 ($f3) | A_FLOAT | 0.0 | |
3 | 4 | A_NOTHING | 0 | |
4 | 5 | A_NOTHING | 0 | |
5 | 6 | A_NOTHING | 0 | |
6 | 7 | A_NOTHING | 0 | |
7 | 8 | A_NOTHING | 0 | |
8 | 9 | A_NOTHING | 0 |
expr_eval |
||
expr オブジェクト内の式を評価するために、expr_eval を使います。 | ||
void expr_eval (Expr *ex, short argc, t_atom *argv, t_atom *result); | ||
ex | 評価されるexpr オブジェクト | |
argc | argv のアーギュメントの数 | |
argv | 式の中で、変数アーギュメントの代わりとなる($i1のような)9個のAtom の配列。使用しないアーギュメントの型は A_NOTHING になります。 | |
result | 式を評価した結果の値とその型を保存するために用意されたAtom | |
expr オブジェクト内の式をargv 内のアーギュメントで評価し、式を評価して得られた値とその型を result にt_atom として返します。result は1つのt_atom へのポインタである必要がありますが、argv は少なくと argc で示された数の Atom を持っていなくてはなりません。上記の expr_new の例のようにアーギュメントの間に「ギャップ(間)」がある場合は、t_atom の型にA_NOTHING を入れておかなければなりません。 |
Max には、 preset というオブジェクトがあり、パッチャーウィンドウ内のいくつか、あるいは全てのオブジェクト(クライアント)に preset メッセージを送る機能を持っています。preset メッセージは、ユーザがプリセットを保存しているときに送られますが、これは、あなたのオブジェクトに対して、現在の内部状態をリストア(復元)する方法を preset オブジェクトに報告するよう要請するものです。その後、ユーザがプリセットを実行すると、preset オブジェクトは以前にオブジェクトから伝えられたメッセージを送り返します。
オブジェクト間の対話は次のように進みます:
クライアントオブジェクトは、preset オブジェクトから受け取る int 34 と 左端のインレットから受け取る 34の違いを認識することはできません。。
preset メッセージに体する応答はオブジェクトに義務づけられているわけではありません。しかし、これはユーザにとって便利なものです。現在、Max の全てのユーザインターフェイスオブジェクトは、preset メッセージに対して応答します。あなたのオブジェクトがユーザインターフェイスオブジェクトではなく、preset メソッドを実装している場合には、ユーザはpreset オブジェクトのアウトレットを、あなたのオブジェクトの左端のインレットと連結しておく必要があります。これによって、ユーザがプリセットを保存する場合に、preset メッセージが送られます。
preset メッセージに対して応答する際に使うことができるルーチンには、次のようなものがあります。
preset_int |
||
オブジェクトの状態をint メッセージによってリストア(復元)する場合に、preset_int を使います | ||
void preset_int (t_object *obj, long value); | ||
obj | オブジェクト自身 | |
value | オブジェクトの持つ現在の値 | |
ユーザが preset を実行した場合、この関数の引数 value の int メッセージが preset オブジェクトからあなたのオブジェクトへ送られます。既存の全てのユーザインターフェイスオブジェクトは、preset が実行された場合、int メッセージを使って内部の状態をリストアします。 |
preset_set |
||
オブジェクトの状態を set メッセージによってリストアする場合に、preset_set を使います。 | ||
void preset_set (t_object *obj, long value); | ||
obj | オブジェクト自身 | |
value | オブジェクトの持つ現在の値 | |
ユーザが preset を実行した場合、この関数の引数 valueのset メッセージが、preset オブジェクトからあなたのオブジェクトへ送られます。 |
preset_store |
||
preset オブジェクトに対して、あなたのオブジェクトの現在の状態をリストアするための様々なメッセージを送る場合に、preset_store を使います。 | ||
void preset_store (char *format, void *items, ...); | ||
format | メッセージの各要素の型に対応した1文字以上のC文字列。 s はシンボル、 l はlong、 f はfloat。 | |
items | オブジェクトの状態をリストアするために使用されるメッセージの要素。これは関数に直接、シンボル、long、あるいは float として渡されます。下記の、preset オブジェクトの要求に適合させている例を参照して下さい。 | |
これは、オブジェクトの状態がシンプルなint や set メッセージではリストアできない場合に使われる、一般的な preset 関数です。下記の例では、現在の状態を preset オブジェクトに対して指定する際に求められるフォーマットを示しています。最初に与えるのは、オブジェクト自身です。その次のシンボルはオブジェクトのクラス名です(これは、マクロ ob_sym を使ってオブジェクトから取得することができます。この宣言はext_mess.h にあります)。次に受け取りたいメッセージを指定するシンボルを与えます。(このためのメソッドがクラスで定義されているほうが良いでしょう)、続いてこのメッセージへのアーギュメント(オブジェクトのフィールドの現在の値)を与えます。 この例では、オブジェクトが set メッセージを受け取るよう指定して、preset_store を使っています。ここでは、myvalue という1つのフィールドがあり、これが保存、リストアされるものと仮定しています。 void myobject_preset(myobject *x) { preset_store("ossl",x,ob_sym(x),gensym("set"),x->myvalue); } この preset が実行されると、オブジェクトは set メッセージを受け取り、そのアーギュメントが myvalue の値になっています。下で述べるように、同じことを preset_int や preset_set を使うことによって、より簡単に行なうことが可能であるという点に注意して下さい。 preset_store に12以上のアイテムを渡さないで下さい。それ以上に大量のデータを preset に保存したい場合は、binbuf_insert を使用して下さい。 次の例では、内部にプリセットデータを集めたbinbuf を設定し、用意しておいたAtomの配列で binbuf_insert を呼び出しています。この例では、オブジェクトの状態は set メッセージによってリストアされるものと仮定しています。 void myobject_preset(myObject *x) { void *preset_buf; /* プリセットを保存するbinbuf */ short atomCount; /* 保存を行なう Atom の数 */ t_atom atomArray[SOMESIZE];/* 保存が行なわれるAtom の配列 */ /* 1.presetの "ヘッダ" 情報の準備 */ SETOBJ(atomArray,x); SETSYM(atomArray+1,ob_sym(x)); SETSYM(atomArray+2,gensym("set")); /** atomArray+3 にオブジェクトの状態を入れ atomCountを設定する*/ /* 2. Binbufを見つける */ preset_buf = gensym("_preset")->s_thing; /* 3. データを保存する */ if (preset_buf) { binbuf_insert(preset_buf,NIL,atomCount,atomArray); } } |
Qelem の中、あるいは何らかのアイドル状態や割り込みの中でoutlet_int、outlet_float、outlet_list、または outlet_anything を呼び出す場合、Max のイベントシリアルナンバを前もってインクリメントさせておかなければなりません。このナンバは受け取った2つのメッセージが同じ論理的「時刻」に(同じイベントに応答して)起きたかどうかを知る必要があるオブジェクトによって読み込まれます。Max はclockの個々のtick 、キーの押し下げ、マウスクリック、MIDIイベントのシリアルナンバをインクリメントさせます。これは、serialno 関数によって返されるファイルシリアルナンバとは異なるものである点に注意して下さい。ファイルシリアルナンバはパッチャーがファイルに保存された時にインクリメントされます。複数のパッチャーがファイルに保存されると、ファイルシリアルナンバは変更されますが、イベントシリアルナンバは変更されません。
evnum_incr |
||
イベントシリアルナンバをインクリメントさせる場合に、evnum_incr を使います。 | ||
void evnum_incr (void); |
evnum_get |
||
イベントシリアルナンバの現在の値を得る場合に、evnum_get を使います。 | ||
long evnum_get (void); |
serialno |
||
個々のパッチャーファイルが保存される時のユニークなナンバを得る場合に、serialno を使います。 | ||
short serialno (void); | ||
この関数は、パッチャーファイルが保存される毎にインクリメントされるシリアルナンバを返します。このルーチンは、table や coll のように、同じデータを参照する複数のオブジェクトを持ち、パッチャーファイル内にデータを「埋め込む」ことのできるオブジェクトにとって役に立ちます。オブジェクトを最後に保存したときからシリアルナンバが変わっていなければ、これを探し出してオブジェクトデータの多重コピーを避けることができます。 |
このMax パッチには simul というオブジェクトがあります。このオブジェクトは evnum_get によって返される情報を使って、左右のインレットで同時にメッセージを受け取った場合は1を、そうでない場合は0を出力しています。下のナンバーボックスには、button オブジェクトをクリックした場合や、キーをタイプした場合の結果が表示されています。
パッチャーをロードすることが可能な高レベル関数がいくつかあります。これらを利用して、特定のタスクを実行するためにパッチャーオブジェクトを使うような巧妙なオブジェクトを作成することができます。
stringload |
||
Max サーチパス内にあるパッチャーファイルを、そのファイル名を使ってロードする場合、stringload を使います。 | ||
void *stringload (char *name); | ||
name | ロードするパッチャーファイルのファイル名(C文字列). | |
この関数は、バイナリまたはテキスト形式のパッチャーファイルを検索し、それを開き、パッチャーファイルとして評価し、パッチャーのためにウィンドウを開いて前面に表示させます。ファイル名の指定を行なうだけで、Max がそのファイルを検索するためにサーチパス内を探します。サーチパスの検索は、現在の「デフォルトボリューム」から始められます。これは、多くの場合、最後にパッチャーファイルを開いたボリュームになります。さらに、File Preferences ダイアログで指定されたフォルダが深さ優先で検索され、最後にMax アプリケーションのあるフォルダが探されます。stringload が0以外の値を返した場合、後で freeobject を使ってパッチャーを閉じるか、または、ユーザ自身にそれを行なわせる必要があります。stringload が0を返した場合、指定された名前のファイルが見つからなかったか、それを開くためのメモリが不足していることを表します。 |
fileload |
||
ファイル名とボリュームリファレンスナンバによってパッチャーをロードする場合に、fileload を使います。 | ||
void *fileload (char *name, short path); | ||
name | ロードするパッチャーファイルのファイル名(C文字列). | |
path | ファイルの場所を指定するためのパスID | |
fileload は、引数 path にパスID の指定を必要とします。これは、openfile_dialog や locatefile_extended によって返されるものと同じです。ファイルが見つかると、fileload はファイルを開き、それを評価し、ウィンドウを開いて前面に表示させようとします。ロードが成功すると、新しく作られたパッチャーへのポインタを返します。また、ファイルが見つからない場合や、メモリが不足している場合には0を返します。 |
readtohandle |
||
データファイルをハンドルに読み込む場合に、readtohandle を使います。 | ||
short readtohandle (char *name, short path, char ***hp, long *size); | ||
name | ロードするパッチャーファイルの名前. | |
path | ファイルの場所を指定するためのパスID | |
hp | ファイルの中のデータへのハンドルを受け取るハンドル変数へのポインタ。 | |
size | hpへ返されるハンドルのサイズ | |
これは、テキストあるいはデータファイルを読み出すために用いられる低レベルルーチンです。ファイル名とパスID、およびハンドルへのポインタを指定します。ファイルが見つかると、readtohandle はハンドルを作り、ファイル中のすべてのデータをそこに読み込みます。そして、ハンドルを変数 hp に割り当て、データのサイズを size に返します。readtohandle はファイルのオープン、読み込みが成功すると0を返し、エラーが生じた場合は0以外を返します |
lowload |
||
Max ファイルにアーギュメントを渡して開く場合、lowload を使います。 | ||
void *lowload (char *filename, short path, short argc, t_atom *argv, short couldedit); | ||
filename | オープンするファイル名 | |
path | ファイルの場所を指定するためのパスID | |
argc | argv のt_atomの数。 正しくパッチャーファイルをオープンする場合には、argc は9になります。 | |
argv | 変更可能なアーギュメント #1-#9 を置き換えるt_atoms の配列。デフォルトでは、すべてのt_atom の型は A_LONG、値は0になります。 | |
couldedit | この値が0以外でファイルがパッチャーファイルではない場合、ファイルはテキストファイルとしてオープンされます。 | |
この関数は、指定されたファイルをロードし、生成されたオブジェクトへのポインタを返します。通常、lowload はパッチャーファイルを開くために使われ、それがテキストファイルであるかMax バイナリフォーマットであるかを問いません。また、内容が "table" という語で始まるテーブルファイルを開くこともできます。 couldedit が0以外でファイルがパッチャーファイルでない場合は、テキストエディタとなり、lowloadは0を返します。couldedit が0以外の場合、lowloadはユーザにエラーの警告を出し、0を返します。エラーがなければ、返される値はパッチャー、あるいはテーブルへのポインタになります。 |
Max の接続の機能を使って、2つまたはそれ以上のオブジェクトを標準のルーチンとメッセージのセットでリンクすることができます。これらのオブジェクトは生成、あるいは消滅が同時に行われなくてもかまいません。この機能は、名前を持ったデータ構造(coll あるいは table オブジェクトなど)のエディタを提供したい場合に役に立ちます。これによって、対応するオブジェクトがロードされると、自動的に名前を持ったデータ構造が表示され、そのデータが何らかの変更を加えられると、表示が更新されます。
接続には、データにアクセスしようとするオブジェクトである「クライアント」と、自分自身を特定のシンボルに関連付けた場合にその名前によって検索されるオブジェクト「サーバ」が必要になります。tableオブジェクトはサーバになることができます(そして、実際Connection ルーチンを使用して、これとコミュニケーションを取ることができます)。あなたのオブジェクトをクライアントとして使用するためには、connection_client を呼び出します。また、オブジェクトをサーバとして使用するするためには、connection_server を呼び出します。1つ以上のクライアントとサーバが同じ名前で存在する(または存在するようになった)場合には、クライアントオブジェクトは newserver メッセージを受け取ります。クライアントに接続されたサーバが解放されると、connection_delete が呼び出され、クライアントは freeserver メッセージを受け取ります。加えて、サーバはクライアントに送るメッセージを定義することもできます。例えば、table オブジェクトはデータが変更されると、クライアントに対してtabchanged メッセージを送ります。これは、関数 connection_send を通して行なわれるため、サーバがクライアントの消息を把握している必要はありません。
connection_client |
||
クライアントをシンボル名で登録する場合に、connection_client を使います。 | ||
void *connection_client (void *client, t_symbol *name, t_symbol *class, method traverse); | ||
client | 登録されるクライアントオブジェクト | |
name | クライアントが登録される名前 | |
class | サーバのクラス名. Max オブジェクト objならばob_sym(obj)になります。 | |
traverse | 接続機能によって同時に複数のクライアントにリンクすることを可能にする関数。接続はクライアントオブジェクトの中にある、リンクを目的としたフィールドにポインタを返す事によって行われます。このように、接続ルーチンを利用するためには、クライアントオブジェクトのデータ構造体は、この同じデータ構造体へのリンク用ポインタ変数を持っていなければなりません。下記のtraversal(走査)関数の実例を参照して下さい。 |
|
この関数はクライアントを名前で登録します。この名前を持ったサーバが既に存在し、connection_server の呼出しによって既に登録されている場合、connection_client によってクライアントオブジェクトはnewserver メッセージを受け取ります(下記を参照)。あるいは、指定された名前のサーバオブジェクトが connection_server を呼び出したときに、クライアントに newserver メッセージが送られます。 これは、引数 traverse として渡すtraversal(走査)関数の例です。最初にリンクポインタを持ったデータ構造体を示します。 typedef struct myclient { t_object c_ob; struct myclient *c_next; void *c_data; } t_myclient; traverse(走査)メソッドは次のように宣言されます。 void *myobject_traverse(t_myobject *x, t_myobject ***ptr); この関数は、ptr をデータ構造体の「次を指す(next to point)」フィールドのアドレスにセットします。そして、このフィールドの現在の内容を返します。上記のような Myclient データ構造体の場合、traverse(走査)メソッドは次のようになるでしょう。 void *myclient_traverse(t_myclient *x, t_myclient ***addr) { *addr = &x->c_next; return (x->c_next); } |
connection_server |
||
サーバをシンボル名で登録する場合に、connection_server を使います。 | ||
void connection_server (void *server, t_symbol *name); | ||
server | 登録されるサーバオブジェクト | |
name | サーバが登録される名前 | |
この関数は、オブジェクト server を名前name で登録します。この名前をつけられたクライアントオブジェクトが既に存在し、そのクラスがサーバオブジェクトと同じ場合、それらに対し、newserver メッセージによってサーバの存在が知らされます。このメソッドは次のように宣言されます。 void myobject_newserver (t_myobject *x, void *server); このメソッドを使うことによって、クライアントは、オブジェクトへの直接のアクセスが必要な場合、サーバへの参照を保存できます。 connection_server を呼出した後、サーバはすべてのクライアントに connection_send を使ってメッセージを送ることができます。 |
connection_send |
||
サーバからすべてのクライアントに対してメッセージを送る場合、connection_send を使います。 | ||
void connection_send (void *server, t_symbol *name, t_symbol *message, void *arg); | ||
server | 登録済みのサーバオブジェクト | |
name | サーバが登録された名前 | |
message | メッセージセレクタ | |
arg | メッセージアーギュメント | |
connection_send はシンボル name で関連付けられたオブジェクト server の接続状態を確認し、シンボル massage で指定された型指定なしのメッセージを(arg と共に)、その時点で接続されているクライアントすべてに送信します。サーバは実際にクライアントが存在するかどうかは全くわからないため、すべての場合において connection_send を呼び出さなければなりません。クライアントが存在しない場合、 connection_send は何も行いません(これは問題ありません)。 |
connection_delete |
||
接続から、クライアントまたはサーバを取り除く場合、connection_delete を使います。 | ||
void connection_delete (void *obj, t_symbol *name); | ||
obj | 登録済みのクライアントまたはサーバ | |
name | クライアントまたはサーバが登録されている名前. | |
クライアントやサーバが接続を解除したい場合(通常、オブジェクトのfree 関数の中で) connection_delete を使います(引数 obj として、自分自身を渡します)。接続に使われる名前を name に与えます。connection_delete がサーバから呼び出された場合、接続されているすべてのクライアントは freeserver メッセージを受け取ります。このメッセージは次のように実行されなければなりません。 void myobject_freeserver (t_myobject *x, void *server); このメッセージを受け取った後、クライアントはサーバオブジェクトを直接参照してはいけません。これは破棄されるだけです。 |
場合によっては、Max ウィンドウに送られるエラーメッセージを受け取ることが好都合なことがあります。
error_subscribe |
||
エラーハンドラからのメッセージを受信する場合に、error_subscribe を使います。 | ||
void error_subscribe(t_object *myobject); | ||
myobject | エラーハンドラに受け取り登録を行うオブジェクト | |
error_subscribe によって、オブジェクトはメッセージ (error)を受け取ることができるようになります。このメッセージの後には、Max ウィンドウに表示されるエラーメッセージの atom のリストが続きます。 error_subscribe を呼び出す前に、内部のエラー処理ルーチンに error メッセージをバインドしておかなければなりません。 addmess((method)myobject_error, "error", A_GIMME, 0); エラー処理ルーチンは次のように宣言されなければなりません。 void myobject_error(t_myobject *x, t_symbol *s, short argc, t_atom *argv); |
error_unsubscribe |
||
エラーメッセージの受け取り登録からオブジェクトを取り除く場合に、error_unsubscribe を使います。 | ||
void error_unsubscribe(t_object *myobject); | ||
myobject | 登録を取り除くオブジェクト | |
この呼出しの後、myobject はエラーメッセージを受け取らなくなります。 |
setclock オブジェクトは、スケジューラと関連する時間の流れを一般化することによって、Clock のスケジューリングをより一般的なものにします。個々の setclock オブジェクトの「時間」は、内部のミリセカンド・クロック以外の処理によって変更することが可能です。加えて、オブジェクトは内部のミリセカンド・クロックからオブジェクトの現在の時間の値へのマッピングを修正するルーチンを実装しています。あなたのオブジェクトはsetclockを使用することも、あるいは、通常のミリセカンド・クロックを透過的に(特に意識せずに)使うこともできる一連のルーチンを呼び出すことができます。多くのMax オブジェクトは、メッセージ clock とそれに続くオプションのシンボルを受け取ることができます。このシンボルは、オブジェクトの内部的なスケジューリングを名前を持った setclock オブジェクトにセットします。標準的な実装方法では、シンボルのバインディング(s_thing フィールド)をSetclock 関数に渡します。デフォルトでは、空のシンボルが渡されるようになっています。バインディングがsetclock オブジェクトにリンクされると、これがClock をスケジュールするために使われるようになります。そうでない場合、clock はメインの内部的なミリセカンド・スケジューラによってスケジュールされます。Setclock データ構造体は、エクスターナルオブジェクトから直接アクセスされることがないため、 void * が使用されます。
setclock_delay |
||
Clock をスケジューラ上でスケジュールする場合に、setclock_delay を使います。 | ||
void setclock_delay (Setclock *scheduler, Clock *clk, long time); | ||
scheduler | このclock のスケジューリングに用いられる setclock オブジェクト. | |
clk | 実行される関数を含んだ clock オブジェクト | |
time | カレントタイムから、Clockが実行される時点までの(Setclockのユニットでの)ディレイタイム | |
Clockオブジェクト clk をスケジュールし、カレントタイムより time ユニットだけ後に実行します。scheduler が0、または、setclock オブジェクトを参照していない場合には、内部のミリセカンド・スケジューラが使われます。そうでない場合、clk は setclock オブジェクトのClock のリスト上でスケジュールされます。Clock は clock_new によって作られなければならず、Clockへ渡したものと同じものが、clock_delay に渡されます。 |
setclock_fdelay |
||
浮動小数点数による時間のアーギュメントを使って、Clock をスケジューラ上でスケジュールする場合に、 setclock_fdelay を使います。 | ||
void setclock_fdelay(Setclock *scheduler, Clock *clk, double time); | ||
scheduler | このclock のスケジューリングに用いられる setclock オブジェクト | |
clk | 実行される関数を含んだ Clock オブジェクト | |
time | カレントタイムからClock が実行されるまでのディレイ時間 | |
setclock_fdelay は setclock_delay の浮動小数点版です。 |
setclock_unset |
||
Clock をスケジューラから取り除く場合に、setclock_unset を使います。 | ||
void setclock_unset (Setclock *scheduler, Clock *clk); | ||
scheduler | このclock のスケジューリングに用いられていた setclock オブジェクト。0ならば、clock は内部のミリセカンド・スケジューラから取り除かれます。 | |
clk | スケジューラから取り除かれるClock オブジェクト | |
この関数は、Clockオブジェクト clk を setclock オブジェクトの Clock のリストから取り除きます。schetuler が0の場合は内部のミリセカンド・スケジューラから取り除きます。 |
setclock_gettime |
||
setclock オブジェクトの現在時刻の値を得るために、setclock_gettime を使います。 | ||
long setclock_gettime (Setclock *scheduler); | ||
scheduler | setclock オブジェクト | |
setclockオブジェクトのスケジューラの現在時刻を返します。schedulerが0の場合、setclock_gettime は、内部のミリセカンド・クロックの現在時刻を返す関数gettimeと同じものになります。 |
setclock_getftime |
||
setclock オブジェクトの現在時刻の値を、浮動小数点数で表されるミリセカンド単位の値として得るために、setclock_getftime を使います。 | ||
void setclock_getftime(Setclock *scheduler, double *time); | ||
scheduler | setclock オブジェクト | |
time | ミリセカンド単位で表されるカレントタイム | |
setclock_getftime は setclock_gettime の浮動小数点版です。 |
これは、Setclockルーチンを使った、メトロノームオブジェクトの一連のメソッドの実装例です。
typedef struct metro { t_object m_ob; long m_interval; long m_running; void *m_clock; t_symbol *m_setclock; } t_metro;
これは、メトロノームのオン・オフを切り替えるためのルーチンの実装例です。インスタンス生成関数の中で、t_symbol m_setclock が空のシンボル(gensym("")にセットされ、m_clock が作られていると仮定しています。また、これより先でクロック 関数 metro_tick が定義されます。
void metro_bang(Metro *x) /* turn metronome on */ { x->m_running = 1; setclock_delay(x->m_setclock->s_thing,x->m_clock,0); } void metro_stop(Metro *x) { x->m_running = 0; setclock_unset(x->m_setclock->s_thing,x->m_clock); }
これは、周期的に動作するクロック関数 metro_tick の実装例です。
void metro_tick(Metro *x) { outlet_bang(x->m_ob.o_outlet); if (x->m_running) setclock_delay(x->m_setclock->s_thing,x->m_clock, x->m_interval); }
最後に、これは、clock メッセージに応答するメソッドの実装例です。関数が unsetメッセージに対して応答するかどうかをチェックすることによって、アーギュメントとして渡されるt_symbolに結び付けられている0以外の値が実際にsetclock のインスタンスであることを確認しようとしている点に注意して下さい。そうでない場合、メトロノームは t_symbol を内部の m_setclock フィールドに割り当てることを拒否します。
void metro_clock(Metro *x, t_symbol *s)
{
void *old = x->m_setclock->s_thing;
void *c = 0;
/* 以下の行は次のような場合に再スタートします
sが空のシンボルである場合
または、s->s_thing が 0 である場合
または、s->s_thing が 0 以外の値を持ち、かつsetclock オブジェクトである場合
*/
if ((s == gensym("")) || ((c = s->s_thing) && zgetfn(c,&s_unset)))
{
if (old)
setclock_unset(old,x->m_clock);
x->m_setclock = s;
if (x->m_running)
setclock_delay(c,x->m_clock,0L);
}
}
イベントを、グローバルな Max のスケジューラの時間から独立してスケジューリングしようとする場合、scheduler_new によって独自のスケジューラを作ることができます。新しく作られたスケジューラで scheduler_set を呼び出すことによって、clock_new の呼び出しがMax のグローバルスケジューラの代わりに、あなたのスケジューラに結びつけられたClockを作ります。これで、clock関数を(schetuser_runを使って)実行できるだけでなく、スケジューラの時間を(scheduler_settime を使って)コントロールできるようになります。これは、setclock オブジェクトルーチンより一般的な機能ですが、setclock オブジェクトからの時間を使ってClock 関数が実行される時点を決定するのではなく、一度 Clock がスケジューラと結び付けられるとこれが次々と作られていきます。(訳注:原文ではこの後に2番目の文と同じものがありますが、省略します)
scheduler_new |
||
新しいローカルなスケジューラを作る場合に、scheduler_new を使います。 | ||
Void *scheduler_new(void); | ||
この呼び出しは、新しく作られたスケジューラへのポインタを返します。 |
scheduler_set |
||
clock 関数が(scheduler_run を使って)いつ実行されるかを設定するために、scheduler_set を使います。 | ||
void *scheduler_set(t_scheduler *scheduler); | ||
scheduler | カレントにされるスケジューラ. | |
スケジューラをカレントにすることで、先の時点での関連した呼び出し(clock_delay のような)が適切なスケジューラに作用します。このルーチンは以前カレントであったスケジューラへのポインタを返します。これを保存しておき、ローカルなスケジューリングが完了したときに復元しなければなりません。 |
scheduler_run |
||
選択した時間にスケジューライベントを実行するために、scheduler_run を使います。 | ||
void scheduler_run(t_scheduler *scheduler, double until); | ||
scheduler | 進行するスケジューラ. | |
until | この実行処理の終了時間 (ミリセカンド単位で). |
scheduler_settime |
||
スケジューラのカレントタイムをセットするために、scheduler_settime を使います。 | ||
void scheduler_settime(t_scheduler *scheduler, double time); | ||
scheduler | セットするスケジューラ | |
time | 選択したスケジューラのカレントタイム(ミリセカンド). |
scheduler_gettime |
||
選択されたスケジューラのカレントタイムを取り出すために、scheduler_gettime を使います。 | ||
void scheduler_gettime(t_scheduler *scheduler, double *time); | ||
scheduler | 問い合わせを受けるスケジューラ | |
time | 選択されたスケジューラのカレントタイム |
エクスターナルオブジェクトを作る場合に、オペレーティングシステムの関数やデータ要素へのアクセスが必要な場合があります。オペレーティングシステム・アクセス・ルーチンは、Max環境で安心してこれらの情報にアクセスする手段を提供します。
event_process |
||
イベントを処理するためにオペレーティングシステムに送る場合に、event_process を使います。 | ||
void event_process(void *event, t_wind *win); | ||
event | 処理されるイベントの構造体 (Mac OS ではイベントレコード) | |
win | レコードの処理が行われるウィンドウの状況 | |
ダイアログボックスのフィルタ処理を実装する場合に、event_process を使う場合があるかもしれません。Max はイベントを処理し、ダイアログボックスを移動させた場合のウィンドウの再描画といった処理を扱うことができます。 |
event_run |
||
Max のグローバルイベントループを実行する場合に、event_run を使います。 | ||
void event_run(void); |
時として、プログラムがの終了をを通知してもらう必要がある場合があります。これによって、コードはグローバルリソースのクリーンアップを実行したり、他のタスクを行ったりすることができます。Max にはこれをサポートする“quittask” ( 終了処理) と呼ばれるメカニズムがあります。quittask は、Max の終了時にquicktask関数に渡される関数へのポインタ、および適切なポインタによる引数を伴ってインストールされます。
quittask_install |
||
オペレーティングシステムに処理のためのイベントを送る場合に、quicktask_install を使います。 |
||
void quittask_install(method *m, void *a); | ||
m | 関数へのポインタ. | |
a | オプションの引数 (何もなければ、0Lを渡します). | |
与えられた関数へのポインタと引数によって、quittask をインストールします。ポインタおよび引数はMax の終了時にこの関数に渡されます。 |
quittask_remove |
||
既存の quittask を取り除く場合に、quittask_remove を使います。 | ||
void quittask_remove(method *m); | ||
m | 関数へのポインタ | |
与えられた関数へのポインタに関連付けられている、インストール済みの quittask を取り除きます。 |