チュートリアル 5:
メッセージの順序

イントロダクション

チュートリアルを開いて下さい。

このチュートリアルでは、メッセージの順序に焦点をあててみます。この順序に沿って、メッセージがオブジェクトからオブジェクトへ渡され、オブジェクトがメッセージを生成します。これとあわせて、パッチがどのように実行されているかを確認するために、Max が持つデバッグツールを使用します。

Max パッチでは、多くの場合、すべてのことが一度に起こっているように見えます。実際には、メッセージは特定の順序に従って生成され、実行されます。正しく動作するパッチを作るためには、ものごとが起こる順序や、動作の複雑な並びをコントロールする方法について理解しておく必要があります。

右から左へ、下から上へ

チュートリアルパッチを見て下さい。このファイルには、数多くの小さなパッチがあります。これらを使ってメッセージが従うルールについて学習します。左上のパッチの最も上にある button をクリックして下さい。接続された3つの button オブジェクトがすべて同時に光るように見えます。これは錯覚です。メッセージはパッチケーブルに順番に送られています。

実際の動作でこれを簡単に確認するには、Max のデバッグツールの一部を使用するという方法があります。上の行にあるパッチには、パッチコードの上に数字が書き込まれた小さな赤い円があることに気付いたと思います。これはウォッチポイント(厳密に言えばブレークポイント・ウォッチポイント)
と呼ばれるものです。パッチをデバッグする場合、ウォッチポイントを使って、特定の時点でパッチの実行を停止させることができます。この動作は Max デバッガを有効にすることによって行ないます。Debug メニューから Enable Dbugging を選んでください。デバッグが有効になると、これらのウォッチポイントはパッチの中でメッセージがどのように渡されるかを見る手助けをしてくれます。

最も上の button をクリックして、左側のパッチを見て下さい。すぐにすべての button オブジェクトが光る代わりに、右側のパッチコードが赤く点滅します。加えて、デバッグウィンドウと呼ばれるウィンドウが開きます。ウィンドウを見ると、どのような情報が与えられているかがわかります。このウィンドウは、ウォッチポイントがbang メッセージを捕えたことを報告しています。さらに、どのウォッチポイントで停止したか(この場合は、ウォッチポイント#1になります)、パッチャーの名前、送信と受信を行なったオブジェクトのクラスが何か(この場合は、両方とも button オブジェクトです)を報告します。

Debut メニューから Step を選んで(または、[Ctrl ]/ [Command] + Tを押して)下さい。中央のコードが点滅するのがわかるでしょう。もう一度 Step を選ぶと、左端のコードが点滅します。さらにもう一度 Step を選んでパッチのトレースを終了して下さい。オブジェクトのアウトレットが複数のインレットに接続されている場合、メッセージは「右から左」の順序で送信されます。

しかし、受信するオブジェクトが垂直に(そして、全く同じ水平位置で)重なっている場合にはどうなるでしょうか?デバッグをまだ有効なままにしておき、上の行の中央にあるパッチの最も上の button をクリックして下さい。ウォッチポイントが点滅するので、Debug メニューから Step を選んで下さい。パッチを進行させると、一番下の button が最初にメッセージを受信し、次に中央、その次に一番上が受信します。これで、Max には順序付けの第2のレベルが存在することがわかります。右から左、そして下から上です。

メッセージの順序づけにはもう一つのひねりがあります。そして、これはより多くのメッセージの生成を引き起こすようなメッセージの影響です。3番目のパッチはこの問題点の例を示したものです。最も上の button をクリックして、メッセージの順序をたどって下さい。この一連の button オブジェクトをトレースすると、オブジェクトの次の「分岐」にメッセージを送信する前に、メッセージが1つのメッセージチェインの最も深い位置にまで達することがわかります。デバッグウィンドウが分岐されたそれぞれのメッセージチェインの長さを表示している点に注意して下さい。

これらのことから、Max のメッセージ順序の法則は次のようになります。

1. 右から左、その次に下から上。

2. 深さ優先で接続されたオブジェクトを横断。

右から左、あるいは、下から上の順序の決定は、接続されたオブジェクトの位置で決定され、パッチコードの位置ではない点に注意して下さい。パッチコードはメッセージのルートを決定するものです。

練習として、垂直、水平の両方向に button オブジェクトの配列を持ち、オブジェクトの深さが複数あるような 新しい button オブジェクトのマトリックスを作ってください(Object メニューの Align オブションを使用するとよいでしょう)。コメントボックスを使って、実際にオブジェクトが光ると考えられる順にボックスに番号を付け、その後、パッチをトレースしてみて下さい。

メッセージ順を完全に理解できるようになるまで行なって下さい。

Debug メニューから Disalbe Debugging を選んで、チュートリアルパッチの中の次のパッチを見て下さい。

さらにメッセージ順序について

時として、望むような結果と、パッチの空間的な順序を合わせることが不都合な場合があります。下の行のパッチの中では、左端のパッチはうまく構成されています。これはきれいにレイアウトされていて、左から右へ昇順の数値で並べられたナンバーボックスがあります。値の小さいものから値の大きいものへという順序でメッセージを送信したい場合、これでは間違いです。最も上の button をクリックすると、数値が逆の順序で Max ウィンドウに表示されることがわかります。これは、メッセージボックスが右から左の順で bang メッセージを受信するためです。

次のパッチは、このパッチの修正バージョンです。ここでは、新しいオブジェクト bangbangを使用しています。このオブジェクトはメッセージを受信し、アウトレットから右から左のという順序でbang メッセージを出力します。アウトレットの数は bangbang のアーギュメントによって決まります(このケースでは、3 というアーギュメントがあるため、3つのアウトレットが作られます)。このアウトレットは適切な順序でメッセージボックスに接続されています。最も上の button をクリックすると、Max ウィンドウには意図した通りの順序でメッセージが表示されます。

bangbang のアウトレットが右から左の順序で出力している点に注意して下さい。これは、パッチ自身のメッセージの順序に倣ったものです。複数のアウトレットを持つオブジェクトのほとんどは、このルールに従い、右端のアウトレットから左端のアウトレットへ向かって順に出力が行なわれます。

bangbang オブジェクトを使用すると、メッセージの順序が明確化されます。つまり、bangbang はパッチ上での位置に関係なく、強制的にメッセージを指定された経路に送ります。オブジェクトは、接続されたアウトレットに基づいて、決められた順序でトリガされることがわかっているため、オブジェクトをパッチ内の任意の場所に置くことが可能になります。明確な順序でメッセージを出力するもう一つのオブジェクトは、trigger オブジェクトです。trigger オブジェクトは入力を受けると、そのアーギュメントによって指定された形でメッセージを出力します。アーギュメントでは、出力するメッセージの型をl(リスト)、b(bang)、i(integer:整数)、s(シンボル:テキストメッセージ)、f(float:浮動小数点数)で指定します。さらに、特定の整数、浮動小数点数、シンボルを定数として使うことも可能です。

次のパッチには 90 という整数を持つ2つのメッセージボックスがあります。print オブジェクトに直接接続されているメッセージボックスをクリックすると、Max ウィンドウいは通常の「右から左」の順序でメッセージが表示されます。しかし、trigger オブジェクトに接続されているメッセージボックスをクリックすると、print への出力を左から右の順(逆順)にコントロールできていることがわかります。trigger オブジェクトのアーギュメントが、型 i(integer-整数)になっているため、送信されたメッセージはすべて整数 90 として表示されます。

その右にあるパッチでも整数メッセージ(90)の入力を使用し、メッセージボックスがtrigger オブジェクトに接続されています(このtrigger オブジェクトの名前には、省略形 "t" が使われています)。しかし、ここでは3つの異なったアーギュメントが使われています。メッセージボックスをクリックすると、3つのアウトレットからの出力がそれぞれ異なり、その違いがアーギュメントの違いに対応しているものであることがわかります。

右端のアウトレットは型 i(integer-整数)が指定されているため、そのまま 90 が出力されます。中央のアウトレットは型 f(float-浮動小数点数)が指定されているため、入力されたメッセージは同じ値を持つ浮動小数点数(90.000000)にキャスト(型変換)されて print オブジェクトに送られています。最後に、左端のアウトレットは、型 b(bang)が指定されているため、入力メッセージは受け取りますが、これをbang に変換して出力します。このように、trigger オブジェクトでは、メッセージの順序を明確化することに加え、メッセージの型変換を行なうことができます。

右端のパッチでは、trigger オブジェクトでの定数の使い方を示しています。浮動小数点ナンバーボックスの値を変更すると、trigger オブジェクトは入力された数値を変換しますが、その中には定数として使用されているいくつかのシンボル(テキストメッセージ)が含まれています。また、入力されるメッセージの型にかかわらず、bang アウトレットの出力が bang のままで変化しないということもわかります。

様々な button によるマトリックスを作るだけでなく、trigger や bangbang オブジェクトと併用することによって、望むようなメッセージの順序付けを行なってみて下さい。

ループによるトラブル

チュートリアルの最後のパッチは、ループ状に接続された4つの button オブジェクトで作られています。この中のどれか1つの button オブジェクトをクリックすると、スタックオーバーフロー・エラーによってシステムが停止してしまいます。これはなぜでしょうか?Max が深さ優先でメッセージの順序を決めていたことを思い出して下さい。ループ状のパッチは無限の深さを持つことになるため、正しい分析ができません。ある button が次のbuttonに送信を行ない、次のbuttonがその次のbutton に送信を行ない、その次の button がさらにその次の次の button に送信を行ない、その次の次の button は最初の button に送信を行ない、トリガのサイクルがまた元に戻ってしまいます。スタックオーバーフローが起きてしまった場合、Max はスケジューラを停止させ、それ以上何かが起こらないようにします。パッチに生じている問題点を見つけ、それを修正した(例えば、ループのbutton オブジェクトの中の1つの接続を取り除いた)後、Edit メニューの Resume をクリックすることによって再びパッチを「オン」にすることができます。

結び

正しく機能するパッチを作成するためには、メッセージの順序を決める法則に関する深い理解が必要です。メッセージをやり取りする場合、右から左、下から上、深さ優先という順序付けは暗黙のうちに取り決められている法則です。しかし、bangbang や trigger のようなオブジェクトを使うと、順序付けを明確にすることができます。あらゆる場合において、構造的な「ループ」が生じないように注意を払っておく必要があります。このような「ループ」は文字通り「パッチキラー」です。

参照

bangbang 右から左へ bang を出力します。
trigger 入力された値を多くの場所へ、右から左の順序で送信します。