MSPエクスターナル・オブジェクトの開発方法

赤松正行


エクスターナル・オブジェクトの概念

Maxはエクスターナル・オブジェクト(以下オブジェクトと呼ぶ)というメカニズムによってMaxアプリケーションの機能を拡張できるようになっている。このようなオブジェクトの仕組みは、MacOSにおける機能拡張やPhotoshopにおけるプラグインなどに見られるように、極めてポピュラーな手法であり、さまざまなメリットが認められている。

実際、Maxアプリケーション自体に組み込まれた機能は必要最小限のものであって、多くの機能はmax-startupフォルダやexternalsフォルダにオブジェクト・ファイルとして存在している。また、MSPも複数のオブジェクトから成るパッケージとして提供されており、Max本来の機能をそのままに、デジタルオーディオの処理機能をMaxに追加している。

MaxやMSPのオブジェクトは製品に付属して提供されるだけでなく、第三者によって独自に開発されたオブジェクトも多数存在している。オブジェクトの開発方法は公開されており、定められたルールに従って、誰でも開発を行うことができる。開発したオブジェクトを配付または販売するにあたって、特別な許可やロイヤリティ(使用料)等は不要である。

オブジェクトを開発する最大のメリットは、本来の目的でもあるのだが、既存のMaxでは実現できない機能を追加できることにある。Maxには多数のオブジェクトが提供されているが、根本的に提供されていない機能については手の出しようがない。例えば、現時点のMaxはビデオ映像を入力する機能はないので、リアルタイムの画像解析はできない。しかし、ビデオ入力機能を持つオブジェクトを開発すれば、ビデオ映像に基づいた処理をMaxで実現できるわけである。

また、パッチまたはパッチャー・オブジェクトに対して、エクスターナル・オブジェクトは処理速度が速いというメリットもある。パッチやパッチャー・オブジェクトはMaxというインタープリタの処理速度に依存しており、冗長なオーバーヘッドが存在する。これに対して、エクスターナル・オブジェクトはC言語等で記述しコンパイルしたネイティブな実行コードであるため、CPUの処理能力を最大限に活かすことができる。従って、パッチとして実現可能な処理であっても、実行速度が問題になる場合は、エクスターナル・オブジェクトとして作成することが考えられる。

いずれの場合も、Maxアプリケーションには何も手を加えていないことに注目すべきであろう。Max自体を改編することは、Maxの開発者自身でもなければ不可能であるが、オブジェクトというメカニズムによって、誰でも比較的手軽にMaxの機能を拡張できるのである。これはオブジェクトを利用する人にとってもメリットがあり、必要に応じてオブジェクトを追加し、場合によっては不要なオブジェクトを削除することによって、最適な処理環境を構築できることになる。さらに、Maxの開発者によっても、万人の要求に全て応えることは不可能であるので、第三者の開発によって機能が充実することは望ましいに違いない。このように、オブジェクトというメカニズムは、昨今流行のオープンソース運動にも似た、解放された環境をもたらすと言えるのである。


オブジェクトの開発環境

独自のオブジェクトを開発するには、一般的にC言語によってソースコードを記述し、それをコンパイルし、必要なライブラリとリンクして、オブジェクトファイルを生成することになる。従って、C言語による開発環境を用意しなければならない。また、一部リソースを使用するために、リソースエディタも必要になる。当然のことながら、オブジェクトの動作確認のためには、MaxとMSPがなくてはならない。

現在、Macintoshでもっとも良く用いられるC言語の開発環境はMetrowersk社のCodeWarriorであり、本稿でもこれを用いることにする。他の開発言語や開発環境による開発は不可能ではないだろうが、Cycling'74社が提供するSDK(Software Development Kit)がCodeWarriorを前提としているため、これを用いるのが無難であろう。

リソースエディタについては本稿ではApple社のResEditを用いる。ResEditは無償で提供されていることもあって、広く用いられている。ResEditはApple社のホームページから入手することができる。また、CodeWarriorのバージョンによってはそのCD-ROMにResEditが添付されているので、それを用いても良い。

なお、本稿における開発環境の詳細と各ソフトウェアの情報については文末の参考資料を参照されたい。


SDKの準備

オブジェクトの開発を行うには、開発環境とともに、Software Development Kit、略してSDKと呼ばれるファイル群が必要になる。これはホストアプリケーションであるMax/MSPと自ら開発するオブジェクトとの間での処理やデータの遣り取りを規定するものであり、API(Application Programming Interface)やデータ構造などを定義するヘッダファイルや、オブジェクトにリンクされるライブラリファイルなどから成る。

MaxおよびMSPのSDKは製品に付属しているので、簡単にインストールすることができる。MaxのSDKは、そのCD-ROMに含まれる「Software Development Kit」フォルダである(以下「Max SDK」と呼ぶ)。これをハードディスクの適切な場所にコピーしておく。MSPのSDKは、MSPの標準インストール時に組み込まれており、Maxアプリケーションと同じフォルダにある「MSP SDK」フォルダがそれである(図1)。MSP SDKはそのままでも良いが、Max SDKと一緒に「SDK」といった名前のフォルダにまとめておくのも良いだろう。

図1 MSP SDKフォルダの内容

各SDKにはオブジェクトの開発方法を詳しく記述したドキュメントが付属している。Max SDKでは「Writing Externals」なるWord文書、MSP SDKでは「Writing MSP Externals.pdf」なるPDF文書がそれである。いずれも英語での記述ながら、本格的な開発にあたっては必読になる。また、時にはヘッダファイルの内容を読み解くことも必要になるであろう。

なお、MSPオブジェクトはMaxオブジェクトの拡張であるので、MSPオブジェクトを作成する場合にもMaxオブジェクトの開発方法を理解しておく必要がある。日本語によるMaxオブジェクトの開発方法の解説については、文末の参考資料を参照されたい。


オブジェクトのメイク

MSPオブジェクトはスクラッチから書くこともできるが、MSP SDKに含まれるサンプルプロジェクト「plus~オ」を元に開発を行うのが理解し易いだろう。ここでは、まずplus~オをメイクし、そのビルド手順を見ていくことにする。

plus~オなるファイルはプロジェクトファイルであるので、これをダブルクリックすればCodeWarriorのIDEが起動し、プロジェクトの内容がプロジェクトウィンドウに表示される(図2)。ただし、プロジェクトファイルが作成されたバージョンより新しいCodeWarriorを用いる場合は、プロジェクトファイルを更新するか否かを尋ねられるので、この場合は更新を行っておく。

図2 plus~オのプロジェクトウィンドウ

プロジェクトファイルを開くと、おそらくアクセスパスが見つからない旨のエラーメッセージが表示されるだろう。また、プロジェクトのメイクを行うとファイルが見つからない旨のエラーメッセージが表示されるであろう。これらは、各種ファイルのハードディスク上の格納場所などがサンプルプロジェクトが開発された環境と異なるためである。従って、アクセスパスの指定やプロジェクトに含まれるファイルの登録を更新する必要がある。

この作業はCodeWarriorのバージョンによって異なるが、Professional Release 5の場合は以下のような変更を行うことでサンプルプログラムを正常にメイクできるようになる。

・プロジェクト設定ダイアログにおいてアクセスパスのユーザパスにMax SDKの「Max #includes」フォルダ、MSP SDKの「MSP #includes」フォルダ、そしてMaxフォルダを追加する。(図3)

・同じくアクセスパスのシステムパスのうち、{Compiler}:MacOS Support:Libraries:MacOS Common:を{Compiler}:MacOS Support:Universal:Libraries:StubLibraries:に変更する。また、{Compiler}:MacOS Support:Headers:Universal Headers:を{Compiler}:MacOS Support:Universal:Interfaces:CIncludes:に変更する。

・プロジェクトウィンドウのMWCRuntime.Libを削除し、CodeWarriorのMacOS Support:Libraries:Runtime:IRuntime PPC:MSL Runtime.Libを追加する。

図3 アクセスパスの設定

以上の変更でエラーなくメイクができるようになれば、プロジェクトファイルと同じフォルダに+~オブジェクトが生成されているはずである。


新規オブジェクトの作成

ここではオリジナルのオブジェクの例として「%~」オブジェクトを作成する。これは名前から想像されるように、シグナルの商余(余り)を得るオブジェクトであり、Maxの%オブジェクトのオーディオ版と考えれば良い。このオブジェクトは2つのインレットと1つのアウトレットを持ち、両方のインレットにシグナルが入力される場合は、左側を被除数、右側を除数として商余を求め、それをシグナルとして出力する。シグナルの入力がひとつである場合は、アーギュメントまたは入力された整数や実数を除数として計算することにする(図4)。

図4 %~のパッチ例

新しいオブジェクトを作成するには、サンプルとして提供されているplusを改造するのが手軽である。ただし、念のためplus関連のファイルはバックアップを取っておくのが良いだろう。

最初に、元となるplus関連のファイルの名前を変更する。具体的には、plus~オはmodulo~.prjに、plus~.cはmodulo~.cに、plus~オ.rsrcはmodulo~.prj.rsrcのように変更する。

ファイル名を変更すれば、それにプロジェクトに登録されているファイルも変更しなければならない。このためには、プロジェクトファイルであるmodulo~.prjを開き、プロジェクトウィンドウのplus~.cをmodulo~.cに、plus~オ.rsrcをmodulo~.prj.rsrcに入れ替える。ちなみに、「オ」という文字は英語OSでは本来「μ」という文字であるが、日本語OSでは半角カタカナ文字に割り当てられ文字化けするので、ここではprjに置き換えている。

次に、プロジェクトの設定ダイアログを開き、以下のように設定を変更する。

・ターゲット設定において、ターゲット名をmodulo~とする。これはメイクにおける分類であるので、適切な名前であれば何でも良い。

・PPCターゲットにおて、ファイル名を%~とする。これが生成されるオブジェクトファイルの名前となる。

以上が、新しいオブジェクトを作成するための事前準備となる。


リソースの編集

次に、%~オブジェクトが使用するリソースを編集するために、プロジェクトウィンドウのmodulo~.prj.rsrcをダブルクリックする。通常は、ResEditによってmodulo~.prj.rsrcが開かれるはずである(図5)。modulo~.prj.rsrcに含まれるリソースを編集するにあたって、%~オブジェクトが使用するリソースID番号を決めておかなければならない。これは他のオブジェクトと重複してはならないものの、IDの登録制度のような厳密な決定方法は取られていないようである。ここでは8001を用いることにする。ただし、開発元で予約しているリソース番号があるので、これらを用いてはならない。これはMax SDKに含まれるドキュメント「Writing Externals」の26ページ「Reserved Resources」に記載されているので、確認しておく必要がある。

図5 ResEditの画面

リソースウィンドウのmAxLをダブルクリックして開くと、mAxLリソースがひとつだけ含まれていることがわかる。このmAxLリソースを選択して、ResourceメニューのGet Resource Infoを選び、このリソースのID番号を8001に、名前を「%~」とする(図6)。このmAxLリソースは68K用のオブジェクトの実行コードであるが、MSPはPowerPCでのみ動作し、68Kでは動作しない。そこで実行マシンが68Kである場合や、PowerPCマシンでもMax68Kを実行している場合には、このmAxLリソースが対応していない旨のメッセージを表示するようになっている。なお、MSP SDKにはnono.68Kなるリソースファイルがあるが、このnono.68Kに含まれるmAXLリソースも同じ働きをする。

図6 mAxLリソースの設定

次に、STR#リソースもひとつあるので、このリソースID番号も8001と設定する。そしてSTR#リソースを開き、文字列を設定する。これらの文字列はMaxのアシスタンス表示に用いることになる。%~はインレットを2つ、アウトレットを1つ持つので、それぞれに対応する適切な3つの文字列を入力することになる(図7)。

図7 STR#リソースの編集

以上がリソースの編集であるので、リソースファイルを保存し、ResEditを終了する。


ソースコードの編集

modulo.prjが使用するソースコードはmodulo.cのみである。ソースコードを編集するには、プロジェクトウィンドウのmodulo.cをダブルクリックし、ソースコードエディタを開いて編集を行う。

modulo.cはファイル名を変えただけで、中身はplus.cのままであるので、plusを含んだ関数などが散在している。このままでは居心地が悪いので、plusという文字列をmoduloに変更しておこう。これは検索ダイアログですべて置換をすれば良い。また、元々のリソースID番号である3214がソースコード中に使われているので、これを8001に置換する。

ここまでの変更作業が終われば、メイクを行って%~オブジェクトを生成できるはずである。この時点で生成されたオブジェクトは外見的には%~オブジェクトであるが、その動作は+~オブジェクトと同一ということになる。

後は、ソースコードを編集して、目的に応じてオブジェクトの動作を具体的にプログラミングしていけば良い。この%~オブジェクトは元になった+~オブジェクトと入出力の数が同じであり、動作方法も似ているので、すでにある関数の中身を書き換えるだけで良いであろう。そうでない場合は、インレット、アウトレット、アーギュメントに関する処理や対応する関数の追加や削除が必要であり、STR#リソースの変更も必要になる。

ちなみに、作成したオブジェクトと同じフォルダに動作確認用のパッチを作成し、このパッチをダブルクリックすることでMaxを起動するようにすれば良いであろう。このようにすれば、Maxはパッチと同じフォルダにあるオブジェクトを自動的にロードするので、手軽に動作を確認できるわけである。また、ソースコードを変更してオブジェクトをメイクし直した場合は、Maxを再起動しなければならい。Maxは既に読み込まれたオブジェクトをロードし直さないので、オブジェクトを変更してもダイナミックには反映されないためである。そして、最終的にオブジェクトが完成すれば、externalsフォルダやmax-startupフォルダなどのMaxのサーチパスに含まれるフォルダにオブジェクトを移せば良い。


ソースコードの詳細

変数の宣言

まず、グローバル変数として宣言している

void *modulo_class;

は、%~オブジェクトのクラスについて情報へのポインタとして用いる。この内容はMaxが内部的に使用する。このように、一般的なオブジェクト指向言語で言うところのクラス変数は、グローバル変数として宣言すれば良い。

次に、構造体である

typedef struct _modulo
{
    t_pxobject x_obj;
    t_float x_val;
} t_modulo;

は、オブジェクトごとに保持されるデータ構造を定義する。つまり、構造体のメンバーはインスタンス変数(メンバー変数)であり、構造体全体はインスタンスを表すと考えれば良いだろう。この構造体には最初にt_pxobject型のデータを含める。これもMaxが内部的に使用する。これ以外は必要に応じて自由にデータを含めて良い。

メイン関数

一般的なC言語プログラムと同じく、オブジェクトもmain()関数が最初に呼び出される。

void main(void)
{
    setup(&modulo_class, modulo_new, (method)dsp_free, (short)sizeof(t_modulo), 0L, A_DEFFLOAT, 0);
    addmess((method)modulo_dsp, "dsp", A_CANT, 0);
    addfloat((method)modulo_float);
    addint((method)modulo_int);
    addmess((method)modulo_assist,"assist",A_CANT,0);
    dsp_initclass();
    rescopy('STR#',7801);
    post("%%~ by Masayuki Akamatsu,1999");
    post("Sample Object for MSP Summer School");
}

main()関数で行うべき処理は、クラスとしての初期化であり、実際にインスタンスを生成するわけではない。具体的には、まずsetup()関数によってクラスの初期化を行う。その引き数によって情報へのポインタを取得し、コンストラクタ(生成関数)としてmodulo_newを、デコンストラクタ(消滅関数)としてdsp_freeを指定する。また、インスタンス変数のメモリサイズをsizeof(t_modulo)によって指定する。次の引き数はメニュー関数の指定であるが、メニューは用いないので0Lとしている。そして最後にアーギュメントの型を羅列し、0で終わりを告げる。%~ではデフォルト値が0である実数をアーギュメントとするので、A_DEFFLOAT, 0としている。

次に、addmess()関数によってシグナルを受け取る関数としてmodulo_dspを指定する。この関数はDSPメソッドと呼ばれる。同じようにaddfloat()関数によって実数を受け取る関数としてmodulo_floatを、addint()関数によって実数を受け取る関数としてmodulo_intを指定する。また、modulo_assistはアシスタンス機能を処理する関数として指定している。このように、main()関数では、メッセージに応じてどの関数を呼び出して処理を行うかをMaxに伝えることになる。

そしてdsp_initclass()関数を呼び出せば、このオブジェクトはMSPオブジェクトとして動作することになり、シグナル処理が可能になる。

また、rescopy()関数を使ってオブジェクトが使用するリソースの種類とID番号を指定する。Maxはrescopy()によって指定されたリソースをテンポラリーファイルにコピーして使用する。従って、リソースを用いる場合には、オブジェクトにリソースを含めるだけでなく、rescopy()で使用するリソースを指定しなければならない。そして、最後のpost()関数はクレジット表示のために用いている。

生成関数(コンストラクタ)

オブジェクトが実際に生成される時、すなわちオブジェクトがパッチ上に置かれた時に、setup()でコンストラクタとして指定したmodulo_new()関数が呼び出される。

void *modulo_new(double val)
{
    t_modulo *x = (t_modulo *)newobject(modulo_class);
    dsp_setup((t_pxobject *)x,2);
    outlet_new((t_pxobject *)x, "signal");
    x->x_val = val;
    return (x);
}

modulo_new()では、まずnewobject()関数によって、インスタンス、すなわち実際のオブジェクトを生成する。そしてdsp_setup()関数によってインスタンスを初期化し、シグナルを受け取るインレットの数を指定する。また、outlet_new()関数によってシグナルを出力するアウトレットを作成する。そして、modulo_new()はアーギュメントの値を引き数として渡されるので、この値をインスタンス変数であるx_valに格納する。

このようにして、オブジェクトの生成として必要な処理を行えば、生成したインスタンスを戻り値として返す。これ以降、Maxは返されたインスタンスを保持し、メッセージに応じて指定した関数呼び出し、インスタンスを渡すことになる。

消滅関数(デコンストラクタ)

パッチからオブジェクトを取り除いた時や、パッチを閉じた時には、オブジェクトが消滅することになり、Maxはデコンストラクタとして指定した関数を呼び出す。%~ではデコンストラクタとしてdsp_free()関数を指定しており、これはMSPの関数である。dsp_free()はそのオブジェクトがシグナルの処理を終えることをMSPに伝える関数である。

なお、必要であればデコンストラクタとしての関数を記述し、setup()でその関数を指定しても良い。この場合には、その関数の中でdsp_free()を呼び出す必要がある。

整数処理関数、実数処理関数

オブジェクトが整数を受け取った場合にはmodulo_int()関数が、実数を受け取った場合にはmodulo_float()関数が呼び出される。これらはmain()で指定した関数である。

void modulo_int(t_modulo *x, long n)
{
    x->x_val = (float)n;
}

void modulo_float(t_modulo *x, double f)
{
    x->x_val = f;
}

いずれの関数も、1番目の引き数にインスタンスを、2番目の引き数に受け取った整数または実数を渡されるので、これをインスタンス変数であるx_valに格納することにする。入力されるシグナルがひとつである場合に、x_valは余りを求める除数として用いることになる。

シグナル処理関数(DSPメソッド)

オブジェクトがシグナルを受け取ると、main()でDSPメソッドとして指定したmodulo_dsp()関数が呼び出される。

void modulo_dsp(t_modulo *x, t_signal **sp, short *count)
{
    if (!count[0])
        dsp_add(offset_perform, 4, sp[1]->s_vec, sp[2]->s_vec, x, sp[0]->s_n);
    else if (!count[1])
        dsp_add(offset_perform, 4, sp[0]->s_vec, sp[2]->s_vec, x, sp[0]->s_n);
    else
        dsp_add(modulo2_perform, 5, &x->x_obj.z_disabled, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
}

modulo_dsp()の2番目の引き数であるspは、入力または出力するシグナルを表す。一般に、オブジェクトは複数のインレットにシグナルを受け取り、複数のアウトレットからシグナルを出力することができる。そこでspは、インレットの左から右へ、そしてアウトレットの左から右へと、シグナルを表すt_signal型の配列になっている。%~の場合、sp[0]が左インレット、sp[1]が右インレット、sp[2]がアウトレットにシグナルとなる。

また、3番目の引き数であるcountはインレットやアウトレットに実際にシグナルが接続されているか否かを示す。この引き数も配列であり、2番目の引き数と同じ順序でインレットおよびアウトレットにシグナルが接続されているか否かを表す真偽値が収められている。

modulo_dsp()では、インレットに接続されたシグナルがひとつである場合は、インスタンス変数x_valを除数として計算し、シグナルが2つである場合は、左インレットのシグナルを被除数、右インレットのシグナルを除数として計算する。このために、接続されているシグナルによって実際の処理を行う関数をdsp_add()関数によって指定している。これらの関数はパフォームメソッドと呼ばれ、MSPが行う連続的なシグナル処理の流れの中に組み込まれることになる。dsp_add()は、1番目の引き数にパフォームメソッドを指定し、2番目の引き数にパフォームメソッドに渡す引き数の数を指定する。そして3番目以降の引き数にパフォームメソッドに渡す引き数を羅列する。例えばcount[0]が偽の場合、これは右インレットにのみシグナルが入力されている場合であるが、最初のdsp_add()が実行される。この場合、パフォームメソッドはoffset_perform、引き数の数は4であり、引き数は順に右インレットのサンプル(sp[1]->s_vec)、アウトレットのサンプル(sp[2]->s_vec)、インスタンス(x)、サンプル数(sp[0]->s_n)と指定している。

シグナル処理実行関数(パフォームメソッド)

パフォームメソッドであるoffset_perform()関数は、入力されるシグナルがひとつである場合に、実際にシグナルの処理を行う。

t_int *offset_perform(t_int *w)
{
    t_float *in = (t_float *)(w[1]);
    t_float *out = (t_float *)(w[2]);
    t_modulo *x = (t_modulo *)(w[3]);
    int n = (int)(w[4]);
    t_float val = x->x_val;
    t_float result;
    long div;

    if (x->x_obj.z_disabled)
        goto out;

    while (n--)
    {
        if (val == 0.0)
        {
            result == 0.0;
        }
        else
        {
            result = *in;
            div = result / val;
            result -= val * div;
        }

        *out = result;
        out++;
        in++;
    }

out:
    return (w+5);
}

offset_perform()の引き数であるwには、dsp_add()で指定した引き数を配列として渡される。ただしw[0]にはパフォームメソッドのアドレスであり、実際の引き数はw[1]からになる。そこで、まずw[1]以降の値をローカル変数に入れている。これは、先のdsp_add()で指定した通り、順に入力シグナルのサンプル、出力シグナルのサンプル、インスタンス、サンプル数である。

次に、実際のサンプルの処理となるのがwhileブロックである。ここでは入力シグナルのサンプルを被除数とし、x_valを除数として商余を求め、出力シグナルにセットする。これをサンプル数だけ繰り返す。ちなみに、C言語には商余を求めるmod演算子があるが、小数点以下の商余の計算に不都合があったため、地道に計算を行って商余を求めている。

そして、最後に引き数として渡された配列数よりも1大きな要素へのポインタを戻り値として返す。これは決まり事となっている。

なお、入力シグナルが2つである場合は、modulo2_perform()関数がパフォームメソッドとして実行される。modulo2_perform()は、入力シグナルが2つであることを除いては、offset_perform()と似ているので説明を省略する。

ここで注意を要するのは、シグナル以外のメッセージについては、メッセージを受け取る度に、その処理関数が呼び出されるのに対して、シグナルを受け取る関数は、ユーザがVector Sizeとして指定した値に基づく数のサンプルデータを受け取るということである。つまり、DSPメソッドにしろ、パフォームメソッドにしろ、サンプルデータごとに呼び出されるのではなく、Vector Size数だけサンプルデータが貯えられた時点で呼び出されることになる。そして、パフォームメソッドは、ひと固まりの入力されたサンプルデータを一気に処理し、出力するサンプルデータに処理結果を収めるわけである。


参考資料

本稿において使用した開発環境は以下の通りである。

Apple社 PowerMaintosh G3/350/DVD RAM1GB/HD18GB MacOS J1-8.6
Opcode社 Max 3.5.9
Cycling'74社 MSP 1.0 revision 6.1
Metrowerks社 CodeWarrior Professional Release 5 日本語版
Apple社 ResEdit 2.1.3

ソフトウェアの情報については以下のホームページを参照されたい。

Max/MSP国内発売元 カメオインタラクティブ社
http://www.cameo.co.jp/

Max/MSP開発元 Cycling'74社
http://www.cycling74.com/

CodeWarrior国内発売元 ビー・ユー・ジー社
http://www.bug.co.jp/

CodeWarrior開発元 Metrowerks社
http://www.metrowerks.com/

ResEdit入手先 Apple社Software Updatesページ
http://asu.info.apple.com/

Maxのオブジェクト開発については、以下の書籍で解説している。ただし、この書籍で取り上げているのはMax 3.0におけるオブジェクトであり、Max 3.5以降のPowerPCネイティブなオブジェクトの開発には多少の注意を要する。

赤松正行著 「コードリソース」 ビー・エヌ・エヌ社刊 ISBN4-89369-324-7


追補

本稿は、1999年8月に行われた「MSPサマースクール」に合わせて発行した論文集「The Proceedings of MSP Summer School in Japan 1999」に収録された「MSPエクスターナル・オブジェクトの開発方法」をHTML化し、若干の加筆訂正を行ったものである。

ところで、本稿ではパフォームメソッドでのポインタのインクリメントをin++としている。一方、MSPのSDKに納められたサンプルプログラムでは++inとしている。in++としたのは筆者の慣れのためであるが、後にDavid Zicarelliに尋ねたところ、CodeWarriorによってコンパイルされたPowerPCコードとしては、++inと表記するほうが高速に実行されるとの話であった。従って、本稿は初出のままインクリメントをin++としているが、SDKのように++inとして扱う方が望ましいようである。

本稿で説明したプロジェクトファイル、ソースファイル、リソーファイル等は、以下からダウンロードできる。

modulo.sitのダウンロード

Copyright(C)1999-2000 by Masayuki Akamatsu. All Rights Reserved.


追補2

「Max/MSP SDK」(2 June 2001)およびCodeWarrior6(CW6)で開発を行う場合は、setup()の引数のキャストが異なる。CW6でのプロジェクトファイル、ソースファイル、リソーファイル等は、以下からダウンロードできる。

modulo(CW6).sitのダウンロード

Copyright(C)1999-2002 by Masayuki Akamatsu. All Rights Reserved.


return to main page