音楽制作の多くの場面で、アクションの繰り返しが必要になります。例えば、「25小節の休止をカウントして、ゴングを連続して4回叩き、そのセクション全体を 3 回繰り返す」などという場合もあるでしょう。プログラミングにおいては、繰り返されるアクションは「ループ」と呼ばれます。これは、コンピュータの動作の概念では、処理が完了し、その後、ストアされたプログラムの先頭の位置に戻り(ループバック)、もう一度アクションの実行を開始すると考えられるためです。ループ処理では、一般的に、繰り返しの前、あるいは後で何らかのチェックを行ない、もう一度実行するかどうかを判断する必要があります。(このチェックがない場合、処理は際限なく続きます)
Max では、イベントが発生した際のサインとして bang メッセージを使うことができます。下の例では、サスティンペダル(コントロールナンバー64)が踏まれるか、中央のC のノート(キーナンバー60)が送信されるごとに、bang が送信されます。
bang は何かが起こったことを示す汎用のインジケータであるため、bang メッセージををカウントするように設計された counterというオブジェクトがあります。 このオブジェクトは、インレットで受信した bang メッセージをカウントし、アウトレットからそのカウント数を出力します。counter では、出力する値の最大値、最小値を設定することができます。また、カウントアップ、カウントダウン、カウントアップとカウントダウンの交互の繰り返し(カウントの往復)の設定を行なうことができます。次の例では、counter は 1 から 6 までカウントし、また 1 に戻ってカウントを始めます。右アウトレットからは、何回最大値(5)に達したかを報告します。
この動作は、counter から連続した数値を送信させたい場合に役に立ちます。例えば、その数値を tableのアドレスとして使用し、table から値を取り出すことができます。また、ループを作成する場合にも役立ちます。ループではある条件を満たした場合を示す固有なイベントが求められるためです。実際に、counter は「最大値に達したときに、それまで最大値に達した回数を右アウトレットから出力し、中央右アウトレットから 1 を出力して最小値に戻る」という独自の条件を内臓し、それに対して反応しますが、他の条件を設定して、特定の結果を引き起こす必要がある場合もあるでしょう。
下の例では、コンピュータのキーボードから r という文字が入力されるたびに、randomに対して bang が送信されます。randomが数値 0 を出力すると、シーケンスが演奏されます。
このケースでは、現象がおきる回数をカウントしてはいません(randomが 0 を選択するまで、文字 r を何回もタイプし続けなければなりません)。単に、ある条件が満たされるまで繰り返しを行なうだけです。
テストした条件が満たされているとき、その結果として、gate が開かれる、処理が開始される、ノートが演奏される、などの別の動作を起こす必要があります。そして、繰り返しが時間処理によって与えられている場合(例えば、metro が 100 ミリ秒ごとに bang を送信しているような場合)、繰り返しは停止されなければなりません。
音楽においては、時間はとても重要な要素であるため、指定された速さで繰り返されるアクションが必要になるでしょう。metro、clocker、tempoオブジェクトは、均一な時間間隔で出力を行なうために使用され、metro の場合は bang を、clockerや tempoの場合は数値を出力します(もちろん、metroの出力を counterに送信すれば、連続した数値を作り出すことも可能です)。
自動的な、時間によって区切られる繰り返しには、少なくとも 1 〜 2 ミリ秒の間隔を置く必要があります。そうでないと、Max はスタックオーバーフローを引き起こします。スタックオーバーフローが起きると、繰り返しが中止されるまで、Max 内部のスケジューラが停止してしまいます。次の2つの例のような接続を行なってはいけません。、これはスタックオーバーフローを生じさせます。
これらのプログラムいはバグがあります!
この例のパッチは、カウントをできる限り速くインクリメント(増加)しようとします。しかし、この方法には2つの欠陥があります。最初の問題点は、ループを停止させる条件がないということです。数値は無限に増加を続けます。2番目の問題点は、それぞれのパッチでオブジェクトの出力を、時間を遅らせることなしに自分自身のトリガインレットに戻していることです。Max は、処理のための時間を十分にあたえられないまま、より多くの処理を行なおうとし続けてしまい、すぐに「処理するべきこと」のスタックがオーバーフローしていることを訴えてきます。
できるだけ速やかにすべての繰り返し処理を完了するループが必要な場合(イベントのシリーズを「同時に」送信したい場合)には、複数のメッセージを送信するように設計されたオブジェクトを使う必要があります。メッセージボックスはカンマで区切られた複数のメッセージを持つことができ、それらすべてを即座に、連続して送信することができます。同じ考え方で、 uzi オブジェクトは、bang メッセージを連続して、できるだけ速く送信するように設計されています。この一連の bang メッセージを counter オブジェクトへ送信して、一連の数値に変換することができます。 uzi 自身も bang メッセージを送信しながら、その数をカウントし、右インレットからカウントを送信するため、可能な限り速く連続した数値を送信するために使用できます。次の例では、16 の異なった MIDI メッセージをできる限り速く送信する 2 つの方法が示されています。
複数のメッセージが速やかに、連続して送信されます
clocker | 一定の間隔で経過時間を報告します。 |
counter | 受信した bang メッセージをカウントし、そのカウント数を出力します |
metro | 一定の間隔でbang を出力します。 |
tempo | メトロノームのテンポで数値を出力します。 |
uzi | 指定された数だけ bang メッセージを送信します。 |