この章では、オブジェクトの開発の開発の準備として、開発環境の選択や設定、必要なインクルードファイル、そして、使わなければならないMax エクスターナルに特有の技術全般のうちのいくつかを考えていきます。
Macintosh OSX では、Max/MSP オブジェクトはCFM オブジェクトコードフォーマットを用います。(Mach-O エクスターナルの作成は、Max の将来のリリースでは可能になるはずですが、さしあたっては、Mach-O エクスターナルはサポートされていません。
訳注:MaxMSP 4.6 ではサポートされています。
したがって、現時点では、エクスターナルを開発するためには、Project Builderではなく、コードウォーリアを使わなければならないことになります。CFMを使用することの利点としては、Max4.1以前のバージョンのために書かれた、数多くの既存のエクスターナルが、Max4.2 や4.3 でも何の変更もなく使えるということです。エクスターナルが InterfaceLib(toolbox 関数) や MathLib (数学関数)の呼び出しを行なわない限り、これらは確実に動作します。SDKに含まれるすべてのMacintosh ファイルはCodeWarrior ver.8.x 用にビルドされたものです。開発には、できるだけ最新のリリースを使うことをお勧めします。
訳注:Xcode 2.2.1 以降を使用した、ユニバーサルバイナリによるエクスターナル開発に関する情報は「ユニバーサルバイナリによる開発(U.Binary SDK)」というドキュメントを参照して下さい。日本語訳を掲載しています(原文はCycling '74 サイトの MaxMSP UB SDK のダウンロードページにあります) 。MaxMSP UB SDK により、 MaxMSP 4.5.5 用のソースコードを使って Xcode 2.2.1 以降で使用できるプロジェクトを作成することが可能です。
Windows XP では、SDKに含まれているプロジェクトファイルは MS Visual Studio .NET 2002 以降に対応しています。MS Visual Studio 6.0 用のサンプルプロジェクトファイルも同梱されています。他の開発環境で使用するプロジェクトの設定をおこないたいという方の手助けとなるよう、重要なコンパイラの設定についても言及したいと思います。
このフォルダには、MacOS およびWindowsのためのMax,MSP,Jitterエクスターナルオブジェクトを作成する上で必要なすべてのヘッダファイル、加えて、共通して使用されるファイルがいくつか含まれています。Macintosh では、提供しているサンプルをコンパイルするためには、このフォルダをMetroworks Code Worrior フォルダ(別名、「コンパイラ」フォルダ)の中に置かなければなりません。Windows では、このフォルダをMax external development ディレクトリと同じ階層に置かなければなりませんが、コンパイラの設定で指定したインクルードフォルダに置くこともできます。
提供しているSDKの中のサンプルは、Macintosh 上で新しいコードウォーリアのプロジェクトテンプレートファイルを使ってビルドしたものです。これらのプロジェクトファイルはコードウォーリア8で動作するXMLファイルですが、これにより新しいプロジェクトの設定が容易にできます。最初に、新しい .mcp(Metroworks CodeWarrior Project)ファイルがMac OS XとMax OS 9 双方のためのエクスターナルをビルドするためにどのような動作を行なうかについて説明します。これは、オブジェクトの複数のバージョンをメンテナンスしようとする場合に役立つかもしれません。
hslider.mcp というプロジェクトファイルを開くと、デバッグ、リリース、デバッグ・クラシック、リリース・クラシックという4つのターゲットがあるのがわかると思います(プロジェクトリストウィンドウの一番上のメニューをチェックして下さい)。OSX に関係するものは、「デバッグ」と「リリース」だけです。「クラシック」ターゲットによって、Max/MSP のOS 9 バージョンで動作するオブジェクトをメイクすることができます。
「デバッグ」ターゲットが選択されていることを確認して、リストに表示されたファイルを確認してください。これらのうちの多くのファイルの「ターゲット」の欄にドットがないことから、それらが「デバッグ」ターゲットでインクルードされていないのがわかると思います。(アイコンは赤と白の的とそれを示す矢印になっています)。該当のファイルは CarbonAccessors.o 、MathLib 、Interface.lib です。
ここでは、CarbonLib はインクルードされていますが、「クラシック」ターゲットのうちのどちらかに変えると、CarbonLib がインクルードされず、他の3つのファイルがインクルードされるのがわかります。「CarbonLibを使わなければならない」という点は、OSX 上のエクスターナルオブジェクトをビルドする際の重要なステップです。
しかし、maximun.mcp ファイルを開くと、「クラシック・デバッグ」と「クラシック・リリース」というターゲットの分類が存在せず、上記の「lib」ファイルのインクルードも行なわれていないことに気付くでしょう。これは、maximum オブジェクトが動作する上で、これらのファイルを必要としないからです。したがって、これは、MacOSX およびMacOS9 のどちらの環境でも動作する「ユニバーサル」オブジェクトであると言えます。MacOSを直接扱う必要があるオブジェクトは「ユニバーサル」になることはありません。そのため、クラシックとカーボンの2つのターゲットを別々に設定する必要があります。私たちが用意したプロジェクトテンプレートファイルは、幸いにもこれらをすべて設定することができるようになっています。
CodeWarrior のプロジェクトテンプレートを使うためには、最初にソースファイル(.c)とリソースファイルを入れるフォルダを作る必要があります。ソースファイルとリソースファイルは各々、「オブジェクト名.c」、「オブジェクト名.rsrc」という名前でなくてはなりません。フォルダ名についてもオブジェクト名と同じものにすることを推奨します。次に、適当なプロジェクトテンプレートを選択します。下記のリストは、どのテンプレートファイルを使うかを考えるための良い参考となるでしょう。
注:"ACAH" プロジェクトテンプレートは CarbonAccessors.o を含み、MacHeadersACAF.hを使います。このヘッダは ACCESSOR_CALLS_ARE_FUNCTIONS を定義し、クラシックターゲットでの Carbon Accessor 関数の使用を可能にしています。多くの場合、これによってOSX とOS9 双方のプラットフォームで動作する、カーボン化されたコードを書くことが可能になります。
希望に沿ったテンプレートファイルを開いたら、これを .c および .rsrc ファイルを含むフォルダ内に保存します。ファイル名を「オブジェクト名.xml 」にして、Search メニューから Find and Replace... を選択します。検索文字列として、C74OBJECTNAME を入力し、オブジェクト名を置換文字列として入力します。「Replace ALL」をクリックします。.xml ファイルを保存し、ウィンドウを閉じます。これで、この.xml ファイルの設定は完了です。このファイルによって、CodeWarriorに対し、エクスターナルオブジェクトをビルドするために正しく設定されたCodeWarrior プロジェクトファイル(.mcp)の作成に必要なすべての情報を与えることができます。
CodeWarrior を起動し、File メニューから Import Project...を選び、保存してある.xmlファイルを選択します(例えば、myobjectname.xml)。CodeWarrior がプロジェクトファイルの保存のためのプロンプトを表示しますので、「オブジェクト名.mcp」というファイル名で、.c や .rsrc ファイルと同じフォルダに保存します。新しいプロジェクトが開きます。これは、既にある.c と .rsrc ファイルを含んでいます。デフォルトでは、デバッグターゲットが選択されています。これで、コンパイルによってエクスターナルを作成する作業ができるようになります。オブジェクトのコンパイルを行なうと、プロジェクトフォルダと同じ階層にある "build-mac"(UI オブジェクトの場合には "build-startup-mac")というフォルダの中にオブジェクトがビルドされます。(最適化されないデバッグターゲットでコンパイルした場合、.xSYM ファイルを伴います。下記を参照して下さい)
CodeWarrior デバッガはGDBを使用しています。これはMacOSX の Developer tools CD によってインストールされます。このCDを持っていない場合にはデバッグができません。デバッグを行なおうとしても、今のところCodeWarrior のデバッガでは、でたらめなコードのデバッグを行なってしまうように思われます。これは汎用にはできません。一般的な要点は2つあります。
ターゲット設定の Runtime 設定パネルにある「ホストアプリケーション」の設定を試すこともできます。(デバッグターゲットの Edit メニューから debug Settings... を選ぶという言い方もできます)ここで、Max/MSP 、あるいは Max/MSP ランタイムのコピーを選択します。
もう一つの有用なデバッグリソースとして、Crash Reporter log があります。これは、ユーザの「ホーム」ディレクトリの「ライブラリ」フォルダ内にある「Logs」フォルダの中のCrash Reporter の中にあります。アプリケーションごとにファイルがあり、そのファイルを参照することができます。開発したオブジェクトがクラッシュするたびに最終的にはMax/MSP がクラッシュするため、Max/MSPのログファイルを調べることによって、クラッシュ時にスタックに生じたことを詳細に見ることができます。これが何かのヒントになるかもしれません。しかし、Crahs reporter は Max/MSP のすべてのファイルに関する情報を追加していくため、最後からではなく最初の方を読むよう注意してください。
注:Crash Reporter log は、Metroweruks デバッガを使ってデバッグを行なうかどうかに関わらず、得られるものです。
Apple の「QuickTime SDK for WIndows」には、エクスターナルオブジェクトを Mac から Windows へ移植する際に非常に役立つツールがいくつかあります。これは、 http://developer.apple.com/quicktime/ からダウンロードすることができます。Cycling'74 からダウンロードして得られる Max/MSP SDK zip ファイルには、QuickTime SDK for Windows を使うためのビルド環境を準備するサンプルとして、空のフォルダが含まれています。サンプルプロジェクトはこのフォルダ配置を使うよう環境設定されているので、これを使うことを推奨します。ヘッダファイルを QuickTime SDK からwin-sdks\Quicktime\incフォルダへ、.Libファイルを win-sdks\QuickTime\Lib フォルダへ、さらに、Tools(.exe) ファイルを win-sdk \Quicktime\tools フォルダへコピーします。
Macintosh では、エクスターナルオブジェクトにアシスタンス文字列やアイコンなどのデータを追加するために、リソースファイルが使用されます。Windows 上でMax エクスターナルに Macintosh スタイルのリソースを追加するために、QuickTime SDK の rezwack tool を使うことができます。Visual Studio.NET 用のサンプルプロジェクトでは、この処理を自動的に行なうためのビルドイベントを使っています。単純にアシスタンス文字列をソースコードの中に書き込む(ハードコーディング)ことも可能であるという点に注意して下さい。
QuickTime SDK for Windows はQuickDraw コードを移植する場合にも有用です。QTML ライブラリには、ほとんどのQuickDraw API が含まれていますが、描画コードの移植にネイティブなWin32 APIを使う代わりにこれを利用できます。MaxMSP SDK の xgui sample には、ネイティブな描画を示したプロジェクト(xgui.vcproj)と、QTML による描画を示したプロジェクト(qtxgui.vcproj)の両方があります。
Macintosh から Windows へプロジェクトを移植する最も手っ取り早い方法(オブジェクトがオペレーティングシステムへの依存性を持たないならば)、あるいは、Windows上で新しいプロジェクトを開始する方法については、後述のステップで述べています。しかし、実際のプロジェクトのビルドを試みる前に、SDKで提供しているプロジェクトファイルできちんとビルドできるかどうかの確認をして下さい。
最初に、minimum.vcproj のような、既存のプロジェクトファイル(Visual Studio .NET の場合は .vcproj ファイル、Visual Studio 6.0 の場合は .dsp ファイル)をあなたのオブジェクトのソースコードがある新しいフォルダにコピーして下さい。プロジェクトの設定が同じように動作するためには、フォルダ内のプロジェクトファイルは、他のサンプルプロジェクトと同じ階層に置く必要があるでしょう。言い換えれば、MaxMSPSDK の "projects" フォルダの中にフォルダを作るということになります。また、minimum.def のような既存の定義ファイル(.def)はオブジェクトのソースコードと同じフォルダにコピーします。そして、コピーされたプロジェクトファイルと定義ファイルのファイル名を、あなたのオブジェクトに適した名前(例えばmyobject.vcproj および myobject.def )に変更します。
テンプレートとしての使用に、どのプロジェクトファイルが最も適しているかを判断する手助けとなるよう、4つのSDKサンプルの簡単な概要を述べておきます。
次に、新しい名前の .vcproj(または .dsp)および .def をテキストエディタで、テキストファイルとして開いて下さい。このエディタは、Unixの改行をサポートし、Macintoshスタイルのフォーマッティングをコンバートできる必要があります。良い例として、Metapad(http://www.liquidninja.com/metapad/ から無料でダウンロードできます)が挙げられます。その後、.defと .vcproj の両方のファイル内にあるオリジナルのオブジェクト名のインスタンス(この例で言えば minimum)を検索し、新しいオブジェクト名(例えば myobject )で置換する必要があります。この作業を行なったら、修正された .vcproj と .def ファイルを保存し、これをVisual Studio のプロジェクトとして再び開いてください。Visual Studio は、このプロジェクトのための「ソリューション」ファイル(.sln)を自動的に生成します。
この時点で、必要ならば他のソースファイルを追加しておかなければなりません。<オブジェクト名>.c というファイル(例えば、myobject.c)は既にプロジェクトに含まれています。オブジェクトが、アシスタンス文字列のようなMacintosh のリソースファイルを使っている場合、少なくともしばらくの間、このアシスタンス文字列をCのコードで書き直すことを推奨します。このアシスタンス情報のためにMacintosh リソースを使い続けたい場合、post-build ステップ、および QTML Development material に含まれている rezwack.exe を使うことによって可能になります。この点に関する詳細は、このドキュメントの将来のバージョンでカバーされるでしょう。Windows のリソースはアシスタンス文字列のために使用できますが、Windows リソースの使用法は、このドキュメントではカバーしていません。
やっと、エクスターナルオブジェクトのビルドが可能になりました。Build -> Build Solution を選択して下さい。最終的な出力ファイルは、
"..\..\sysbuild\win_debug\externals\ ",
"..\..\sysbuild\win_rerlease\externals\"
または、同じ場所にある、"max-startup"フォルダに出力されます。エラーがなければ、出力ファイルをMax サーチパス内の適当なフォルダに置いて下さい。あるいは、出力フォルダをMax サーチパスに追加しておくこともできます。Max エクスターナルは、ファイル名に".mxe" という拡張子を使う点に注意して下さい。他のDLLと同じ方法でビルドしているにもかかわらず、エクスターナルは ".dll" という拡張子を持つことはできません。
エクスターナルが直ちにコンパイルできない場合に表示される様々なエラーに関しての包括的なトラブルシューティングはこのドキュメントの範囲を超えていますが、いくつかの共通するエラーや問題、それに対する解決法やアドバイスについて、簡単に述べたいと思います。
Max エクスターナルを他の開発環境で作ることは、かなり直接的な方法になります。ここでは、必要なコンパイラの設定について説明します。最初にMaxだけを使ったエクスターナルについて、次にMSPの機能を使ったエクスターナルで追加する必要がある設定について、最後にQuickTime SDK for Windows を使う場合に追加する必要がある設定について説明します。
すべてのエクスターナルのための基本的な設定
プロジェクトタイプ: Win32 Dynamic Link Library
MSP プロジェクトのための設定の追加 (上記の設定にこれらを追加します):
QuickTime SDK for Windows を使用するプロジェクトのための設定の追加
必要なC言語のヘッダファイルの多くは、c74supportフォルダの中にあります。これらは、それぞれ必ず、または必要に応じてソースファイルにインクルードされなければなりません。
ext.h | すべてのMaxエクスターナルオブジェクトで必須です。 |
ext_proto.h | PowerPC用のエクスターナルをコンパイルする場合に、ext_hによって使われます。 |
ext_support.h | 68K用のエクスターナルにのみ使用されます。保守されません。 |
ext_mess.h | ext.hで使用されるため、直接インクルードする必要はありません。 |
ext_common.h | 一般的に使用されるマクロと定義。 |
ext_qtimage.h | Quicktimeイメージ処理用スケーリング定義 。 |
ext_sndfile.h | サウンドファイルのための構造体定義 。 |
ext_string.h | 文字列処理関数のプロトタイプ 。 |
ext_path.h | ファイルパス情報に依存しないシステムを提供するために必要です。(Chapter 8) |
ext_wind.h | 自分自身のウィンドウを提示するオブジェクトのために必要です。(Chapter10) |
ext_user.h | ユーザインターフェイスオブジェクトの作成に使用します。(Chapter 11) |
ext_colors.h | ユーザインターフェイスオブジェクトのためのカラーパレット定義。 (Chapter 11) |
ext_menu.h | chkmenuメッセージに応答するメソッドのために必要です。 (Chapter 10) |
edit.h | テキストエディタのためのデータ構造。(Chapter 9) |
ext_edit.h | テキストエディタウィンドウとのインターフェイスに使用します。 (Chapter 9) |
ext_anim.h | グラフィックウィンドウやスプライトを使用するオブジェクトのために必要です。 (Chapter 12). |
ext_expr.h | expr オブジェクトとのインターフェイスを使用する場合に必要です。(Chapter 9) |
ext_numc.h | 数値ルーチンを使用する場合に必要です。(Chapter 10) |
ext_midi.h | MIDIマネージャのデータ構造体にアクセスする場合に必要です。 ( timein のコード例を参照) |
ext_event.h | タイムラインエディタを書く場合に使用します。(Chapter 14) |
ext_track.h | タイムラインエディタを書く場合に使用します。(Chapter 14). |
その他、取り扱うMacintosh のデータ構造に関係した特定のインクルードファイルが必要になる場合があります。
このドキュメントを読み通すと、多くのMax の構造体の型定義は、ここで挙げた ext.h で void 型へのポインタ (void *)として述べられていることに気づくでしょう。
Maxはエクスターナルオブジェクトの作成を支援する多くの関数を提供しています。これらは、多くの場合、Maxに組み込まれているオブジェクトがその機能を果たすために用いている関数と同じものです。これらの関数は、Max自身の中でオブジェクトを書く場合に利用できるものと同様なプログラミング・インターフェイスを提供します。
Maxアプリケーションの中では、オブジェクトはロードされた時点で動的にリンクされます。ロードは、オブジェクトがMax-startupフォルダにある場合はMaxの起動時に、Fileメニューのインストールコマンドを用いて明示的にインストールされた場合はその際に、あるいは、オブジェクトボックスにオブジェクトの名前がタイプされた場合やオブジェクトを参照するパッチャーファイルが読み込まれた場合はその時点で実行されます。
この動的なロードによって、完全なコンパイルエラーチェックを経てプロトタイプ宣言されたMax関数呼び出しを使用することが可能になります。これらのプロトタイプを参照したい場合は、Max inludesフォルダの中の、ext_proto.hというファイルを開いて下さい。
個々のMaxエクスターナルオブジェクトはCの構造体定義を必要とします。ノーマルオブジェクトを定義するのであれば、t_object と呼ばれる構造体から始める必要があります。このフィールドはポインタではなく、オブジェクトに含まれる完全な構造体です。一般に、Maxオブジェクトはデータ構造体の開始に関するUNIX規約に従っており、英小文字の後にアンダースコアが続きます。この文字は通常、構造体名の最初の文字を使用します。この例は、t_alarmclockというオブジェクトを仮定した場合の構造体です。
typedef struct alarmclock { t_object a_ob; /* 非ユーザインターフェイスオブジェクトでは、必ず最初に置かなけ */ /* ればなりません */ long a_hours; long a_minutes; long a_seconds; long a_alarmset; } t_alarmclock;
t_object は、いくつかの情報と共に、オブジェクトのクラス定義への参照を含んでいます。このクラス参照によって、クラスのインスタンスは正しい方法でメッセージに応答することができるようになります。
オブジェクト構造体のフィールドにはどのようなデータ型でも自由に用いることができます。Maxは、内部的には、浮動小数をfloat型として格納するため、他の特別な精度を持つものはfloatに含むことができず、失われてしまうということを覚えておいて下さい(これは、あなたのオブジェクトの中で特別な精度を扱えないということではありません)。また、整数(int)はMaxからあなたの書いた関数へlongとして渡され、アウトレットやほとんどのMax構造体にはlongで送られます。