/**/

チュートリアル 26:
MIDIによるビデオのコントロール

MIDIと映像の関係

Maxが最初に開発されたとき、Maxは主にMIDIを用いてインタラクティブに楽器をコントロールするものでした。コンピューターの処理速度が向上するにつれて、MSPを使用してオーディオ信号が直接Max上で生成できるようになり、 そしてJitterを用いて映像のような大量のマトリックスデータが処理できるようになってきました。Maxの力が偉大なのは、それらの分野のデジタルデータ(MIDI、オーディオ、映像)の全てを操作することができ、そしてそれらを相互に結びつけることができるためです。このチュートリアルでは入力されるMIDIデータによってJitterのビデオ再生をコントロールすることに焦点をあてて見ていきます。

MIDIで映像をコントロールすることによる主な利点として、次のようなものがあります。

  1. 画面上をマウスで操作するのではなく、フィジカルインターフェース(スライダーやホイールなど)を使用することができます。

  2. リアルタイムなパフォーマンスによって、音と映像の間に面白い関係を作り出すことができます。

MIDIコントローラーには映像のコントローラとして使用できる物も数多くあります。複数のスライダのバンクや、フェーダボックス、デジタルミキサ、ジョグホイール等です。ほとんどのシンセサイザーキーボードにはボタン、スライダ、ホイール、そしてフットペダルがピアノ型の鍵盤と共に搭載されています。このチュートリアルではそれらの多くには触れず、一般的に用いられているMIDIキーボードを扱います。

このチュートリアルは、MIDIのセットアップがMax チュートリアルやMSPチュートリアルで使われている設定であることを前提として書かれています。具体的には、次のようなことが仮定されています。

  1. OMSがインストールされていて、OMS Setupを使用してOMSの設定がされており、MaxのファイルメニューにあるMidi SetupからMaxの仮想ポートをOMS Setupで設定したデバイスに設定してあること。

    訳注:現在のバージョンのMax/MSP では OMS がインストールされている必要はありません。機器の設定については、Maxファンダメンタルの「セットアップ」「MIDIの使用」「ポート」、Maxチュートリアルの「イントロダクション」、MSP チュートリアル「オーディオ I/O」などのドキュメントを参照して下さい。

  2. モジュレーションホイールと、ピッチベンドホイールがついている61鍵のMIDIシンセサイザーキーボードを使用すること。

  3. キーボードはMIDIインターフェースに接続されており、Maxの仮想ポートaに設定されていること。

このチュートリアルパッチでは、ビデオを「演奏」します。MIDI キーボードからのノート情報を使用してムービーの再生をコントロールしたり、様々な種類のMIDIメッセージを使用してリアルタイムでビデオにエフェクトをかけたり、エフェクトの調整を行なったりしていきます。

ビデオコントロール用のパラメータのための、MIDIデータのマッピング

MIDIのチャンネルメッセージ(ノート、ピッチベンド、アフタータッチなど)のデータは0から127までの値です。ほとんどの場合、Jitterのアトリビュートは、アーギュメントとして0から1までの値を用います。特にデータ型charでプレーン数が4の2Dマトリックスを使って映像を扱う場合などはこれにあてはまります。このため、始めに行なわなければならないことの1つは、Jitterオブジェクトのコントロールに適切な範囲にMIDIデータを変換することです。このチュートリアルパッチではそのためのいくつかの方法を説明します。

・Jitter Tutorialフォルダからチュートリアルパッチ26jMIDIControl.patを開いて下さい。

このパッチの黄色い部分には、様々な MIDI 入力用オブジェクトがあり、ポート a に接続されたキーボードコントローラが生成するMIDI 情報を収集しています。ctlin a 1 はモジュレーションホイールからの値を、ctlin a 7 はボリュームペダルからの値を、bendin a はピッチベンドホイールからの値を、notein a はキーボードからの値をそれぞれ受け取っています。モジュレーションホイールやボリュームペダルのようなコンティニュアスコントローラは、連続した値を出力するため、ここでは最も使いやすいコントロールです。これらの値を0から1の範囲にマッピングするのはとても簡単で、単純に127で割るだけです。


MIDIのコントロールデータを0から1の範囲に変換する

どちらのコントロールデータも0から127までの範囲の値です。モジュレーションホイールが"標準"で止まっているときの値(モジュレーションをかけていない状態)は0ですが、ボリュームペダルの通常の位置での値は0ではなく100や127などの値(ボリュームがオンの状態)です。そのため、それぞれ多少異なった方法で映像のエフェクトをコントロールするために使えるでしょう。

ピッチベンドホイールは、これとは違った標準の位置を持ちます。標準で止まっている位置での値は64で、ユーザがホイールを離すとこの位置に戻ります。そこで、止まっている状態の値が0.5になるようにしたいのですが、困ったことに64は0と127のちょうど中央ではありません。単純に127で割った場合、ベンド値64は0.504になってしまいます。そのため、ここでは下の例のように、下方向のベンド値と上方向のベンド値に対して別々な処理を行なっています。


中心の値から下方向には64個のピッチベンドの値があり、上方向には63個の値があります

キーボードからのピッチに関する情報では、問題はさらに複雑です。まず第1に、ほとんどのキーボードは0から127までに対応する鍵盤をもっていません。普通の5オクターブのキーボードではMIDIノートナンバー 36から96までの値を出力します。さらに重要なことは、ノートナンバーはピッチの"高さ"(0から127までの幅を持った値)としてだけではなく、音楽的に意味を持った"ピッチのクラス"(C、C#、Dなど 12半音ごとに作られる 12 のクラス)として認識されるということです。このパッチでは、2通りの方法でピッチを確認できるようにしてあります。ノートナンバーの36から96までの範囲の値を0から1までの範囲の値にし、% 12オブジェクトを使用してピッチのクラスを取得しています。(全てCは0、C#は1というようになります)


ノートオンの時のノートナンバーを使ってピッチの高さとピッチのクラスを取得

上の例では、他にもいくつかの便利なオブジェクトを使用して、入力されるノートナンバーの値の範囲を,小さな値の範囲に変換しています。poly 1 1 オブジェクトは一回に1つだけのノートオンメッセージを通過させます。このオブジェクトは次のノートオンメッセージを受信すると、自動的に直前のノートオンメッセージに対するノートオフメッセージ(同じノートナンバーでベロシティが 0 のメッセージ)を送信します。ユーザーがレガート奏法(前のキーを離す前に次のキーを押す)で弾いたり、コードとして複数のノートを「同時に」(実際には「ほぼ同時」です。MIDIにおいては、全く同時ということはあり得ません)弾いたりした場合、実際にこのパッチがどのノートの値をトラッキングしているのかわかりにくくなるため、ここでは、一度に一つだけのノートナンバーをトラッキングするようにしておく必要があります。。poly 1 1オブジェクトを使用することによって、現実のMIDIキーボード上でキーが押されたままであっても、最後に押されたノート以外の全てのノートは確実にオフになります。 stripnote オブジェクトはノートオフメッセージを遮断するため、ノートオンメッセージのみがこのオブジェクトを通過します。ここでは、最初にノートが演奏されたときだけにキーのナンバーを取得する必要があり、ノートがオフになったときにピッチをトラッキングする必要はありません。

注:このパッチはMIDIキーボードを使用しなくても試せるように作られています。画面上の kslider オブジェクトの鍵盤をクリックすることによって、擬似的にノートを演奏する事ができます。また、Mod.、Vol.、Bend.、Key、Vel.と表示されたナンバーボックスをドラッグすることによって、その他の値を操作することもできます。言うまでもなく、マウスでの操作感は、フィジカルインターフェースであるMIDIキーボードにはやや劣るでしょう。しかし、少なくともパッチをテストしたり、この章で説明されている内容を試してみることは可能です。

・MIDIキーボード(とホイール)を試してみて、MIDIメッセージがMaxで受信されていることを確認して下さい。受信できない場合は、MIDI入力オブジェクトをダブルクリックして適切な入力デバイスを選択して下さい。

sendとreceiveの使用

このパッチには数多くの send receive オブジェクトが使われているため、メッセージの流れを追いながらこのパッチの動作を理解するのは少し難しいかもしれません。これらのオブジェクトは主にパッチコードが複雑に絡み合わないようにするために使用されます。ここでは jit.qt.movie オブジェクトを中心として、パッチ内の様々なオブジェクトと非常に多くのメッセージを送受信するため、sendreceive オブジェクトの使用が特に適していると言えます。 jit.qt.movie オブジェクトの入出力には receive send オブジェクトを使用しているため、パッチ中の他の全てのオブジェクトと遠隔的に通信を行なうことができます。


どんな場所からでも jit.qt.movie と通信することができます

メッセージボックス中のセミコロン( ; )の使い方に慣れていない方のために、セミコロンの使用方法について少し説明します。メッセージボックスの中に、セミコロン、receive オブジェクトの名前を書き入れ、その後にメッセージを入力します。このようにすると、メッセージボックスがトリガされた場合、send オブジェクトにメッセージを送信したときと全く同じ動作をします。下の例を見て下さい。


メッセージボックス中のセミコロンは send オブジェクトと同様な動作をします

それでは read メッセージを jit.qt.movie オブジェクトに送信したときに何が起こっているか、順を追って見ていきましょう。

;movieA read blading.mov;movieA vol 0 と書かれた、赤いメッセージボックスをクリックして下さい。

メッセージボックスをクリックすると、blading.mov というムービーが読み込まれます。 jit.qt.movie はムービーファイルを開く処理を終えると、右アウトレットから read メッセージを送信します。ファイルの読み込みが正常に終了すると、メッセージは read blading.mov 1になり(正常に完了しなかった場合は数値の部分が1以外のものになります)、パッチの左下の薄い紫色の部分にある receive Arightoutlet オブジェクトに送信されます。ここでは、route オブジェクトを使って、アウトレットから送信する必要がある全てのメッセージを検出し、そのメッセージをパッチ内の適切な場所に送信しています。 read メッセージのアーギュメントは、その後、パッチ右下の緑色の部分にある r read オブジェクトへ送信され、 zl ecils 1オブジェクトと sel 1 オブジェクトによってメッセージの最後の数値が 1 かどうかチェックされます。1である場合は、正常にムービーが読み込まれたということを意味しているため、次の処理へ進んで、ムービーのアトリビュートを取得します。


ムービーが正常に読み込まれた場合、framecount、fps、rate、dim アトリビュートを取得します

read メッセージのアーギュメントで残っているのはムービーのファイル名だけです。このファイル名をメッセージボックスに表示させ、再生されているムービーのファイル名がわかるようにしてあります。読み込みが正常に行なわれなかった場合、このメッセージボックスには ファイル名の代わりに failed to read movie というメッセージが表示されるようになっています(delay オブジェクトを使って、このメッセージが確実に、ファイル名より後にメッセージボックスに入力されるようにしています)。

MIDIノートを使ったビデオクリップのトリガ

このパッチではMIDIキーボードで弾かれたノートのピッチのクラスによって、ビデオの再生位置を決めるようにしました(もちろん、MIDIを使用してムービーの再生位置を変更したり、他のムービーを再生したりするやり方は数多くあります。ここで紹介されているのは、たまたま私たちがこのチュートリアルのために選択したやり方というだけのものです。後のチュートリアルでは一つの映像から別の映像に切り替える方法を見ていきます)。そのために、ムービーのトータルのフレーム数(jit.qt.movieオブジェクトの framecount アトリビュート)を調べて 12で割っています。そして、得られたノートのピッチのクラスの値(ノートナンバー % 12)を使って、ムービーの中の12の地点のうちの特定の場所に再生位置を移動します。

ムービー blading.movは1秒のシーンを12個含んだ12秒の映像です。そこで、ここでは各音高のクラスの値によって、この短いムービーのそれぞれのシーンの先頭に再生位置を移動するようにしましょう(もちろんここまで整然とうまくできているのは、最初から計画的に作ってあるためです。しかし、このパッチはムービーの実際のフレーム数(framecount)を使用することによって、どのような長さのムービーでも必ず12個に分割できるように作られています)。


中央のCの上の音高F(5)は、フレーム数75、ムービーの12シーンの中の5番目を指しています

ノートオン・ベロシティの値が toggle をオンにして、metro から jit.qt.movie への bang の送信をスタートさせ、ノートオフ・ベロシティは toggle をオフにします。

・Show/Hide Display Windowと表示された toggle をクリックして、Display ウィンドウを表示して下さい。MIDIキーボード(または kslider オブジェクト)でノートをいくつか演奏し、ムービーの再生位置を様々な場所に移動させてみて下さい。

jit.qt.movie オブジェクトから出力されるマトリックスは send Aleftoutlet オブジェクトに送信され、最終的に receive display オブジェクトで受信されて jit.pwindow に送られます。それでは jit_matrix メッセージは、send Aleftoutlet から、receive display までの間でどのような処理をされているのでしょうか?これらのマトリックスは、実際には、ビデオエフェクト処理のサブパッチへ送られています。しかしそのサブパッチを調べる前に、まずそれらのエフェクト処理をどのようにコントロールしようとしているかについて説明します。

コントロール情報のルーティング

このチュートリアルの始めの方で、MIDIで得られた情報を Jitter のアトリビュートのコントロールに用いるために、0から1までの値に変換する様々な方法について見てきました。このパッチの黄色い部分を見ると、MIDIから得られたコントロールの情報が、5つの send オブジェクト、s pitchs vels bends mods vol に送信されていることがわかります。これらは 5つの 異なった MIDIコントロールソースです。これらのコントロールソースを使って最大8つの映像エフェクトを直列に繋いたものをコントロールしようとしています。エフェクトのリンクはこのようなものになるでしょう。

ムービー -> 再生速度コントロール -> ボリュームコントロール -> 明度コントロール -> 彩度コントロール -> エッジ検出 -> ズームインコントロール ->ピクセレーション -> ズームアウトコントロール -> display ウィンドウ

自由度を最大限にするため、任意のMIDIコントロールソースによって任意のエフェクトをコントロールできるようにしたいと考えました。これを実現するために、まさにこのような目的のために設計された matrixctrl オブジェクトと router オブジェクトの組み合わせを使っています。router オブジェクトは複数のインレットで受信したメッセージを、内部的にルーティングして、指定したアウトレットから送信します。matrixctrl オブジェクト(MSPの matrix~オブジェクトとMaxの router オブジェクトをコントロールするために設計されたもので、このオブジェクト単体ではJitterのマトリックスを操作するのに向きません)は、このルーティングの情報を編集するためのユーザーインターフェースオブジェクトです。パッチの中の青い領域にある matrixctrl オブジェクトに注目して下さい。


5番目の入力(VOL)を2番目の出力(Volume)に割りあてています

matrixctrl はソース(入力元)をグリッドの縦線、デスティネーション(出力先)をグリッドの横線として表示します。そのため、router オブジェクトの5番目のソースインレットに入ったメッセージを2番目のデスティネーションアウトレットから出力したい場合には、グリッド上のその交点をクリックします。この例では、router オブジェクトによって、vol データが Volume エフェクトをコントロールするように設定されています。matrixctrl グリッドの必要な場所をクリックすると、router オブジェクトにメッセージが送信され、router オブジェクトの内部にソースからデスティネーションへの接続が設定されます(もう一度クリックすると赤い点が消え、router 内部の接続も切断されます)。

このプログラムでは、router オブジェクトは patcher effectsサブパッチの中にあります。しかし、これらのオブジェクトが matrixctrl と同じパッチの中にあったとしたら、下の例のような接続になるでしょう。


router はMaxメッセージの"パッチベイ"で、matrixctrl はそのユーザーインターフェースです

パッチのパーツ単位でのルーティングとバイパス

いくつかのビデオエフェクトを使用しない場合(例えばズームやピクセレーションを使用したくない場合もあるでしょう)には、その特定のエフェクトをバイパスする必要があります。effects サブパッチの中では、Ggate オブジェクトと gate オブジェクトを使用してエフェクトのいくつかをバイパスしています。使用するエフェクトと使用しないエフェクトの設定を簡単に行えるように、このパッチには、メインパッチに radiogroup オブジェクトを使ったチェックボックスを置いています。ユーザーがチェックボックスをクリックすると、radiogroupは全ての項目のオン/オフの状態をアウトレットから送信し、その情報を使ってサブパッチの中の Ggate オブジェクトを切り替えることができます。


ズームイン、ピクセレート、ズームアウトのエフェクトは完全にバイパスされます

patcher effects オブジェクトをダブルクリックして、effects サブパッチの内容を見て下さい。


radiogroup オブジェクトの出力を使って、gate オブジェクトと Ggate オブジェクトを切り替えます

サブパッチの中の receive Aleftoutlet オブジェクトはメインパッチの jit.qt.movie から送信された jit_matrix メッセージを受信します。上の例では、Ggateオブジェクトによって、jit_matrix メッセージが p brightness サブパッチをバイパスするように、そして次の Ggate によって p saturation サブパッチを通過するようにルーティングされています。このように、 Ggate オブジェクトは各エフェクトに対するインサート/バイパスの切り替えを行っています。そして radiogroup オブジェクトのチェックボックスは、それらを切り替えるためのユーザーインターフェースを提供しています。このエフェクトのチェインの最後で、マトリックスはようやく send display オブジェクトに渡され、Display ウィンドウに送信されることになります。

このように、メインパッチの中には、コントロールデータのルーティングとエフェクトのルーティングのための2つの独立したコントロールが用意されています。matrixctrl オブジェクトを使って、(1つ以上の)入力ソースからのMIDIデータを、任意の(あるいは複数の)エフェクトにルーティングすることができます。そして radiogroup チェックボックスを使用して、全部のエフェクトの一つ一つについて、インサート/バイパスを決定することができます。

・[effects] サブパッチウィンドウを閉じて下さい。チェックボックスを使用してインサートしたいビデオエフェクトを選択し、matrixctrl を使用してMIDIからの入力ソースをエフェクトに割り当てて下さい。様々な組み合わせで演奏してみて、それぞれのエフェクトにはどのタイプのコントローラーが最も直観的に(そして、キーボードによるパフォーマンスを行なう場合に機能的に)操作できるかを確認して下さい。

ビデオエフェクトのコントロール

このチュートリアルのそれぞれのビデオエフェクトはとてもシンプルなものであるため、その各々については詳しく述べません。ここでは、リアルタイムにビデオエフェクトをコントロールする方法を決定する場合に参考になるような、いくつかの特徴について指摘しておきましょう。

・もう一度 patcher effects オブジェクトをダブルクリックして effects サブパッチウィンドウを開いて下さい。これらのビデオエフェクト用サブパッチの典型的な一例を見るために、p brightnessオブジェクトをダブルクリックして下さい。


0から1までの範囲のデータは、明度をコントロールするために0から2までの範囲にスケーリングされます

このサブパッチでは、jit_matrix メッセージがサブパッチの左インレットから入力され、コントロール用データが右インレットから(0から1までの範囲で)入力されます。コントロール用データは、適切な範囲にスケーリングされ、Jitterオブジェクトのアトリビュートを設定します。そして処理されたマトリックスは次のエフェクトのサブパッチへと出力されます。p saturationp zoomin というサブパッチはほとんど同じ構造を持っています。p zoomout サブパッチもほぼ同じ構造を持っていますが、下の例のように多少の計算処理を含んでいます。


0から1まで直線的な増加をするデータは、1から0.125までの指数関数曲線の値に変換されます

上の例では、入力されるコントロールのデータ(0から1まで)は、2のべき乗を計算するために使用されています。コントロールデータが0の場合は 20= 1になり、コントロールデータが1の場合は2-3= 0.125 となります。このようにして実際のコントロールの値は増減の方向が逆転するように、そして直線ではなく指数関数曲線によって変化するようになっています。

p edges サブパッチでは、ソーベルエッジ検出を行う jit.sobel というオブジェクトを使ってエフェクト処理を行っています。このサブパッチでコントロールしているのは、オリジナルのイメージとエッジ検出の出力イメージをミックスする部分だけです。このため、実際には jit.xfade オブジェクトの xfade パラメータをコントロールしているだけです(チュートリアル8で詳細に解説されています)。

p pixelate サブパッチは画像マトリックスのディメンションのサイズを減らす処理(ダウンサンプリングと呼ばれる処理)を行ないます。全体的にデータが間引かれ、320 x 240の Dispay ウィンドウで見るとイメージの画素が目立つようになるはずです(このピクセレーション処理についてはチュートリアル14で述べています)。このパッチでは、jit.qt.moviedim アトリビュートを取得することによってオリジナルのビデオのディメンションを(最初にムービーを読み込んだ時点で)取得しています。そして、コントロールデータを 0 から0.0625の範囲の係数に変換した値を使って、取り出したディメンションをスケーリングしています。新しくスケーリングされたディメンションのデータは jit.matrixdim アトリビュートを設定するために使用されます。次はその例です。


ダウンサンプリングしたイメージを再びアップサンプリングすると、ピクセレート処理になります

p ratep volumeサブパッチは他のサブパッチとやや異なります。これらのサブパッチの中では、実際にはマトリックス処理を行っていません。ここではメインパッチの jit.qt.movie のアトリビュートを変更しているだけです。下の例は p rate サブパッチの内容です。


計算の結果を、全ての r rateオブジェクトに送り、同時に jit.qt.movieオブジェクトの rate アトリビュートも設定します。

まとめ

MIDIコントローラーを使用したフィジカルインターフェースは、Jitter上でのリアルタイムなビデオのコントロールに適しています。特にビデオと音楽が関連を持っている場合にはよりいっそう適していると言えます。キーボード、ピッチベンドホイール、ボリュームペダルなどの様々なタイプのコントローラでは、それぞれ異なった方法によるコントロール値のマッピングが必要になるでしょう。全てのMIDIチャンネルメッセージのデータは0から127までの範囲の値を取りますが、Jitterのアトリビュートをコントロールする際には、作成しようとするエフェクトに合わせてこのデータを様々な方法で変換する必要があります。このパッチでは、最初に全てのMIDIデータを0から1の範囲の値に変換し、その後、それぞれのビデオエフェクトごとの必要に応じて値の範囲をスケーリングしています。

Jitterのオブジェクトは非常に多くのメッセージを受信するため、多くの場合、目的とするメッセージを構成するためにメッセージボックスを使う必要があります。パッチ中の様々な場所から同じ場所にむけてメッセージを送信しなくてはならない場合、メッセージボックスの遠隔メッセージ送信機能(パッチコードを使用せずにメッセージを送信できる機能。セミコロンの後にrecieveオブジェクトの名前を書くことで利用できます。)を使用することを考えてみるとよいでしょう。これによって、パッチの中でパッチコードがスパゲッティ状になるのを防ぐことができます。

多くの様々なソースからのMaxメッセージを、多くの様々な送信先へ送る必要がある場合、そして、メッセージの目的の送信先へのルーティングを変更する機能を使用したい場合には、Maxメッセージの設定可能な「パッチベイ」として、 router オブジェクトを使うことができます。matrixctrl オブジェクトは、router 内部でのソース(送信元)とデスティネーション(送信先)のパッチング(接続)を設定するためのユーザインターフェースを提供します。このパッチでは、matrixctrl router を使用して、5つのタイプのMIDIコントロールデータのうちの任意のものを、異なった 8つのビデオエフェクトのうちの任意のものと結びつけることを可能にしています。また、 radiogroup オブジェクトを使用して、ビデオエフェクトのインサート/バイパスのスイッチとして機能するチェックボックスのバンクを作っています。