このチュートリアルでは、Max パッチの内部での JavaScript の使い方を紹介します。JavaScript は、オブジェクト指向のスクリプト言語です。当初は、ウェブサイトの埋め込みソフトウェアの使用を容易にするために開発されました。Max の js オブジェクトは、Max 環境の中での言語として JavaScript を使用することを可能にします。これにより、エクスターナル開発ツール(コンパイラ、デバッガなど)を使わず、にあなた自身のオブジェクトのプログラムコードを書くことができます。このチュートリアルでは、js オブジェクトを使って、Max からの単純な数値入力に応答してパッチに数値を返すオブジェクトをJavaScript で作る簡単な例を示します。
js オブジェクトは、「Max の中で、組み込みプログラミング言語を使って直接オブジェクトを書く」というパワフルな機能を Max ユーザに提供します。簡単に言えば次のようなことが可能です。
Max自身 (例えばサブパッチなど)以外のプログラミング言語を使ってMax オブジェクトを開発する場合、いくつかの選択肢があります。Max ソフトウェア開発キット (Max Software Developemt Kit)を使って、C言語 で独自のエクスターナルオブジェクトを開発することができます。また、mxj オブジェクトを使って、Javaでオブジェクトを開発することもできます。この2つの方法では、あなたが書いたコードは、 Max が実行できる形式にコンパイルされなければなりません(これは、共有ライブラリを読み込むことによって直接に、あるいは、Java 仮想マシンを経由してJava コードを実行することによって行なわれます)。js オブジェクト(および、そのグラフィカルバージョンである jsui)を使った場合、パッチを実行する場合と同じように、コードはスクリプトとして直接コンピュータによって評価されます。これにより、js オブジェクトのために書かれたミニプログラムがどのように動作するかを、より速やかにフィードバックさせることが可能になります。このことは、js が最初にコードのミスをチェックしないという意味ではありません。チェックは行われます。ここでは、js オブジェクトがプログラムのミスの発見を手助けする方法をいくつか見ていきます。
Max の js オブジェクトは、Netscape によって開発されたJavaScript 言語のバージョン 1.5 を使用します。このチュートリアルでは、JavaScript についての特別な知識があることを前提としていませんが、この言語についての理解がより深ければ、コードの開発はより容易になるでしょう。Max で使用している、このバージョンのJavaScript に関しての最も信頼できるリファレンスは、次の URL で見ることができます。
http://developer.mozilla.org/en/docs/JavaScript
訳註:日本語による JavaScript に関するドキュメントが以下のURL にあります。
JavaScript 言語には、Webブラウザでの使用のために特別に設計された多くの言語の拡張(エクステンション)があるだけでなく、数多くのバリエーションが存在します。このことを覚えておくと良いでしょう。Max の js オブジェクトは core JavaScript 言語(上記の URL で概説されているもの)のみをサポートし、同時に、Max とのインターフェイスのために追加されたいくつかのエクステンションをサポートします。
チュートリアルを開いて下さい。
チュートリアルパッチを見て下さい。パッチからのMIDI の再生を聞きたい場合には、パッチの左下にある noteout オブジェクトをダブルクリックして有効なMIDI 出力を選んで下さい。
パッチの上部にある toggle をクリックして metro オブジェクト をスタートさせて下さい。metro が動作するたびに、float オブジェクトはjs オブジェクトに値を送ります。float オブジェクトの右インレットに接続されている浮動小数点 ナンバーボックスの値をゆっくり増加させて下さい。それに応じて、js オブジェクトの出力が変化します。出力される数値はパッチ内の multislider オブジェクトを使って表示され、MIDI ノートが生成されます。
js オブジェクトへ送る値が 3.0 を超えて増加するに従って、js オブジェクトによって生成される値は高い値と低い値の間で振動を始めます。さらに js オブジェクトへの値を大きくする(3.5 を超える)と、出力はカオス的な振る舞いをします。
このパッチのjs オブジェクトは、ロジスティック個体数方程式(Logistic Population Equation)と呼ばれるシンプルなカオス関数をシミュレーションしています。この関数の基本となる式は次のようなものです。
f(x) = rx(1-x)
ここで、r は現在の入力値、x は1つ前の出力値を表しています。
チュートリアルパッチの js オブジェクトをダブルクリックして下さい。パッチ内の js オブジェクトのためのソースコードが書かれたテキストエディタが表示されます。このコードは「popu.js」というファイルとして保存され、チュートリアルパッチと同じフォルダに置かれています。
Max の js オブジェクトでは、Max の中でJavaScript コードを直接編集することができます。これは、ベーシックなテキストエディタによって行なわれます(実際、coll や text オブジェクトの内容を編集する際に同じテキストエディタが使用されています)。js オブジェクトが読み込むソースコードは、オブジェクトの最初のアーギュメントによって決められます。これには、Max サーチパス内にあるテキストファイルを指定します。js にアーギュメントを指定しない場合、エディタ内でスクラッチからJavaScript プログラムを書くことができますが、そのプログラムを使うためには、一度ファイルとして保存しなければなりません。
js オブジェクトのエディタを開くと、JavaScript コードを見ることができます。コードは、コメントブロックで始まっていますが、ここには、ファイル名、プログラムの実行内容、作者名が書かれています。これらの行には行頭にダブルスラッシュ(‘//’)があるため、js オブジェクトはこれを無視します。これは一般的に、C++ (および他のプログラミング言語)でコメントを定義するために使われるものです。JavaScriptでは、C 言語のスタイルによるコメント(‘/*’ で始まり ‘*/’ で終わるもの)を使うこともできます。
最初のコメントブロックに続くプログラミング部分では、js オブジェクトで用いるグローバルコードがいくつか定義されています。これは、変数を定義するコード、および、Max 環境の中でこのオブジェクトに対して何かが行われる前に実行しておく必要があるプログラムの部分を実行するためのコードです。この例では、グローバルコードを使って、この js オブジェクトにインレットとアウトレットがいくつ必要かを Max に伝え、変数(xと呼ばれるもの)を定義し、初期化しています。
// インレットとアウトレット inlets = 1; outlets = 1; // グローバル変数 var x = 0.66;
キーワード inlets’と‘outlets’は js オブジェクトにインレットとアウトレットを各々いくつずつ持たせる必要があるかを Max に伝えます。インレットとアウトレットの数を変更した場合、この変更を反映させるために、手作業で js オブジェクトを作り直す必要があります。これ以外の変更をJavaScriptコードに対して行なったときには、、ほとんどの場合その必要はありません。js オブジェクトを含む Max パッチを閉じて再び開くか、オブジェクトボックスをタイプし直すことによって、オブジェクトを作り直すことができます。
‘var’キーワードは JavaScript に対して、これに続くラベルが変数として宣言されることを伝えます。この変数への値の割当ては、宣言の自体の中で行う(ここでは、x イコール 0.66 と宣言することによって、それを行っています)ことも、コードの後の方で行うこともできます。この新しい変数 x はグローバルなスコープを持っています。これがどのような意味を持つかは、後ほど正確に述べることにします。
JavaScript コードに対する変更を確定するためには、テキストエディタ内のコードを保存しておく必要があります。変更を保存する(テキストエディタが最前面に来るようにして、File メニューから Save を選択します)と、Max は js オブジェクトが更新されたことを告げ、あなたのコードで生じている問題があればそれを報告します。
次の行を、コードの中の‘outlets = 1;’という文の下にタイプして下さい。
post(“Hi There!!!”);
テキストエディタ内のコードを保存して下さい。Max ウィンドウには次のように表示されるはずです。
js: Compiling Functions and Executing Global Code...
Hi There!!!
最初のメッセージは、js オブジェクトが(変更された)JavaScript コードを再びロードしたことを報告しています。2行目は、新たに入力したpost() 文からの出力を表示しています。post() 文は、アーギュメントを Max ウィンドウに表示します。これは、print オブジェクトが行っているのと同じことを、js の中で行うためのものです。
次の行を、x を0.66 に初期化している場所の下に正しく追加して下さい。
post(x);
コードを保存すると、Max ウィンドウは次のように報告します。
js: Compiling Functions and Executing Global Code...
Hi There!!! 0.66
post() に文字列(ダブルクォーテーションで囲まれたもの)を与えると、それを表示します。他の文字は変数名として解釈されます。このケースでは、js に対し、前の行で0.66 で初期化した変数 x の値を報告するように要求しています。post() は行の最後に改行文字(キャリッジリターン)を出力しないため、改行を行いたい場合には、post() という文を引数なしで置きます。
この行を、すでに追加してある2つのpost () 文の間のどこかに加えて下さい。
post();
コードを保存すると、今度は、Max ウィンドウが次のように表示します。
js: Compiling Functions and Executing Global Code...
Hi There!!!
0.66
今までに追加したpost()文のうちのどれかから、閉じる丸括弧 (‘)’) を取り除いて下さい。JavaScriptコードを保存して下さい。Max ウィンドウにはエラーメッセージが表示されるはずです。
js: Compiling Functions and Executing Global Code...
•error: js: Javascript: SyntaxError: syntax error, line 15
source line: post(;
このメッセージは、シンタックスエラーと呼ばれるタイプミスが起きていることを教えてくれています。JavaScript の構文(シンタックス)としては不正なものが何か書かれているということを意味するものです。このケースでは、丸括弧は釣り合いが取れていなければならないというルールを破ってしまっています。釣り合いの取れていない丸括弧、大括弧、中括弧は、シンタックスエラーの原因として一般的なものです。js は手助けとして、エラーが起きた行を分離するよう努めます(post() 文を置いた場所によっては、引用される行が多少異なってしまう場合もあります)。
JavaScript コードの問題のある行へカーソルを移動させて、丸括弧を正しく閉じるようにして下さい。コードを保存すると、元のように正しくなります。
JavaScriptでの間違いの原因として一般的なもう一つのものは、スペルミス(綴りの間違い)です。
post() 文の1つを書き直して、‘post’という語の綴りが間違っているようにして下さい(気兼ねなく創作してしまいましょう)。スクリプトを保存して下さい。次のように表示されるでしょう。
js: Compiling Functions and Executing Global Code...
Hi There!!!
•error: js: Javascript: ReferenceError: pst is not defined, line 15
リファレンスエラーとは、JavaScript に対して、全く理解不可能なコマンドを実行するように命じたということを意味します。post() が正式なコマンドを表す単語であるのに対し、pst はそうではありません。
JavaScript はエラーが起こった箇所でグローバルコードの実行を停止するということを覚えておいて下さい。この引用されたケースでは、”Hi There!!!” という語はMax ウィンドウに表示されていますが、xの値 (0.66) は表示されていません。このことは、エラーが起こった場所を探すための重要な手がかり(すなわち、この2つの間のどこかでエラーが起こったということ)を与えてくれます。js コードの開発段階でpost() 文をうまく使うことは、Max でのデバッグで print オブジェクトやワイヤータップ(ウォッチポイントによる傍受)を使うことと全く同様に、重要なことです。後でそれを取り除くことはいつでもできます。
スペルを正しく直してコードを保存して下さい。スクリプトの残りの部分に移りましょう。Max オブジェクトは、メソッドを使うことによって他のオブジェクトとの相互作用を行います。メソッドはオブジェクトのインレットで受け取ったメッセージに応答して実行されるコードのルーチンです。JavaScript では、これらのメソッドはコードの中で関数として定義されていて、それぞれの関数は、受け取ったMax メッセージのそれぞれ異なった型に対応しています。ここで取り上げている js オブジェクトの例では、2つの関数が定義されています。これらの関数(msg_float() と bang())はそれぞれ、オブジェクトがインレットに浮動小数点数、および bang を受け取ったときに実行されるコードを持っています。
まず、bang() 関数を見てみましょう。コードは次のようになっています。
function bang() { post(“the current population is”); post(x); post(); }
この関数は、Max パッチから js に対してbang を送ったときに何を実行すれば良いかを js に指示するものです。ここでは、内容を説明する前置きを付け加えた上で、その時点での x の値を Max ウィンドウに表示します。関数の最後にあるpost() 文は、Max ウィンドウにキャリッジリターン(改行コード)を置き、次のメッセージが新しい行から始まるように Max に命じるものです。関数が波括弧(訳注:{})で囲まれている点に注意して下さい。この波括弧の片方を取り除いてしまうとシンタックスエラーになります。
チュートリアルパッチで、js オブジェクトに接続された button をクリックして下さい。bang メソッドは正しく動作するはずです。
msg_float()functionを見て下さい。これがコードです。function msg_float(r) { x = r*x*(1.-x); outlet(0, x); }
msg_float() 関数はこのJavaScript コードの最も重要な部分を実行します。これは、1つのステキな式の繰り返しを実行するものです。bang() 関数と違って、msg_float() 関数は引数(丸括弧の中に r として書かれているもの)を持っている点に注意して下さい。この引数は js オブジェクトに対し、オブジェクトのインレットに送られてくる浮動小数点数を変数 r に割当てるよう命じるものです。その後、この値は関数の他の部分で使うことができます。
一般的に言って、JavaScriptの関数の名前は、関数を呼び出そうとするメッセージの名前に直接対応しています。例えば、私たちの js オブジェクトでは bang メッセージに対して bang() 関数を対応させています。beep() と呼ばれる関数は、beep という語で始まる Max メッセージに対応しています。しかし、float および int はJavaScript の予約語であるため、float や int に対応する関数を定義するために、それぞれ、msg_float() および msg_int() を使っています。
私たちの msg_float 関数の主要部分では、r(インレットで受け取った値)、古い x の値、および 1.0 から古いx の値を引いた値の3つを掛け合わせた結果をxに代入しています。
次の文
x = r*x*(1.-x);
は、Max 内で埋め込みプログラミング言語を使用することによるパワフルな機能の例です。例えば、これを expr オブジェクトで行うためには、オブジェクトの出力を取り出し、Max でフィードバックループを起こさないような方法を用いて、その値をインレットへ戻さなければなりません。これには、おそらくナンバーボックスを利用してその値を経由させるといったような方法を使うことになるでしょう。
done_with_expr というpatcher オブジェクトをダブルクリックして、通常の Max オブジェクトでこれを行うとしたらどうなるかを見て下さい。expr オブジェクトは自分が前に出力した値を保持していないため、その値を手動で保存しておき、オブジェクトの第2インレットを使ってそれを再び入力しなければならないという点に注意して下さい。
msg_float() 関数のコードの2行目では、新しい x の値を取り出し、それをjs オブジェクトのアウトレットからMax に送っています。outlet() 関数は、引数として使用するアウトレットのナンバーを取り、そこから情報を送り出します。アウトレットのナンバーは 0 から始まり、左端のアウトレット(この例では1つしかありません)が 0 になります。
コードがどのように動作しているかがわかったところで、もう一度パッチを実行させてみて下さい。方程式のどこでカオスが生じるかが理解できるかどうか確認して下さい。そして、それはなぜでしょうか。
この JavaScript コードがうまく動作するためのキーポイントは、x をグローバル変数として使っている点にあります。JavaScript は、多くのスクリプト言語と同様に、変数を使う時にそれに対して動的なメモリ割当てを行います。そして、新しい変数名は、すべてを前もって定義しておかなくても使うことができます。しかし、これらの動的変数は、使用される関数の中でローカル(局所的)なものになります。例えば、msg_float() 関数の中に変数 i がある場合、bang() 関数の中でそれを使うことはできません。同様に、iを両方の関数の中で、それぞれ他とは独立した変数として使うことができます。私たちはグローバルコードの中で x を変数として明確に定義したため、msg_float()(ここでは、x を評価し、新しい値をセットして、その値をパッチに送り出しています)と bang()(ここでは、現在の x の値をMax ウィンドウに表示しています)でx を同じものとして参照することができるのです。
次の行をコメントアウトして下さい。var x = 0.66;
行頭に2つのスラッシュ (‘//’) を置くとコメントアウトできます。スクリプトを保存して、js オブジェクトを作り直すか、チュートリアルパッチを再び開いて下さい。パッチを実行してみて下さい。
x が定義されていないため、js オブジェクトは、float または bang を受け取ったときに参照エラーを報告します。これは、初期化されていない変数にアクセスしようとしたからです。個々の関数の中でx に何かの値をセットすることによってこのエラーを取り除くことができます。しかし、この場合 x はローカル(局所的)に使われることになります。これにより2つの関数の間で x の値を共有できなくなるだけでなく、js に float の値を送るたびに x は毎回再初期化されることになり、オブジェクトが関数による乗算の繰り返しを通じて x を維持することができなくなります。
x の宣言部分をコメント化したものを元に戻して下さい。スクリプトを保存すると、元どおりうまく動作するようになります。
js オブジェクトは、Max の中で標準的なプログラミング言語を用いてコードを書くことを可能にするパワフルなツールです。スクリプトのグローバルコードセクション(すべての固有な関数の外側に属します)では、インレット、アウトレット、およびグローバル変数を定義します。特定のメッセージ(float、bang メッセージ等)に応答するメソッドは関数として、グローバルコードの下に書かれます。そして、これらの関数は、関連づけられたメッセージがMax 環境から送られると、それに応じて実行されます。post() 関数を使って、情報を(パッチでprint オブジェクトを使った場合と同様に) Max ウィンドウに表示することができます。また、outlet() 関数を使って、js オブジェクトから、そのjs オブジェクトを含んでいるMax パッチにメッセージを送り返すことができます。js オブジェクトのためのテキストエディタ内に、直接 JavaScript コードを書くことができます。変更されたスクリプトを保存すると、js オブジェクトはシンタックスエラーや参照エラーのようなプログラミングのミスを見つけるためにコードをスキャンし、Max の中でコードのプログラミングやデバッグを可能にしてくれます。
// popu.js // // ロジスティック個体数方程式(logistic population equation)のシミュレート // f(x) = rx(1-x) // // 入力は r、出力はカレントの x の値 // // rld, 5.04 // // インレットとアウトレット inlets = 1; outlets = 1; // グローバル変数 var x = 0.66; // float -- 方程式を1回実行 function msg_float(r) { x = r*x*(1.-x); outlet(0, x); } // bang -- 現在の個体数をMaxウィンドウに表示 function bang() { post(“the current population is”); post(x); post(); }
js | Max の JavaScript オブジェクト |