/**/

チュートリアル 45:
JavaScript 内でのJitterの使用に関するイントロダクション

Max の js オブジェクトは、Max 4.5 で導入されたもので、JavaScript 言語によって書かれた手続き型コードを Max の中で使うことができます。Max の js オブジェクトには、core JavaScript 1.5 言語の実装に加え、Max 固有のオブジェクトやメソッドが数多く追加されています。例えば、Patcher オブジェクト(Max パッチャーとのインターフェイスとして設計されています)や、post() メソッド(Max ウィンドウへのメッセージ表示を行います)などがそれにあたります。js オブジェクトには多くのエクステンション(拡張)があり、Jitter と共に Javasciptを使う場合、Javascript 言語から直接 Jitter の機能を実行することを可能にしてくれます。Jitter による js のエクステンションによって、次のようなことが可能になります。

  • Jitter オブジェクトを直接 Javascript の中でインスタンス化し、手続き型コードの中で Jitter 処理の関数チェインを作ることができます。

  • Javascript によって Jitter の マトリックスを生成し、Javascript 関数からそのマトリックスにアクセスし、値やパラメータをセットすることができます。

  • Jitter ライブラリ操作(例えば、opfunctor オブジェクト)を使って、JavasScript の中で Jitter マトリックス上での高速なマトリックス操作を行うことができます。これにより、Javascript 内での、低レベルの Jitter 処理システムが可能になります。

  • Jitter オブジェクトからのコールバックを待ち受けて、それを受け取り、その結果に基づいて関数を呼び出す(例えば、ムービーのループの中で新しい関数をトリガする)ことができます。

このチュートリアルを始める前に、ぜひともMax のチュートリアルマニュアルにある、「チュートリアル48:基本的な Javascript」「チュートリアル49:Javascript によるスクリプトとカスタムメソッド」を見て、Max でのJavaScript の使い方の基礎を復習しておいて下さい。これらのチュートリアルでは、 js の Javascript コードの中で Jitter オブジェクトの関数チェインをインスタンス化したり、それをコントロールしたりする場合の基本が説明されています。

・Jitter チュートリアルフォルダにあるチュートリアルパッチ、45jJavaScriptIntor を開いて下さい。

チュートリアルパッチには、2列に並んだ Max オブジェクトが表示されます。右側の列には、ムービーにエフェクトをかけて表示する処理を行うパッチがあります。これらの処理は、全てMax パッチ内の qmetro オブジェクトと jit.pwindow オブジェクトの間に接続されている Jitter オブジェクトを使って行っています。左側の列には qmetrojit.pwindowオブジェクトがありますが、その間には 45jWakeFilter.js という JavaScript ファイルをロードする js オブジェクトがあるだけです。このチュートリアルを学習する中で、この両側にある2つのパッチが、まさに、全く同じ処理を行っていることが理解できるでしょう。まず、右側のパッチに注目して、実際にどのような処理が行なわれているのかを見てみましょう。

jit.wake オブジェクト

・右側のパッチで、Display Processing using Patcher と表示されている toggle ボックスをクリックして下さい。右横の read countdown.mov と書かれたメッセージボックスもクリックして下さい。

ここでは、metro オブジェクトの代わりに qmetro オブジェクトを使っています。これは、JavaScript が実行されている間にスケジューラの未処理分が発生する可能性を考えてのことです。Max の js オブジェクトの通常の動作では、カレント(現時点)の処理を実行しながら、スケジューラのために未処理イベントのキューを作っています。結果として、非常に高速な metro オブジェクトは、 js オブジェクトに対する数多くの未処理の bang メッセージをあっという間に蓄積させてしまうことになります。qmetro オブジェクトは、後続のメッセージによって「処理が奪い取られる」ことができるように、bang メッセージを低い優先度のキューの最後に送ります。このトピックに関しての詳細な説明は チュートリアル16 の「名前を持ったJitterマトリックスを使う」を参照して下さい。

jit.pwindowには、徐々に色彩効果が変化するムービーが表示されます。


典型的な Jitter によるビデオエフェクト・チェイン

こちら側のパッチでは、QuickTime ムービーを(jit.qt.movieオブジェクトを使って)再生し、エッジ検出オブジェクト( jit.robcross )に送ります。その後、bob という名前を持ったマトリックスと( jit.opを使って)掛け合わせられています。jit.op から出力されるマトリックスは、時間的なフィードバックと空間的なコンボリューション(畳み込み)をマトリックスに適用する jit.wake オブジェクトによって処理されますが、そのパラメータはプレーンごとに独立してコントロールされています。jit.wake オブジェクトからの出力は( jit.brcosa オブジェクトによって)僅かにブライトネスを増加させられ、名前を持ったマトリックス( bob )に再び格納されます。このエフェクトチェインの出力は、jit.wake オブジェクトの出力として jit.pwindow に表示されます。

名前を持った Jitter マトリックスを使ったフィードバックのテクニックはチュートリアル17:「名前を持ったマトリックスによるフィードバック」で述べられています。jit.robcross オブジェクトは、Robert によるクロスエッジ検出アルゴリズム(他の2種類のアルゴリズムを使用できる同じようなオブジェクトに、jit.sobel があります)を適用します。jit.wake オブジェクトは内部にフィードバック・マトリックスを持っています。これは、様々なモーションや空間的なブラー(ぼかし)効果を作るために、イメージのコンボリューション(畳み込み)と共に使用されます(同様な効果は、jit.slidejit.convolve のようなオブジェクトを使って作ることができます)。

random_bleedという名前の patcher オブジェクトを開いて下さい。

このサブパッチが処理アルゴリズムのバリエーションのキーとなります。ここでは12個の random オブジェクトがあり、これがメイン処理チェインの中の jit.wake オブジェクトのそれぞれ異なるパラメータをコントロールしています。これらの random オブジェクトの出力は、整数による乱数(0 〜 999)から、0 〜 0.6の範囲の浮動小数点の値に変換するため( scale オブジェクトによって)スケールされます。その後、この値は、次のような1つの1ポールフィルタを実現している2つの * オブジェクトと + オブジェクトによって平滑化されます。

yn = 0.01xn + 0.99yn-1

平滑化された値は jit.wake のアトリビュートをセットし、これによって、それぞれの方向(上下、左右)に、それぞれのプレーン(カラーチャンネルとして指定される、赤、緑、青)上で生じる滲みの量をコントロールします。この平滑化アルゴリズムは次のような特徴を持つものであることに気がつくでしょう。平滑化された出力を示している全てのナンバーボックスオブジェクトの値は、0.3(または0.6の半分)近辺で変化する傾向にあります。これらのアトリビュート・セット間でのわずかな違いによって、Jitter のアルゴリズムは、ゆっくりと変化する「色ずれ」を表示します。

・メインチュートリアルパッチに戻り、read wheel.mov および read dozer.mov と書かれているメッセージボックスオブジェクトをクリックして、ムービーを変えてみて下さい。これら2つのムービー上での効果と、"countdown”ムービー上での効果を比較して下さい。新しいムービーを読み込んだときに、bob マトリックスの全ての値を 255 で初期化(事実上、白になるようにクリア)している点に注意して下さい。

Javascript ルート

・パッチの右側のqmetro オブジェクトの上にある toggle ボックスをクリックして、qmetroをオフにして下さい。パッチの左側の qmetro オブジェクトに接続された toggle ボックスをクリックして、qmetro を動作させて下さい。パッチの左側にある、read countdown.mov と書かれているメッセージボックスをクリックして下さい。


見たことがある?

パッチの左側のビデオは、右側で表示されていたものと非常によく似ています。これは、パッチの左側にある js オブジェクトには、ムービーを読み込んで同じエフェクトをかけるマトリックス処理を実行するために必要な全てのオブジェクトと命令が含まれているからです。

・チュートリアルパッチの js オブジェクトをダブルクリックして下さい。このパッチの js オブジェクトのためのソースコードを持ったテキストエディタが表示されます。コードは、チュートリアルパッチと同じフォルダの中にある‘45jWakefilter.js’というファイルに保存されています。

JavaScript コードの最初には、おなじみのコメントブロックがあり、ファイル名が書かれています。その後にはグローバルコードのブロック( jsオブジェクトがインスタンス化されるときに実行されます)があり、続いて、多くの関数が定義されています。これらの関数のほとんどは、Max パッチャーから js オブジェクトへ送られる様々なメッセージに対応するものです。

マトリックスの生成

・グローバルブロックのコード(bang() 関数の前までのコード)に注目して下さい。コードは、js オブジェクトにインレットとアウトレットをいくつ作るかを定義する、おなじみの文で始まります。

// インレットとアウトレット inlets = 1; outlets = 1;

その次には、今まで見たことのないいくつかの文があります。

//作業を行うための Jitter マトリックス (グローバルで宣言します) var mymatrix = new JitterMatrix(4, "char", 320, 240); var mywakematrix = new JitterMatrix(4, "char", 320, 240); var myfbmatrix = new JitterMatrix(4, "char", 320, 240);
// フィードバックマトリックスを、すべて最大値になるように初期化します。 myfbmatrix.setall(255, 255, 255, 255);

このコードのブロックでは、js オブジェクトの中で扱ういくつかの Jitter マトリックスを定義します。変数、mymatrixmaywakematrixmufbmatrix は JitterMatrix オブジェクトのインスタンスとして定義されています。これは、Array やTask、あるいは jsui sketch オブジェクトのインスタンスを定義した場合と同様です。新しい JitterMatrix オブジェクトのアーギュメントは、jit.matrix オブジェクトのアーギュメントとして使用されるものと全く同じです。すなわち、オプションで与えられる名前、プレーン数、型、大きさの値のリストです。

Jitter マトリックスの name アトリビュートと Javascript の内部で表現する「変数名」を混同しないことは重要です。例えば、コードの中で JitterMatrix オブジェクトを作り、それを変数 mymatrix に割り当てているとします。このとき、jit_matrix mymatrix というメッセージをパッチ内の jit.pwindow に送ったとしても、マトリックスは表示されません。この mymatrix オブジェクトは name プロパティを与えられない場合、他の Jitter オブジェクトで用いられるのと同様な慣例によって自動的に生成される name プロパティ(例えば、uxxxxxxxxx)を持ちます。この区別は、Max パッチとデータを共有するために用いられる Javascript グローバルオブジェクトによるものと同様です。

3つの JitterMatrix オブジェクトは全て同じ形式で作られています。コードのこの部分の4行目では、myfbmatrix というJitterマトリックスを指定し、その全ての値を255 にセットしています。JitterMatrix オブジェクトの setall() メソッドがこれを行っていますが、これは、jit.matrixに対する setall メッセージと同様なものです。実際、jit.matrix オブジェクトによって使われている全てのメッセージとアトリビュートは、Javascript の中での JitterMartix オブジェクトのメソッドとプロパティとして公開されています。次はその例です。

// マトリックスの全ての値を 0 にセットする。 mymatrix.clear(); // 値 foo をセル(40.40)の値にセットする。 var foo = mymatrix.getcell(40,40); // セル(30,20)の値を、(255,255,0,0)にセットする。 mymatrix.setcell2d(30,20,255,255,0,0);

setcell2d() メソッドによって、値の配列を用いてマトリックス内の1つのセルの値をセットすることができますが、このとき、最初の2つのアーギュメントはマトリックス内の位置と見なされます。そしてそのセルに、その後に続くアーギュメントの値がセットされます。1次元および3次元のマトリックスのためのユーティリティ関数(それぞれ、 setcell1d()setcell3d() )も存在します。汎用の手段としては、Max メッセージでの場合と同様な、シンプルな setcell() 関数を使って、mymatrix.setcell( 0,30,“val”, 0, 0, 255,255) という形で指定することができます。

オブジェクトの生成

・グローバルブロックの続きを読んでみましょう。ここまでで、作業用のマトリックスを生成しましたが、次はそれらを扱うオブジェクトを作ります。

// 使用する Jitter オブジェクト。(これもグローバルで宣言します) var myqtmovie = new JitterObject("jit.qt.movie", 320, 240); var myrobcross = new JitterObject("jit.robcross"); var mywake = new JitterObject("jit.wake"); var mybrcosa = new JitterObject("jit.brcosa");

この4行はJitterObject オブジェクトのインスタンスを作るものです。右側の Max パッチにある4つのオブジェクト(jit.qt.moviejit.robcrossjit.wakejit.brcosa)に対応した、同じ機能を持つ4つのオブジェクト(myqtmoviemyrobcrossmywakemybrcosa)が必要です。この後で見るように、これらの JitterObject オブジェクトはMax パッチャー内の対応する4つのオブジェクトと同じように動作します。JitterObject のインスタンス化を行う場合の第1のアーギュメントは、ロードしたいJitter オブジェクトのクラス(例えば、 “jit.qt.movie”は、JavaScript の中へ jit.qt.movie をロードします)です。オブジェクトに対するそれ以降のアーギュメントは、 Max パッチャーでの場合と同様にオブジェクトに渡すことができます。そのため、新しい JitteObject jit.qt.movie にアーギュメントとして 320, 240 という値を与えることによって、320 x 240 の大きさ(dim)を持つように命じることができます。

オブジェクトボックスで、オブジェクト名に続いてタイプ入力することによってアトリビュートを初期化できる(例えば、jit.brcose @saturation 1.1)のと同様に、グローバルな Javascript コードを使って、すでに生成した JitterObject オブジェクトのアトリビュートを初期化することができます。

myrobcross.thresh = 0.14; // エッジ検出のための閾値(スレシュホルド)をセット mywake.rfb = 0.455; // wake red チャンネルのフィードバック値をセット mywake.gfb = 0.455; // wake green チャンネルのフィードバック値をセット mywake.bfb = 0.455; // wake blue チャンネルのフィードバック値をセット mybrcosa.brightness = 1.5; // フィードバックステージのブライトネスをセット

JitterObject のプロパティが、ロードされるJitter オブジェクトで使われるアトリビュートと直接対応している点に注意してください(例えば、jit.brcosaオブジェクトをロードする JitterObject は、brightnesscontrastsaturation というプロパティを持ちます)。上記のコードでは、パッチの右側にある jit.robcross オブジェクトと全く同じになるように、JitterObject myrobcross の thresh プロパティを 0.14 に設定しています。同じ方法で、mywakemybrcosa オブジェクトのアトリビュートも同様に初期化しています。

Jitter オブジェクトのメソッドを呼び出す JavaScript 関数

read() 関数のコードを見てみましょう。この関数は js オブジェクトが read メッセージを受け取った場合に呼び出されます。

function read(filename) // ムービーの読み込み { if(arguments.length==0) { // ムービーが指定されていない場合には、「ファイルを開く」ダイアログを表示 myqtmovie.read(); } else { // 指定されたムービーを開く myqtmovie.read(filename); } // フィードバックマトリックスを全て最大値に初期化 myfbmatrix.setall(255, 255, 255, 255);
}

read() 関数は、js オブジェクトに送られた read メッセージのアーギュメントを解析します。アーギュメントがないことが判明すると、myqtmovie オブジェクトの read() メソッドをアーギュメントなしで呼び出します。アーギュメントが指定されている場合には、myqtmovie オブジェクトに対して、そのアーギュメントをファイル名として読み込みを行うよう命じます。

・パッチの左側にある、read と書かれたメッセージボックスをクリックして下さい。Max パッチャーにある jit.qt.movie オブジェクトに read メッセージを送った場合と同じように、ダイアログボックスがポップアップされる点に注意して下さい。ダイアログをキャンセルするか、新しいムービーをロードして、このアルゴリズムがムービーにどのように作用するかを見て下さい。


JavaScript の JitterObject はMax パッチャーの中にある場合と同じように動作します。

必要があれば、ムービーのオープンに失敗していないかどうかを確認するために、read() メソッドによって返された Array を見ることができます。しかし、ここでは、js オブジェクトに送られる read メッセージのアーギュメントが、サーチパス内にある正当なQuickTime ムービーのファイル名であると確信できます。

ムービーを読み込んだ後(あるいは、myqtmovie オブジェクトに、jit.qt.movieの 「ファイルを開く」ダイアログを表示するよう命じた後)、JitterMatrix である myfbmatrix の全ての値が 255 になるように初期化します。

パフォームルーチン

通常の Jitter 処理チェインが、qmetro に対応して、jit.qt.movie から一連の Jitter オブジェクトを通じて出力までに至る動作を行うのと同様に、JavaScript の Jitter アルゴリズムは、処理アルゴリズムの1つのループ(1つのマトリックスの出力)を外部ソースからの bang に対応して実行します。

・JavaScript コードの bang() 関数を見てみましょう。Max パッチャーの中と同じように、各々の JitterObject は順番に呼び出され、交替でマトリックスを処理していきます。

function bang() // 再生/処理 ループの繰り返し(イタレーション)のうちの1回分を実行 { // セットアップ // 新しいマトリックスの滲みの係数を計算 calccoeffs(); // 処理 // ムービーから新しいマトリックスを取り出す ([jit.qt.movie]) myqtmovie.matrixcalc(mymatrix, mymatrix); // エッジ検出を実行 ([jit.robcross]) myrobcross.matrixcalc(mymatrix, mymatrix); // 前の(明度を上げられた)出力と掛け合わせる (brightened) mymatrix.op("*", myfbmatrix); // wake のエフェクトの処理 (同じ場所での処理はできません) ([jit.wake]) mywake.matrixcalc(mymatrix, mywakematrix); // 明度を上げて、フィードバックマトリックスにコピー ([jit.brcosa]) mybrcosa.matrixcalc(mywakematrix,myfbmatrix); // 処理済みのマトリックスを Max へ出力 outlet(0, "jit_matrix", mywakematrix.name); }

bang() 関数が mywake オブジェクトのプロパティ(詳しくは後述)をセットアップする中で、calccoeffs() 関数が呼び出されます。その後には、Jitter オブジェクトの処理チェインが続きます。これは、新しいマトリックスを myqtmovie オブジェクトから取得して、それを変化させます。JitterObject のmatrixcalc() メソッドは、Max の中で Jitter オブジェクトに bang メッセージ(マトリックスを生成する Jitterオブジェクトの場合)、あるいは、jit_matrix メッセージ(マトリックスの処理、または表示を行うオブジェクトの場合)を送ることと同じです。matrixcalc() メソッドへのアーギュメントは最初が入力マトリックス、次が出力マトリックスです。myqtmovie オブジェクトは入力マトリックスとして不要なアーギュメントを持っていますが、これは無視されます。ここでは、単純に有効な JitterMatrix の名前を与えるだけです。2つ以上のインプット、あるいはアウトプットを必要とする jitter オブジェクト(例えば、jit.xfade)によって処理をする場合、matrixcalx() メソッドにはブラケット([ , ])の中にマトリックスのセットを配列として与えます。

JitterMatrix オブジェクトの op() メソッドは、マトリックスに対して jit.op オブジェクトを実行することと同じです。アーギュメントは op アトリビュート、および、実行の際にスカラー(値)を使うか、マトリックスを2番目のオペランドとするかの指定に対応しています。従ってこれらを物語風に言うと、bang() 関数の「処理」のセクションでは次のようなことが起こっているということができます。

myqtmovie オブジェクトはロードしたビデオファイルの現在位置から新しいマトリックスを生成し、JitterMatrix である mymatrix に格納します。

myrobcross オブジェクトは mymatrix オブジェクトを取得し、そのエッジ検出を実行して、結果を同じマトリックスに格納します(このことに関する詳細は後述します)。

・mymatrix という JitterMatrix に、mymatrix の op() メソッドを使って myfbmatrix の内容が掛け合わせられます。この乗算は前のステップと「同じ場所」で行われます。

mymatrix という JitterMatrix を mywake オブジェクトによって処理し、その出力を mywakematrix という3番目の JitterMatrix に格納します。

・最後に、JitterMatrix である mywakematrix の明度を上げ、その出力を myfbmatrix に格納して、bang() 関数の次の繰り返し処理で使用します。従って、私たちのJavaScript コードでは、マトリックス myfbmatrix は、Max パッチで使用された bob という名前のマトリックスと全く同様に使われています。

技術的な注:ロードされる Jitter オブジェクトのクラスによって、JitterObject は、matrixcalc() メソッドの入力と出力の両方で同じマトリックスを使うことができます。この「同じ場所」を利用した処理によって、処理時間と、新しい中間のマトリックスにデータをコピーするためのメモリの節約になります。このような動作ができるかどうかは、完全に Jitter オブジェクトの内部動作に依存しています。例えば、jit.brcosa オブジェクトは正しく動作するのに対し、jit.wake オブジェクトでは(前の出力マトリックスによってフィードバック処理を行うため)動作しません。同様な根拠によって、JitterMatrix オブジェクトの op() メソッドは処理を「同じ場所」でうまく行うことができます。

処理されたマトリックス(mywakematrix マトリックスに格納された mywake オブジェクトの出力)は outlet() 関数を使ってパッチャーに送り出されます。

outlet(0, "jit_matrix", mywakematrix.name);

この呼出しでは、JitterMatrix の name プロパティを使って、マトリックスの名前(uxxxxxxxxx)をMax パッチの受け側のオブジェクトに送信します。

他の関数

・JavaScript コードの calccoeffs() 関数を見てみましょう。この関数は、bang() 関数が実行されるたび毎にに、内部的に呼び出されます。

function calccoeffs() // [jit.wake] オブジェクトの畳み込み(コンボリューション)の状態を決定する // 12 の滲みの係数を計算します{ // red チャンネル mywake.rupbleed*=0.99; mywake.rupbleed+=Math.random()*0.006; mywake.rdownbleed*=0.99; mywake.rdownbleed+=Math.random()*0.006; mywake.rleftbleed*=0.99; mywake.rleftbleed+=Math.random()*0.006; mywake.rrightbleed*=0.99; mywake.rrightbleed+=Math.random()*0.006;
// greenチャンネル mywake.gupbleed*=0.99; mywake.gupbleed+=Math.random()*0.006; mywake.gdownbleed*=0.99; mywake.gdownbleed+=Math.random()*0.006; mywake.gleftbleed*=0.99; mywake.gleftbleed+=Math.random()*0.006; mywake.grightbleed*=0.99; mywake.grightbleed+=Math.random()*0.006;
// blueチャンネル mywake.bupbleed*=0.99; mywake.bupbleed+=Math.random()*0.006; mywake.bdownbleed*=0.99; mywake.bdownbleed+=Math.random()*0.006; mywake.bleftbleed*=0.99; mywake.bleftbleed+=Math.random()*0.006; mywake.brightbleed*=0.99; mywake.brightbleed+=Math.random()*0.006; } calccoeffs.local = 1; // パッチャーから呼び出されないようにします

calcoeffs() 関数は、文字通り、パッチの右側にある random_bleed パッチャーの機能を複製したものであることがわかるでしょう。これは、jit.wake オブジェクトが持っている様々なアトリビュートに対応した、mywake JitterObject の様々なプロパティをセットします。これらのプロパティを通常の変数のように使って、値をセットしたり、取得したりできる点に注意して下さい。これにより、その値を同じ変数で、オペレータを使って変更することができます。例えば、次はその例です。

mywake.rupbleed*=0.99; mywake.rupbleed+=Math.random()*0.006;

このコード(mywake オブジェクトの異なるプロパティのために12 回繰り返されています)は、mywake のカレントの rupbleed プロパティの値を初期値として使い、それに 0.99 を掛け、小さなランダム値(0 と 0.006 の間)を加算しています。

まとめ

Max の中で JavaScript コードを使って、Jitter のマトリックスやオブジェクトを使った手続き的システムを定義することができます。js の中の JitterMatrix オブジェクトによって、JavaScript の中で Jitter マトリックスの生成、値のセット、アトリビュートの問い合わせを行うことができます。例えば、JitterMatrix の setall() メソッドでは、全てのセルを特定の値にセットすることができます。op() メソッドを使って、JitterMatrix に対し、「同じ場所」で数値演算を適用することができます。このメソッドには、jit.opオブジェクトで使われる数学的なオペレータの完全なセットが含まれています。Jitter オブジェクトは、クラスとして、JitterObject オブジェクトの中へロードされることが可能です。インスタンス生成時に、JitterObject はJitter オブジェクトのメッセージとアトリビュートと全く同様な、プロパティとメソッドを得ます。JitterObject の matrixcalc() メソッドは、Jitter オブジェクトに bangまたは jit_matrix メッセージを送信した場合と全く同様に動作します。どちらの動作を行うかは、オブジェクトのクラスに関連して決まります。これは、Jitter 処理の複雑な関数グラフを、JavaScript に移植することを可能にしてくれます。

次の2つのチュートリアルでは、Jitterと連携した可能性の拡大のために JavaScript を使用する他の方法について見ていきます。

コードリスト

// 45jWakefilter.js // // Jitter オブジェクトとマトリックスを [js] の中での使用例を示す、ビデオ再生処理チェイン // // rld, 6.05 // //インレットとアウトレット inlets = 1; outlets = 1;

//作業を行うための Jitter マトリックス (グローバルで宣言します)
var mymatrix = new JitterMatrix(4, "char", 320, 240); var mywakematrix = new JitterMatrix(4, "char", 320, 240); var myfbmatrix = new JitterMatrix(4, "char", 320, 240);

//フィードバックマトリックスを、すべて最大値になるように初期化します。 myfbmatrix.setall(255, 255, 255, 255);

//使用する Jitter オブジェクト。(これもグローバルで宣言します) var myqtmovie = new JitterObject("jit.qt.movie", 320, 240); var myrobcross = new JitterObject("jit.robcross"); var mywake = new JitterObject("jit.wake"); var mybrcosa = new JitterObject("jit.brcosa");

// Jitter オブジェクトのために、いくつかのアトリビュートの初期値を設定します。 myrobcross.thresh = 0.14; // エッジ検出のための閾値(スレシュホルド)をセット mywake.rfb = 0.455; // wake red チャンネルのフィードバック値をセット mywake.gfb = 0.455; // wake green チャンネルのフィードバック値をセット mywake.bfb = 0.455; // wake blue チャンネルのフィードバック値をセット mybrcosa.brightness = 1.5; // フィードバックステージのブライトネスをセット

function read(filename) //ムービーの読み込み { if(arguments.length==0) { // ムービーが指定されていない場合には、「ファイルを開く」ダイアログを表示 myqtmovie.read(); } else { //指定されたムービーを開く myqtmovie.read(filename); } // フィードバックマトリックスを全て最大値に初期化 myfbmatrix.setall(255, 255, 255, 255); }

function bang() //再生/処理 ループの繰り返し(イタレーション)のうちの1回分を実行{ //セットアップ
//新しいマトリックスの滲みの係数を計算: calccoeffs();
//処理
// ムービーから新しいマトリックスを取り出す ([jit.qt.movie]): myqtmovie.matrixcalc(mymatrix, mymatrix);
// エッジ検出を実行 ([jit.robcross]): myrobcross.matrixcalc(mymatrix, mymatrix);
// 前の(明度を上げられた)出力と掛け合わせる (brightened) mymatrix.op("*", myfbmatrix);
// wake のエフェクトの処理 (同じ場所での処理はできません)([jit.wake]): mywake.matrixcalc(mymatrix, mywakematrix);
// 明度を上げて、フィードバックマトリックスにコピー ([jit.brcosa]): mybrcosa.matrixcalc(mywakematrix,myfbmatrix);
// 処理済みのマトリックスを Max へ出力 outlet(0, "jit_matrix", mywakematrix.name);
}

function calccoeffs() // [jit.wake] オブジェクトの畳み込み(コンボリューション) // の状態を決定する12個の滲みの係数を計算します { // red チャンネル mywake.rupbleed*=0.99; mywake.rupbleed+=Math.random()*0.006; mywake.rdownbleed*=0.99; mywake.rdownbleed+=Math.random()*0.006; mywake.rleftbleed*=0.99; mywake.rleftbleed+=Math.random()*0.006; mywake.rrightbleed*=0.99; mywake.rrightbleed+=Math.random()*0.006; // green チャンネル mywake.gupbleed*=0.99; mywake.gupbleed+=Math.random()*0.006; mywake.gdownbleed*=0.99; mywake.gdownbleed+=Math.random()*0.006; mywake.gleftbleed*=0.99; mywake.gleftbleed+=Math.random()*0.006; mywake.grightbleed*=0.99; mywake.grightbleed+=Math.random()*0.006; // blue チャンネル mywake.bupbleed*=0.99; mywake.bupbleed+=Math.random()*0.006; mywake.bdownbleed*=0.99; mywake.bdownbleed+=Math.random()*0.006; mywake.bleftbleed*=0.99; mywake.bleftbleed+=Math.random()*0.006; mywake.brightbleed*=0.99; mywake.brightbleed+=Math.random()*0.006; } calccoeffs.local = 1; // パッチャーから呼び出されないようにします。