Max 5 API Reference

Jitter Max ラッパー

Max ラッパークラス

Jitter オブジェクトを Max パッチャーに対して公開するために、Max「ラッパー」クラスを定義する必要があります。これは、シンプルなクラスの場合、主として少数のユーティリティ関数を使って容易に行うことができます。この関数は、Jitter クラスを受け取り、デフォルトの機能によって適切なラッパークラスを作るものです。しかし、特別な動作を行わせる場合には、それ以上の関与が必要になることがあります。例えば、インレットやアウトレットの追加、MSP との一体化、マトリックス情報の Max のリストへの変換などを行なう場合がこれにあたります。ここで示す、最初の Max ラッパークラスは、シンプルで基本的な Jitter クラスを含んでいるだけで、それ以上の複雑な追加要素を持たないものです。
 
一般に、Jitter クラスはMax パッチャーについての考慮を行わずに設計し、パッチャーとの通信のために必要なあらゆるロジックは Max ラッパークラスでメンテナンスするほうが望ましいでしょう。これが難しいような状況では、通常、Jitter クラスに Max ラッパーによってのみ呼び出される特別なメソッドを作るか、先の章で説明するように Jitter のオブジェクト通知メカニズムを利用することによってこれに対処します。次のものは、前章で示した、最小限の Jitter クラスのための、最小限の Max ラッパークラスです。

typedef struct _max_jit_foo
{
   t_object       ob;
   void         *obex;
} t_max_jit_foo;

void *class_max_jit_foo;

void main()
{   
   void *p,*q;
   
   // Jitter クラスの初期化
   jit_foo_init(); 
   
   // Writing Max Externals で説明されている Max クラスの生成
   setup(&class_max_jit_foo, 
      (method) max_jit_foo_new, 
      (method) max_jit_foo_free, 
      (short)sizeof(t_max_jit_foo), 
      0L, A_GIMME, 0);

   // 追加情報を格納するためのバイトオフセットの指定
   p = max_jit_classex_setup(calcoffset(t_max_jit_foo, obex));
   
   // クラスレジストリからの Jitter クラスの探索
   q = jit_class_findbyname(gensym("jit_foo"));    
   
   // Jitter オブジェクト用の標準メソッドで、Jitter クラスをラップする
   max_jit_classex_standard_wrap(p, q, 0);    

   // インレット/アウトレット、アシスタンスメソッドの追加
   addmess((method)max_jit_foo_assist, "assist", A_CANT,0);
}

void max_jit_foo_assist(t_max_jit_foo *x, void *b, long m, long a, char *s)
{
   // インレット/アウトレット、アシスタンスを持たない場合
}

void max_jit_foo_free(t_max_jit_foo *x)
{
   // 内部の Jitter オブジェクトインスタンスを探索して、解放
   jit_object_free(max_jit_obex_jitob_get(x));
   
   // obex エントリによって結びつけられたリソースを解放
   max_jit_obex_free(x);
}

void *max_jit_foo_new(t_symbol *s, long argc, t_atom *argv)
{
   t_max_jit_foo *x;
   long attrstart;
   void *o;

   // max ラッパークラス、及び Jitter クラスに基づいて
   // ラッパーオブジェクトインスタンスを生成 
   if (x = (t_max_jit_foo *)max_jit_obex_new(class_max_jit_foo, 
         gensym("jit_foo"))) 
   {
      // 汎用アウトレットの追加 (右端)
      max_jit_obex_dumpout_set(x, outlet_new(x,0L));
      
      // 必要なら、ノーマルの arg をゲット
      attrstart = max_jit_attr_args_offset(argc,argv);
      
      // Jitter オブジェクトのインスタンス化
      if (o = jit_object_new(gensym("jit_foo"))) 
      {
         // 内部の Jitter オブジェクトインスタンスをセット
         max_jit_obex_jitob_set(x,o);
         
         // アトリビュートのアーギュメントを処理
         max_jit_attr_args(x,argc,argv);
      } 
      else 
      {   
         // インスタンス化失敗の場合, クリーンアップしてエラーを報告
         freeobject((void *)x);
         x = NULL;
         error("jit.foo: out of memory");
      }
   }

   return (x);
}

オブジェクト構造体

まず最初に行なわなければならないことは、あなたの Max クラスオブジェクト構造体の定義です。通常どおり、オブジェクト構造体の最初のエントリは、標準の Max オブジェクトでは t_object 型、UI オブジェクトでは t_jbox 型、MSP オブジェクトでは t_pxobject 型、MSP の UI オブジェクトでは t_pxjbox 型でなければなりません。Max/MSP のオブジェクト型の違いに関するより詳しい情報は、Max/MSP 開発者ドキュメントを参照して下さい。Jitter オブジェクトは、これらの内のどのオブジェクト型の中へでもラップすることができます。

さらに、効果的に Jitter クラスをラップするために必要な追加情報やリソースを指すポインタを定義する必要があります。これは、通常、”obex” データと呼ばれます。ここには、Jitter によって、アトリビュート情報、汎用の「ダンプアウト (dumpout)」、内部的な Jitter オブジェクトのインスタンス、インレット/アウトレットのためのマトリックス操作リソース( Matrix Operator resources)、そして、シンプルな Max オブジェクトでは必要とされませんが、その他の補助的なオブジェクト情報などが保存されます。

Max の バージョン 4.5 現在、このような普通の Max オブジェクトのための追加オブジェクト情報を利用する機能がまだ存在しています。これを書いている時点では、この情報は Pattr 開発者ドキュメントの中で、オブジェクトアトリビュートの定義に関連して示されています。これはオブジェクトのパッチャーアトリビュートセットによって保存、操作されます。

あなたの Max クラスの定義

あなたのエクスターナルの main 関数で行なわれるMax クラスの登録では、通常 your_object_name_init() というような名前をつけた Jitter クラスの登録関数を呼び出すことから始めなければなりません。その後、Max オブジェクトで setup 関数によって行う場合と同様に、Max クラスのコンストラクタ、デストラクタ、オブジェクト構造体のサイズ、型指定のあるアーギュメントの定義を始めます。あなたのラッパークラスが obex データを見つけられるようにするために、各々のインスタンス内で obex へのポインタが置かれる位置のバイトオフセットを指定し、あなたの Max クラスの中でこのポインタを保存するリソースを割当てる必要があります。この操作は、max_jit_classex_setup() 関数によって行うことができます。その後、 jit_class_findbyname() によってJitter クラスを探し出し、それを max_jit_classex_standard_wrap() 関数によってラップしなければなりません。 max_jit_classex_standard_wrap() 関数は、Jitter クラスで定義されている、型を指定されたメソッドをすべて追加し、同様に、透過的な(すなわち、プライベートな)アトリビュートのためのゲッター、セッターメソッドや、getattributes、getstate、summary、importattrs、exportattrs などのような Jitter オブジェクトに共通なメソッドすべてを追加します。

Jitter クラスをラップしてしまうと、Max オブジェクトに対して、インレット/アウトレットのアシスタンスメソッド、あるいは何か特定のメソッドなど、任意のメソッドを追加することができるようになります。Jitter オブジェクトのように、derer や usurp ラッパーを持つメソッドを追加することもできます。そして、これらは、単に従来の addmess() 関数を使うのではなく、 max_addmethod_defer_low() あるいは max_addmethod_usurp_low() 関数を使って追加しなければなりません。

コンストラクタ

Max オブジェクトのコンストラクタの内部には、普通の Max エクスターナルを作る場合とは多少の違いがあります。あなたのオブジェクトがアトリビュートアーギュメントに応答する場合、コンストラクタは、型を持つ atom アーギュメントの変数を取るように定義しなければなりません。これは A_GIMME という型記号で指定します。あなたの Max オブジェクトにメモリ割当てを行う場合、従来の newobject 関数の代わりに、 max_jit_obex_new() 関数を使います。あなたは、Jitter クラスの名前を、 max_jit_obex_new() 関数に渡す必要があり、これがあなたの obex データのメモリ割当てや初期化を行います。成功した場合、続いて汎用の「ダンプアウト」アウトレットの追加を行わなければなりません。このアウトレットは、アトリビュートの問い合わせや、情報を提供するためのメソッドに対する応答に使用されます。 max_jit_object_dumpout_set() 関数によって行われる *jit_qt_movie* の framedump メソッドによるフレームナンバや、read メソッドのサクセスコードのようなものがこれにあたります。オブジェクトが、 max_jit_mop_setup_simple() を呼び出すマトリックスオペレータであれば、 max_jit_mop_setup_simple() が内部的にmax_jit_object_dumpout_set() を呼び出すため、明示的に max_jit_object_dumpout_set を呼び出す必要はありません。

この後、 jit_object_new() によって Jitter オブジェクトのメモリ割当てを行い、これを max_jit_obex_jitob_set() によって obex データの中に保存します。この jitter オブジェクトのインスタンスは、いつでも max_jit_obex_jitob_get() 関数によって見つけることができる点に注意して下さい。必要であれば、あなたの Jitter オブジェクトのメモリ割当てを行う前に、非アトリビュートアーギュメントを見ることができ(これらのアーギュメントの場所までの位置は max_jit_attr_args_offset() によって返されます)、これをあなたの jitter オブジェクトのコンストラクタで利用することができます。アトリビュートアーギュメントの処理は、Max オブジェクトとJitter オブジェクト双方のインスタンスのメモリ割当ての後に、 max_jit_attr_args() によって行う方法が一般的です。 max_jit_attr_args() には、Max オブジェクトのインスタンスを渡します。アトリビュートアーギュメントを、何とかしてあなたの Jitter オブジェクトコンストラクタで使いたいという場合には、あなた自身でアトリビュートアーギュメントを解析する必要があります。Jitter オブジェクトに対するメモリ割当てができない場合(メモリ不足で実行した場合や、 Jitter は存在するがオーソライズされていない場合など)、Max ラッパーオブジェクトをクリーンアップし、NULL を返すことが重要です。

デストラクタ

あなたの Max オブジェクトのデストラクタの中では、、jit_object_free() による内部の Jitter オブジェクトの解放、およびmax_jit_obex_free()による追加のobex データの解放も行なわなければなりません。マトリックスオペレータは、通常、マトリックスの入力、および出力に割り当てられたリソースを解放するために、max_jit_mop_free() の呼び出しを必要とします。

オブジェクトが jit_object_attach() によって登録済みオブジェクトに接続され、通知を受けるようになっている場合、デストラクタの中で jit_object_detach() を使って登録済みオブジェクトから切り離し、解放されてしまったオブジェクトのメモリに対して登録済みオブジェクトが通知を行おうとすることによる無効なメモリアクセスを防がなければなりません。オブジェクトの登録と通知に関しては、後の章でより詳しく説明します。

ダンプアウト

アトリビュートのゲッターや、summary、 getattributes といったいくつかの標準的なメソッドが呼び出された場合、Max ラッパーオブジェクトによって、「ダンプアウト(dumpout)」という汎用アウトレットが自動的に用いられます。このアウトレットは、必要ならば他の Max メソッドで利用することも可能です。これを行うためには、outlet_anything() とよく似た動作をする max_jit_obex_dumpout() 関数によってアクセスする方法が最も簡単ですが、この関数は最初の引数として、アウトレットへのポインタではなく、Max オブジェクトへのポインタを取ります。あなたのコンストラクタの中でセットされた、アウトレットへのポインタは、max_jit_obex_dumpout_get() 関数によって問い合わせることができ、標準のアウトレット呼び出しによって使用できます。しかし、その場合でも、出力のルーティングを行なうことができるように、ダンプアウトアウトレットからの出力は、単なる bang や int、float ではなくシンボルで始まるメッセージであることが推奨されます。そのため、outlet_anything() を使うことは最も理にかなっています。

追加のインレット/アウトレット

あなたの Max エクスターナルにインレットやアウトレットを追加する場合に、いくつか注意しなければならないことがあります。

第1に、オブジェクトがマトリックスオペレータである場合、マトリックスインレットおよびアウトレットは、高レベルの max_jit_mop_setup_simple() によって、あるいは、より低レベルの max_jit_mop_inputs()max_jit_mop_outputs() の呼び出しによって追加されなければならないという点です。これらのマトリックスオペレータ関数については、「マトリックスオペレータ」の章で述べています。

第2に、オブジェクトが MSP オブジェクトである場合、すべてのシグナルインレット及びアウトレットは左端に置き、非シグナルインレット及びアウトレットはシグナルインレット及びアウトレットの右側に置かなければならない(すなわち、混在することができない)という点です。

最後に、追加されるインレットにプロキシ(詳細は Max/MSP デベロッパドキュメントに述べられています)を使用して、どのインレットでメッセージを受信したかがオブジェクトにわかるようにしておかなければならないという点です。これは、 max_jit_obex_proxy_new() 関数によって行うことができます。インレットナンバは0から始まり、最も左のインレットに対してはプロキシを作る必要はありません。トリガメッセージがどのインレットで受信されたかを知る必要があるメソッドの中では、 max_jit_obex_inletnumber_get() 関数を使うことができます。

Max ラッパーアトリビュート

時には、内部の Jitter クラスではなく、Max ラッパークラス固有のアトリビュートを追加する必要がある場合があるかもしれません。Max ラッパークラスのためののアトリビュートオブジェクトは、前の章で述べた Jitter クラスの場合と同じ方法で定義されます。しかし、これらのアトリビュートは jit_class_addattr() 関数によってではなく、その代わりに max_jit_classex_addattr() 関数によって Max クラスに追加されます。この関数は max_jit_classex_setup() 関数によって返される classex ポインタを取ります。アトリビュートフラグ、および、カスタムゲッター、セッターメソッドは、Jitter クラスで行われた場合と全く同様に定義する必要があります。

Copyright © 2008, Cycling '74