Max 5 API Reference

オブジェクト機能の強化

Preset のサポート

preset はパッチのステート(状態)を保存するシンプルなメカニズムです。ステートの保存が行なわれると、オブジェクトは preset メッセージを受け取ります。あなたのオブジェクトではメッセージを作ってこれに応答します。このメッセージは preset が再び呼び出されたときに、あなたのオブジェクトに送信されます。

よりパワフルで一般的なステート保存を行ないたい場合には、後述の pattr システムを使用して下さい。

preset 内の単一の整数の保存をサポートするのであれば、preset_int() という便利な関数を使うことができます。 preset_int() 関数は、int メッセージと共に、preset の中であなたが送った値を記録します。この値は、後であなたのオブジェクトに送り返されます。

    class_addmethod(c, (method)myobject_preset, "preset", 0);

    void myobject_preset(t_myobject *x)
    {
        preset_int(x, x->m_currentvalue);
    }

より一般的には、preset_store() を使います。次は、2つの値(m_xvalue と m_yvalue)によるリストを保存している例です。

        preset_store("ossll", x, ob_sym(x), gensym("list"), x->m_xvalue, x->m_yvalue);

アシスタンス

オブジェクトのインレットやアウトレットに関する説明をパッチの編集中に表示するために、assist メッセージに対して、この説明用テキストを文字列にコピーする関数で応答することができます。

    class_addmethod(c, (method)myobject_assist, "assist", A_CANT, 0);

次に示す関数は2つのインレットと1つのアウトレット用のものです。io という引数が 1 の場合はインレット、2 の場合はアウトレットを表します。index という引数が 0 の場合は左端のインレットまたはアウトレットを表します。出力文字列 s には最大 512 文字をコピーすることができます。文字列のコピーには strncpy_zero() を使います。また、その時点のオブジェクトの値に基づいてアシスタンス文字列をフォーマットしたい場合には snprintf_zero() を使うことができます。

    void myobject_assist(t_myobject *x, void *b, long io, long index, char *s)
    {
        switch (io) {
            case 1: 
                switch (index) {
                    case 0:
                        strncpy_zero(s, "This is a description of the leftmost inlet", 512);
                        break;
                    case 1: 
                        strncpy_zero(s, "This is a description of the rightmost inlet", 512);
                        break;
                }
                break;
            case 2:
                strncpy_zero(s, "This is a description of the outlet", 512);
                break;
        }
    }

ホットインレットとコールドインレット

オペレータ(+、- など)のようなオブジェクトや int オブジェクトには、演算の実行や値の出力を行なわずに、単に値を格納するだけのインレットがあります。これらのインレットは青い色のラベルをつけられていて、これはそのインレットが処理を実行する「ホット」インレットではなく、「コールド」インレットであることを示しています。このラベル付けを実装するためには、オブジェクトがinletinfo メッセージに応答するようにします。

        class_addmethod(c, (method)myobject_inletinfo, "inletinfo", A_CANT, 0);

オブジェクトの左端以外のインレットがすべて「コールド」であれば、独自の関数を書く代わりに、stdinletnifo() 関数を使用することができます。これは次のようになります。

        class_addmethod(c, (method)stdinletinfo, "inletinfo", A_CANT, 0);

独自の関数を書くためには、index アーギュメントに注目します(この値が 0 の場合、左端のインレットを表します)。この例では、第3のインレットをコールドに切り替えています。「ホット」インレットの場合には、何もする必要はありません。

    void myobject_inletinfo(t_myobject *x, void *b, long index, char *t)
    {
        if (index == 2)
            *t = 1;
    }

テキストエディタの表示

coll や text のようなオブジェクトは、ダブルクリックするとテキストエディタ・ウィンドウを表示します。ユーザはオブジェクトの内容を編集し、更新されたデータを保存することができます。ここでは、同じことをあなたのオブジェクトで行なう方法を示します。

まず、非UI オブジェクトでダブルクリックをサポートする必要がある場合、dblclick メッセージに応答する必要があります。

    class_addmethod(c, (method)myobject_dblclick, "dblclick", A_CANT, 0);

    void myobject_dblclick(t_myobject *x)
    {
        // open editor here
    }

エディタを保持しておくために、オブジェクトのデータ構造体に t_object 型のポインタを追加する必要があります。

    typedef struct _myobject
    {
        t_object m_obj;
        t_object *m_editor;
    } t_myobject;

インスタンス生成ルーチン(new instance ルーチン)で、m_editor フィールドを NULL に初期化します。その後、次のように dblclick メソッドを実装します。

        if (!x->m_editor)
            x->m_editor = object_new(CLASS_NOBOX, gensym("jed"), (t_object *)x, 0);
        else
            object_attr_setchar(x->m_editor, gensym("visible"), 1);

上のコードでは次のことを行なっています。エディタが存在しない場合、"jed" オブジェクトを作り、私たちのオブジェクトをアーギュメントとして渡すことによって、エディタを1つ作ります。これにより、エディタのウィンドウが閉じられたときに、私たちのオブジェクトに対して知らせることができます。

エディタがすでに存在している場合、エディタの visible アトリビュートを 1 に設定して、テキストエディタ・ウィンドウを前面に移動させます。

エディタウィンドウのテキストを設定するためには、このjed オブジェクトに settext メッセージと、最後が 0 で終わるテキストのバッファを送ります。さらに、テキストのエンコード方法を指定するシンボルを送ります。最も良い結果を得るためには、テキストは UTF-8 でエンコードされる必要があります。次の例では、文字列が "Some text to edit" となるように設定し、その後、それをエディタに渡しています。

            char text[512];

            strcpy(text,"Some text to edit");
            object_method(x->m_editor, gensym("settext"), text, gensym("utf-8")); 

title というアトリビュートは、テキストウィンドウのウィンドウタイトルを設定します。

            object_attr_setsym(x->m_editor, gensym("title"), gensym("crazytext"));

ユーザがテキストウィンドウを閉じると、あなたのオブジェクト(あるいは、エディタを作ったときに引数として渡したオブジェクト)には edclose メッセージが送信されます。

            class_addmethod(c, (method)myobject_edclose, "edclose", A_CANT, 0);

edclose メソッドは、このテキストを使って何らかの処理をする責任があります。また、エディタは解放されるため、オブジェクトに保存されているエディタへの参照はゼロでなければなりません。 テキストへのポインタのポインタが、そのサイズと共に渡されます。テキストエンコーディングは常にUTF-8 です。

    void myobject_edclose(t_myobject *x, char **ht, long size)
    {
        // このテキストで何らかの処理を行ないます。
        x->m_editor = NULL;
    }

オブジェクトがテキストファイルの内容を表示している場合、この最初のテキストを表示するという役割もあります。しかし、ユーザがFile メニューから Save を選んだとき、エディタがテキストデータを保存するようにファイルを割り当てることができます。 ファイルを割り当てる場合、ファイル名とパスID があれば、filename メッセージを使用して下さい。

        object_method(x->m_editor, gensym("filename"), x->m_myfilename, x->m_mypath);

filename メッセージは テキストエディタ・ウィンドウのタイトルを設定します。しかし、title アトリビュートを使ってこの単なるファイル名を上書きすることができます。例えば、ファイル名の前にオブジェクト名を表示させたい場合があるかも知れません。

        char titlename[512];

        sprintf(titlename, "myobject: %s", x->m_myfilename);
        object_attr_setsym(x->m_editor, gensym("title"), gensym(titlename));

ユーザが Save を選択するたびに、オブジェクトは edsave メッセージを受け取ります。edsave メソッドからゼロを返すと、エディタは、テキストをファイルに保存し始めます。非ゼロを返すと、エディタは、あなたがテキストの保存を引き受けたとみなします。一般的な考え方はこうです。ユーザがテキストを保存したい場合、オブジェクトの内部で更新するか、ファイル内で更新するか、あるいはその両方でしょう。例えば、js オブジェクトは edsave メッセージを使って、Javascript コードの再コンパイルをトリガします。しかし、それでけではなく、edsave メソッドから 0 を返すということも行ないます。これにより、テキストエディタはスクリプトファイルを更新します。edsave メソッドのプロトタイプは、戻り値を覗いて edclose メソッドと同じです。

    class_addmethod(c, (method)myobject_edsave, "edsave", A_CANT, 0);

    long myobject_edsave(t_myobject *x, char **ht, long size)
    {
        // do something with the text
        return 0;       // tell editor it can save the text
    }

table オブジェクトのデータへのアクセス

table オブジェクトはアーギュメントとして名前をつけることができます。table オブジェクトが名前を持っている場合、table_get()を使ってデータにアクセスすることができます。この関数には、シンボル、データへのポインタを割り当てた場所、そしてデータの長さを与えます。次の例で は、 foo という名前の table にアクセスし、見つかった場合にはそのすべての値をpost によって表示させています。

    long **data = NULL;
    long i, size;

        if (!table_get(gensym("foo"), &data, &size)) {
            for (i = 0;  i < size; i++) {
                post("%ld: %ld",i,(*data)[i]);
            }
        }

table にデータを書き込むこともできます。 書き込んだ後にテーブルエディタを再描画したい場合には、table_dirty() を使って下さい。次の例では、table の中の値をすべてゼロにセットし、table の再描画を行なうように通知しています。

    long **data = NULL;
    long i, size;

        if (!table_get(gensym("foo"), &data, &size)) {
            for (i = 0;  i < size; i++) {
                (*data)[i]  = 0;
            }
            table_dirty(gensym("foo"));
        }

buffer~ サポート

Copyright © 2008, Cycling '74