チュートリアル48:
基本的なJavaScript

JavaScript とは?

JavaScript は、オブジェクト指向のスクリプト言語です。当初は、ウェブサイトの埋め込みソフトウェアの使用を容易にするために開発されました。Max の js オブジェクトは、Max 環境の中での言語として JavaScript を使用することを可能にします。これにより、エクスターナル開発ツール(コンパイラ、デバッガ等)を使わずにあなた自身のオブジェクトのプログラムコードを書くことができます。このチュートリアルでは、js オブジェクトを使って、Max から入力される1つの数値に応答してパッチャーに数値を返すオブジェクトをJavaScript で作る方法についての簡単な例を紹介することにします。

js オブジェクトは、「Max の中で、組み込みプログラミング言語を使って直接オブジェクトを書く」というパワフルな機能を Max ユーザに提供します。簡単に言えば、次のようなことが可能になります。

  • Max オブジェクトそれ自身を使って実装することが難しい、あるいは不可能な手続き的操作を設計し、プログラムすること。2つほど例を挙げると、再帰的処理を必要とするような操作、あるいは、アーギュメントの個数が決まっていないメッセージへの対応が必要な操作などがこれに含まれます。

  • カスタマイズ可能なメッセージに対応し、それ自身の内部データ構造に依存するようなオブジェクトの生成。

  • メッセージに応えて、指定時刻に動作するイベントをスケジュールすること。

  • 多くの jsオブジェクトの間で、或いはjsオブジェクトとMaxパッチャーの間で使われるグローバル変数を管理すること。

  • 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://devedge.netscape.com/library/manuals/2000/javascript/1.5/guide/

 

訳註:上記のURL は現在使用できないようです。英文のリファレンスは次のURL にあります。

JavaScript 1.5 ガイド:http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide

JavaScript 1.5 リファレンス:http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference

また、日本語による JavaScript 1.5 に関するドキュメントが以下のURL にあります。

JavaScript 1.5 ガイド:http://developer.mozilla.org/ja/docs/Core_JavaScript_1.5_Guide

JavaScript 1.5 リファレンス:http://developer.mozilla.org/ja/docs/Core_JavaScript_1.5_Reference


注:JavaScript 言語には、Webブラウザでの使用のために特別に設計された多くの言語の拡張(エクステンション)があるだけでなく、数多くのバリエーションが存在します。Max の js オブジェクトは core JavaScript 言語(上記の URL で概説されているもの)のみをサポートします。また、同様に、Max とのインターフェイスのために、言語に追加されたいくつかのエクステンションをサポートします。

JavaScript の動作

・チュートリアルパッチ、48.Basic Javascript.pat を開いて下さい。パッチからのMIDI プレイバックを聞きたい場合は、Max からの MIDI 出力を聴くように設定された出力シンセサイザが存在するかどうかを確認して下さい(このトピックに関して再確認したい場合は、チュートリアル12:「MIDI ノートの送信と受信」を参照して下さい)。

・パッチの一番上にある toggle をクリックして qmetro をスタートさせて下さい。qmetro が動作するたびに、float オブジェクトは値を js オブジェクトに送ります。float オブジェクトの右インレットに接続された浮動小数点 ナンバーボックスの値をゆっくり増加させて下さい。それに応じて、js オブジェクトの出力が変化します。出力される数値はパッチ内の multislider オブジェクトを使って表示され、MIDI ノートが生成されます。

js オブジェクトへ送る値が 3.0 を超えて増加するに従って、js オブジェクトによって生成される値は高い値と低い値の間で振動を始めます。さらに js オブジェクトへの値を大きくする(3.5 を超える)と、出力はカオス的な振る舞いをします。

このパッチの js オブジェクトは、ロジスティック人口方程式と呼ばれるシンプルなカオス関数をシミュレーションしています。この関数の基本となる式は次のようなものです。

f(x) = rx(1-x)

ここで、r は現在の入力値, x は前の出力値を表しています。

・チュートリアルパッチの js オブジェクトをダブルクリックして下さい。パッチ内の js オブジェクトのためのソースコードが書かれたテキストエディタが表示されます。このコードは「popu.js」というファイルとして保存され、チュートリアルパッチと同じフォルダに置かれています。

Max の js オブジェクトでは、Max の中でベーシックテキストエディタによって、JavaScript コードを直接編集することができます(実際、colltext オブジェクトの内容を編集する際に同じテキストエディタを使っています)。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 に伝えます。JavaScriptコードの変更を行うほとんどの場合と異なり、インレットとアウトレットの数を変更した場合には、この変更を反映させるために、手作業で js オブジェクトを作り直す必要があります。これは、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() を使っています。

私たちの float メソッドの主要部分では、xに対し、r(インレットで受け取った値)、古い x の値、及び 1.0 から古いx の値を引いた値の3つを掛け合わせた結果の値を代入しています。

次の文

x = r*x*(1.-x);

は、Max 内での埋め込みプログラミングの使用によるパワフルな機能の例です。例えば、これを expr オブジェクトで行うためには、オブジェクトのアウトプットを取り出し、Max でのフィードバックループを防ぐために、おそらくナンバーボックスを利用してそれを経由させるといったような方法によって、その値をインレットへフィードバックしなければならないでしょう。

・サブパッチャー p done_with_expr をダブルクリックして、通常の Max オブジェクトでこれを行うとしたらどうなるかを見て下さい。expr オブジェクトは自分が前に出力した値がわからないため、その値を手動で格納し、オブジェクトの2番目のインレットを使ってそれを再び入力しなければならないという点に注意して下さい。

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 オブジェクトからそれを含む Max パッチャーに送り出すことができます。js オブジェクトのためのテキストエディタ内に、直接 JavaScript コードを書くことができます。変更されたスクリプトを保存すると、js オブジェクトはシンタックスエラーや参照エラーのようなプログラミングのミスを見つけるためにコードをスキャンし、Max の中でコードのプログラミングやデバッグを可能にしてくれます。

次の2つのチュートリアルでは、Max の中での使用に関連した JavaScript の他の機能について調べます

コードリスト

// popu.js // // ロジスティック人口方程式のシミュレーション // 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 オブジェクト
expr 数式の評価
print Max ウィンドウへのメッセージの表示