2018年6月5日火曜日

OpenMusicの基礎 番外編 〜ワンスモード〜

※この記事は「はじめての<脱>音楽 やさしい現代音楽の作曲法」における私執筆の「OpenMusic」の基礎及び,前回までのOpenMusicの基礎 番外編シリーズをお読みください.

前回はomloopの非常に基礎的な考え方をご紹介しました.少し難しい(と私は感じるの)ですが,慣れてくるとだんだん意図通りの繰り返し制御ができるようになります.ここからもう少しアルゴリズム作曲に活かせるようなomloopの使い方を紹介したいのですが,その前にご紹介しておきたい話題があります.これを知らないと,複雑なプログラムを意図通りに動作させることができません.

まず,いつも引き合いに出しているMaxで例題となる処理を作ってみます.説明のためだけに作る,全く必然性のない処理ですが,こんな処理です.

①乱数 r(0~10) を発生させる
②乱数 r の値を表示する
③r+r を計算する
④r+rの値を表示する

※「乱数 r 」というのは,勿論便宜的に設定した変数であって,MaxやOpenMusicのようなビジュアルプログラミング環境では,実際にはこのような変数を設定して代入することはしません.

乱数 r の値がいくつであっても,必ずrの2倍の値が表示されるはずです.

こんなパッチになります.Maxのrandomオブジェクトは,アーギュメントの値-1が乱数の最大値となることに注意してください.


このパッチの処理手順は図のようになります.順番が左右あちこちに飛んでいて分かりづらいですが,順番をしっかり確認しましょう.


ここで押さえておきたいのは,一回のbangで①〜⑥の全ての処理が一気に行われるということです.randomオブジェクトは,第1インレットにbangが入力されるまで乱数を新たに発生させませんから,このパッチの+オブジェクトで,まさに r+r の計算が行われることになります.

OpenMusicでも同じように作ってみましょう.これで良いでしょうか?Maxの時のように,1回のEvalBoxごとに1回乱数が発生して,その乱数の2倍の値が出力されるでしょうか?

OM+オブジェクトをEval Boxしてみましょう.


"OM >"となっている行がprintオブジェクトに入力された値,"OM =>"となっている行がOM+オブジェクトをEval Boxした処理結果です.ということは,この処理は,乱数が2回発生して,その和を求めているということになります.
これは,OpenMusicの制御構造を思い出すと,納得できると思います.OpenMusicはMaxとは逆に下から上のオブジェクトへデータを要求していく制御構造になっています.これを踏まえると,このパッチはこのような処理手順で処理を実行しています.図に書き込むと行ったり来たり,非常にややこしくなるので箇条書きにしますが,パッチと見比べながら処理手順を追ってみてください.

① OM+オブジェクトがEval Boxされる(ユーザ操作)
② OM+オブジェクトの第1インレットにデータが未到着なので,上のオブジェクトにデータを要求.
③ PRINTオブジェクトは更に上のオブジェクトにデータを要求
④ OM-RANDOMオブジェクトはデータを要求されたので,乱数を生成してアウトレットから出力
⑤ PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力
⑥ 今回はあくまでOM+オブジェクトの第1インレットからの要求なので,OM+オブジェクトの第1インレットにのみ出力する
⑦ OM+オブジェクトの第2インレットにデータが未到着なので,上のオブジェクトにデータを要求.
⑧ PRINTオブジェクトは更に上のオブジェクトにデータを要求
⑨ OM-RANDOMオブジェクトはデータを要求されたので,乱数を生成してアウトレットから出力
(10) PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力
(12) 今回はあくまでOM+オブジェクトの第2インレットからの要求なので,OM+オブジェクトの第2インレットにのみ出力する
(13) 両方のインレットにデータが到着したので和を計算して表示

PRINTオブジェクトのアウトレットから出ている線の数だけ同じ処理が繰り返されているのです.データが到着していないインレットの数だけ要求が発生するので当然です.そしてそのたびに,OM-RANDOMオブジェクトは乱数を生成しているのです.
これは,1つの要求が終わって,次の要求が始まるまでの間に,それまでのオブジェクトの状況が保持されていないために起こります.
だったら保持するようにしようというのが「ワンスモード」です.

OM-RANDOMオブジェクトを選択してキーボードの"1"キーを押すと,OM-RANDOMオブジェクトの左上に"1"というアイコンがオーバーラップ表示されました.これは,OM-RANDOMオブジェクトがワンスモードに入ったことを意味します.


ワンスモードになったオブジェクトは,1回のEval Boxの間,一回要求に答えたら,処理結果を保持しておき,その後新たな要求が来てもその処理結果をアウトレットから出力するだけになります.このパッチをEval Boxするとこうなります.乱数による偶然ではなく,ちゃんと意図通りの動作をしていることを示すために何度かEval Boxしてみます.

OM-RANDOMオブジェクトが2回とも同じ値を出力していて,r+r が計算できていることがわかります.この時の処理手順は以下のようになります.

① OM+オブジェクトがEval Boxされる(ユーザ操作)
② OM+オブジェクトの第1インレットにデータが未到着なので,上のオブジェクトにデータを要求.
③ PRINTオブジェクトは更に上のオブジェクトにデータを要求
④ OM-RANDOMオブジェクトはデータを要求されたので,乱数を生成してアウトレットから出力.ワンスモードなのでこの値は最後まで保持しておく.
⑤ PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力
⑥ 今回はあくまでOM+オブジェクトの第1インレットからの要求なので,OM+オブジェクトの第1インレットにのみ出力する
⑦ OM+オブジェクトの第2インレットにデータが未到着なので,上のオブジェクトにデータを要求.
⑧ PRINTオブジェクトは更に上のオブジェクトにデータを要求
⑨ OM-RANDOMオブジェクトはデータを要求されたが,ワンスモードなので乱数を生成せず, ④で生成した値をアウトレットから出力
(10) PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力
(12) 今回はあくまでOM+オブジェクトの第2インレットからの要求なので,OM+オブジェクトの第2インレットにのみ出力する
(13) 両方のインレットにデータが到着したので和を計算して表示

これで,r+r の値を計算することはできたのですが,OM-RANDOMオブジェクトが2回動作しているのは変わりません.そこで,PRINTオブジェクトをワンスモードにすることで,2回目の要求でOM-RANDOMオブジェクトの動作を省略することができます.

この時の手順は以下のようになります.

① OM+オブジェクトがEval Boxされる(ユーザ操作)
② OM+オブジェクトの第1インレットにデータが未到着なので,上のオブジェクトにデータを要求.
③ PRINTオブジェクトは更に上のオブジェクトにデータを要求
④ OM-RANDOMオブジェクトはデータを要求されたので,乱数を生成してアウトレットから出力.
⑤ PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力.ワンスモードなのでこの値は最後まで保持しておく.
⑥ 今回はあくまでOM+オブジェクトの第1インレットからの要求なので,OM+オブジェクトの第1インレットにのみ出力する
⑦ OM+オブジェクトの第2インレットにデータが未到着なので,上のオブジェクトにデータを要求.
⑧ PRINTオブジェクトは,ワンスモードなのでOM-RANDOMオブジェクトに値を要求せず, ⑤で生成した値をアウトレットから出力
⑨ PRINTオブジェクトは乱数を表示してアウトレットからそのまま出力
(10) 今回はあくまでOM+オブジェクトの第2インレットからの要求なので,OM+オブジェクトの第2インレットにのみ出力する
(11) 両方のインレットにデータが到着したので和を計算して表示

いかがでしょうか?複雑なプログラムを作ろうとすると,ワンスモードを使いこなす必要があります.特にomloopを使う時は,非常に重要なテクニックになります.

0 件のコメント:

コメントを投稿