Chapter 9:
高度な機能

このセクションでは、大部分のオブジェクトでは使う必要はありませんが、先進的なプログラマにとっては興味深いと思われる機能について説明します。 。

オブジェクト生成とメッセージに関する高度なルーチン

これらのルーチンは、クラスのインスタンスを生成し、これらに「型指定のない-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_mebang メッセージを送る場合

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 で定義されているマクロ、mess0mess1mess2、などは、型チェックなしのメッセージを送信する場合に役立ちます。ここでは、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つのケースで、連携するオブジェクトに送られます。

  • ウィンドウの w_scratch ビットがセットされている場合
  • ウィンドウが閉じられようとする際、スクリーンに表示される“Save Changes?”アラートで、ユーザが Save をクリックした場合。このケースは、ウィンドウのw_scratch ビットがセットされていない場合です。
     
バインディング
     
  addmess (myObject_edclose, "edclose", A_CANT, 0);
   
宣言
   
  void myobject_edclose (Myobject *obj, char **text, long size);
     
  text 編集されたテキストへのハンドル
  size ハンドルのサイズのバイト数.
     
 

このメソッドでは、エディタは編集ウィンドウのテキストをあなたに渡します。ウィンドウのw_scratch ビットがセットされている場合、ウィンドウのテキストがユーザに変更されたかどうかを知りたいと思うかもしれません。テキストエディットオブジェクト t_edext_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 によって、ここでエディタのテキストをセットします */ } }


expr オブジェクトへのアクセス

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_newargv の中のアーギュメントから 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 を入れておかなければなりません。


Presets

Max には、 preset というオブジェクトがあり、パッチャーウィンドウ内のいくつか、あるいは全てのオブジェクト(クライアント)に preset メッセージを送る機能を持っています。preset メッセージは、ユーザがプリセットを保存しているときに送られますが、これは、あなたのオブジェクトに対して、現在の内部状態をリストア(復元)する方法を preset オブジェクトに報告するよう要請するものです。その後、ユーザがプリセットを実行すると、preset オブジェクトは以前にオブジェクトから伝えられたメッセージを送り返します。

オブジェクト間の対話は次のように進みます:

  • 保存を行っている間:
    • preset オブジェクトからクライアントオブジェクトへ:「ハロー!、これはpresetメッセージです。君の状態をリストア(復元)する方法を教えて下さい。」
    • クライアントオブジェクトからpresetオブジェクトへ:「int 34 メッセージを送って下さい」(一例)
  • 実行されている間:
    • preset オブジェクトからクライアントオブジェクトへ:「int 34」

クライアントオブジェクトは、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_intoutlet_floatoutlet_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);
     
 

この関数は、パッチャーファイルが保存される毎にインクリメントされるシリアルナンバを返します。このルーチンは、tablecoll のように、同じデータを参照する複数のオブジェクトを持ち、パッチャーファイル内にデータを「埋め込む」ことのできるオブジェクトにとって役に立ちます。オブジェクトを最後に保存したときからシリアルナンバが変わっていなければ、これを探し出してオブジェクトデータの多重コピーを避けることができます。


イベントシリアルナンバの利用

このMax パッチには simul というオブジェクトがあります。このオブジェクトは evnum_get によって返される情報を使って、左右のインレットで同時にメッセージを受け取った場合は1を、そうでない場合は0を出力しています。下のナンバーボックスには、button オブジェクトをクリックした場合や、キーをタイプした場合の結果が表示されています。

Max ファイルのロード

パッチャーをロードすることが可能な高レベル関数がいくつかあります。これらを利用して、特定のタスクを実行するためにパッチャーオブジェクトを使うような巧妙なオブジェクトを作成することができます。

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_dialoglocatefile_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 オブジェクトのスケジューリング

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 オブジェクトを参照していない場合には、内部のミリセカンド・スケジューラが使われます。そうでない場合、clksetclock オブジェクトの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_fdelaysetclock_delay の浮動小数点版です。


setclock_unset

     
  Clock をスケジューラから取り除く場合に、setclock_unset を使います。
   
  void setclock_unset (Setclock *scheduler, Clock *clk);
     
  scheduler このclock のスケジューリングに用いられていた setclock オブジェクト。0ならば、clock は内部のミリセカンド・スケジューラから取り除かれます。
  clk スケジューラから取り除かれるClock オブジェクト
     
 

この関数は、Clockオブジェクト clksetclock オブジェクトの 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_getftimesetclock_gettime の浮動小数点版です。


setclockオブジェクトルーチンの使用

これは、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);

Quittask (終了処理)

時として、プログラムがの終了をを通知してもらう必要がある場合があります。これによって、コードはグローバルリソースのクリーンアップを実行したり、他のタスクを行ったりすることができます。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 を取り除きます。