2018年6月20日水曜日

SMPTEタイムコードのデコード(オフライン)

SMPTE Time Codeというレガシーな仕組みをご存知ですか?

映像の再生位置を示す「タイムコード("時間:分:秒:フレーム数"で表現される時間情報)」が,「オーディオ信号」として伝送されるという方式のものです.

SMPTEタイムコードのオーディオデータを生成してダウンロードできるサイトです.まずは,このサイトでオーディオデータを生成して聞いてみましょう.(※音量注意です.聴感上,非常に音が大きく感じられますし,結構不快な音かもしれません.

http://elteesee.pehrhovey.net/


このデータは後で使いますので,Bit-depthを"16-bit signed int"にするのをお忘れなく.

どうでしょうか?「プルルルルルルルルル・・・」という音が聞こえると思います.この音が,実はタイムコードを表しているのです.

例えば,iPhoneでSMPTEタイムコードを再生して,別のiPhoneのマイクロホンでそれを拾い,デコードしている例があります.

http://blog.livedoor.jp/cpiblog00465/archives/52419598.html

このように,音を出力し,それを拾うだけで時間情報の同期ができてしまうのです.

この技術は,現在でも音響だけでなく,照明や映像等が複雑に絡み合うシステムを構築する際によく使われます.例えば,音響は,Pro ToolsのようなDAWでマルチトラック再生し,同時にサウンドカードの別系統からSMPTEタイムコードを再生し出力,それを映像機器や照明機器に入力し,時間を同期して映像の再生や照明演出が進んでいくシステムを構築できます.

ディズニーランドではパレードやアトラクションでの演出の同期に,SMPTEタイムコードによる同期のテクニックが使われています.

https://ggsoku.com/2012/03/projection-mapping/

SMPTEタイムコードの音声信号の波形を拡大してみると,このようになっています.


矩形波のような,正弦波のような波形になっています.本当は,もっとしっかり矩形波になっている筈なんですが,上記ページから入手したものの波形はこんな感じになっています.しかし,実用上問題ありません.

この波形を見ると,幅の長い波と短い波があることがわかります.SMPTEタイムコードでは,幅の短い上下の変化2回で "1" ,幅の長い上下の変化1回で "0" とみなします.


こうして音声波形から0と1を読み取っていくと,二進数列ができます.この二進数列を以下のように読んでいきます.


このデコード処理をMATLABで実装してみたいと思います.(MATLABだと音声ファイルの扱いが簡単なので)

波形のステップ幅の検出は,ステップ時に信号の値が"0"を通過することに着目し,0通過時から次の0通過時までの幅を計測します.0通過は,今回のような矩形波の場合,現在のサンプルと.1つ前のサンプルとの積を求め,その符号を調べ,マイナスになれば0を通過したことがわかります.(プラス x プラスはプラスの値,マイナス x マイナスもプラスの値になりますが,プラス x マイナス,或いはマイナス x プラスはマイナスの値になります.)

Sync wordを基準にして,それが出現したら過去にバッファしたビット列の中から,必要な部分を参照し,タイムコードをデコードしていきます.

ゆくゆくリアルタイムで実装することを見越して,for文の中で1サンプルずつ参照しながらデコードを行う設計になっています.

clear;
s=audioread('smpte.wav');
del=0;%1サンプル前のオーディオデータ
isshort=0;%短いステップ内に入ったことを示すフラグ
count=0;%ステップ内のサンプル数を計測
bitcount=1;%ビットを記録する位置
bitbuf=zeros(16,1);%sync word検出用バッファ
synccode=[1;0;1;1;1;1;1;1;1;1;1;1;1;1;0;0];%sync word
timecode=zeros(1,16*4*2);%検出したビットのバッファ(いつまでもsync wordが検出できない場合に備えてバッファを必要数の2倍にしておく)
%行ベクトルにしているのは、bin2decの引数にする2進数の文字列をint2strによって生成するため
hour=0;
min=0;
sec=0;
frame=0;
for k=1:length(s)
    sgn=sign(s(k)*del);%現在のオーディオデータと1サンプル前のオーディオデータの積の符号
    if (sgn<0) %ステップ内に入った(信号が '0' を通過した)
        if isshort==0 %短いステップ内ではない
            for n=16:-1:2
                bitbuf(n)=bitbuf(n-1);%過去の15ビットをバッファリング
            end
            if count<11 %短いステップであれば現在のビットは '1'(閾値は適当)
                isshort=1;%次にもう一回短いステップがあるはずなのでフラグを '1' にしておく
                bitbuf(1)=1;
            else %ステップが長ければ現在のビットは '0'
                bitbuf(1)=0;
            end
            timecode(bitcount)=bitbuf(1);%ビットのバッファに現在のビットを格納
            bitcount=bitcount+1;%次回の格納先を1ずらす
            if bitcount>16*4*2 %次回の格納先がバッファサイズを超えたら一旦格納先をリセット
                bitcount=1;
            end
        else %2回目の短いステップ検知時は何もしない
            isshort=0;
        end
        if isequal(bitbuf,synccode)==1 %syncwordを検知したら、timecodeにはSMPTE規格のビット列が格納されている筈
            %各値を10進数に変換
            frame=bin2dec(int2str(timecode(4:-1:1)))+10*bin2dec(int2str(timecode(10:-1:9)));
            sec=bin2dec(int2str(timecode(20:-1:17)))+10*bin2dec(int2str(timecode(27:-1:25)));
            min=bin2dec(int2str(timecode(36:-1:33)))+10*bin2dec(int2str(timecode(43:-1:41)));
            hour=bin2dec(int2str(timecode(52:-1:49)))+10*bin2dec(int2str(timecode(58:-1:57)));
            sprintf('%d:%d:%d:%d',hour,min,sec,frame)
            bitcount=1;%バッファの格納先をリセット
        end
        count=0;%ステップ数をリセット
    end
    count=count+1;
    del=s(k);%現在のオーディオデータを保持
end

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を使う時は,非常に重要なテクニックになります.

2018年5月24日木曜日

OpenMusicの基礎 番外編 〜omloopの基礎〜

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


はじめての<脱>音楽 やさしい現代音楽の作曲法」,すでに重版になったようで,ご好評いただいているようです.私が担当したのはほんの一部だけですが,非常に嬉しく思います.

OpenMusicの特徴は,ソースコードを書かなくても良いグラフィカル・プログラミングですが,グラフィカル・プログラミングは見た目の難しさが少なく,直感的にプログラムを作成しても何らかの結果を得やすいという利点がありますが,一方で,プログラムの制御構造が,グラフィカル・プログラミングという名前とは裏腹に,見ただけでは分からないという欠点もあります.(その制御構造の分かりづらさは前回の記事でお分かりいただけたと思います.)なので,込み入ったプログラムを書こうとすると途端に難しくなってきます.今日ご紹介する繰り返し処理もその一つ.パッチの見た目からこの制御構造を理解するのはほぼ不可能だと思います.

プログラミングでよく使うテクニックに,繰り返し処理があります.その名の通り,同じ処理を指定した回数繰り返す処理です.例えば,10000個の整数全部に100を足す等の処理です.正攻法でいけば,10000回同じ処理を書かないといけないように思えますが,繰り返し処理を使えば,一回だけ処理を書いておいて,それを10000回繰り返させる,といった書き方が可能です.この処理はプログラミングの常識的なテクニックなので,何らかのプログラミング言語を学んだことがある人ならご存知のはずです.

OpenMusicでも繰り返し処理を記述することができます.繰り返し処理を行うオブジェクトが"omloop"オブジェクトです.

パッチ内でomloopオブジェクトを出して,ダブルクリックすると,画像の右側のようなウィンドウが出てきます.このウィンドウが,omloopの中身のパッチを作成するウィンドウで,このウィンドウで作った処理が,繰り返し処理されることになります.


"eachTime"と"finally"というオブジェクトが既にあります.この2つのオブジェクトは繰り返し処理に必須のオブジェクトなので,最初から出ています.

omloopの処理がどのように行われるか知るために,このようなパッチを作りました.Eval Boxすると,OM Listenerウィンドウにこのように表示されます."forloop"オブジェクトは,所謂for文を実装するオブジェクトで,第1インレットの値から第2インレットの値まで内部変数の値を1ずつ増やしながら繰り返しを行うオブジェクトです.


前回の記事で,OpenMusicは,パッチの下から上のオブジェクトにデータの要求を行うという制御構造を説明しました.その考え方でこのパッチを見ると,以下のようなことが起きています.重要なのは,eachTimeの使い方です.eachTimeは,ループの各回の開始時点でデータの要求を行い,データが到着すると,ループが終了するまで,次のデータ要求を繰り返します.

① forloopオブジェクトの内部変数は0(第1インレットで設定したので)
② eachTimeオブジェクトがprintオブジェクトに値を要求
③ printオブジェクトはデータを持っていないのでさらに上のテキストボックスにデータを要求
④ テキストボックスは"hello"を出力
⑤ printオブジェクトはOM Listenerウィンドウに"hello"を表示し,アウトレットからも出力
⑥ eachTimeオブジェクトに"hello"が入力されたので,この回は終了.forloopオブジェクトの内部変数が1増える
⑦ ②〜⑥をforloopオブジェクトの内部変数が9になるまで繰り返す
⑧ forloopオブジェクトの内部変数が9になったのでループは終了.finallyオブジェクトがデータ要求を行い,データを受け取るとomloopオブジェクトの処理は終結.(この時,finallyオブジェクトに入力された値が,omloopオブジェクトのアウトレットから出力される

このようになります.この処理の結果が,上の画像のOM Listenerウィンドウの表示です.尚,最後,"finish"が2回表示されているのは,1個目は,omloop内のprintオブジェクトに入力された時点の"finish",2個目は,omloopをEval Boxした結果としての"finish"です.

また,forloopオブジェクトの内部変数は,forloopオブジェクトのアウトレットから整数で出力されます.



値の範囲を変えると,この通り.


また,omloopウィンドウ左上にある,緑色の矢印ボタンをクリックすると,インレットオブジェクトが出てきます.そして,パッチウィンドウのomloopオブジェクトには,インレットが増えています.この操作を繰り返すと,インレットをいくつでも増やすことができます.このようにして,omloopオブジェクトの外からomloopオブジェクトに入力した値を,omloopオブジェクトの処理で使うことができるのです.



この他によく使うループの方法として,listloopがあります.listloopオブジェクトは,インレットに入力されたリストの要素をループ毎に順番に1つずつ出力していくオブジェクトです.


長くなりそうなので今回はここまで.

2018年5月17日木曜日

コンテンポラリーミュージックユニットAffine始めました.

Twitterではちょこちょこ言っていますが,今年の初めから,これまでずっと活動してきたmacaroomに加え,「Affine(アファイン)」というユニットを始めました.macaroomでは主にポップな歌モノをやっていますが,こちらはコンテンポラリーミュージック.完全なる実験音楽です.
macaroomが去年行った"Cage Out"という一連の企画で出会ったSaKi 汐音さん(名前暫定)という作曲家(?)にお誘いいただきまして始めることになりました.始めはこんなにがっつりやるつもりではなかったのですが,以前から興味のあった実験音楽や,本格的なライブ・エレクトロニクスの実践ができると思い,また,相方の常人離れした感性に惹かれ,何か面白いことができるのではないかと思い,今は,このユニットで私のできるだけのことをやってみようという気持ちになっています.

そんなAffineの頭のおかしい相方が,Affineのことを記録するブログを始めました.

http://affinedrawing.blogspot.jp/

ブログを始める際,「私が手間をとってブログをやるのだからお前も同じだけの手間を取れ」という非常に日本人的な発想丸出しの要望が来たので(頭おかしいくせにこういう時だけ日本人根性丸出し),このブログにたまにAffineのことも書いていきます.(複数ブログをやるのはかったるい)

ユニット名「Affine」は,私が提案しました.ユニット名について,この一案だけ出て,他に対案が全く出なかった(主宰者からも出ないという有様)ので,無投票当選となりました.

Affine.数学や工学に詳しい人であれば馴染み深い言葉です.画像処理の基本・アフィン変換のアフィンです.しかし,古い教科書は参考書では,このAffineをアファインと読む例もあり,我々はその読み方を採用することにしました.それについて,深い理由はなく,2音節より3音節の方が良いかなと思っただけです.

Affineとは,非常に基礎的なベクトルの演算だけで幾何学を構築した空間のことです.
多くの場合,幾何学というと,あの直線の長さがどうこう,ここの角度が云々と,その空間にあるものの「形」をベースにして議論がされます.一方Affine幾何学の場合,空間にあるものの形を考えることなく,ベクトルとその操作だけで幾何学の基本的な性質を構築します.逆に言うと,そのような抽象的な幾何学で明らかになった諸性質を実際的な空間で議論し直すのが,いわゆる通常の幾何学と言えるかもしれません.(この理解は数弱の私の理解であり,非常に信憑性が薄いです

最初は,"Orthogonal" というユニット名を考えました.Orthogonalとは直交という意味です.直交とは,ある直線と別の直線が90度に交わっていること.

2つのベクトルが直交している時,その内積が0になることは数学の常識です.ある量とある量が独立して変化する時,それらの量は直交していると言えます.例えば,バスに乗っている時の心拍数と,その人の移動する速さは直交しています.バスが早く走ろうがゆっくり走ろうが,その人は座っているだけであり,運動による心拍数の上下がないからです.しかし,歩きまたは走って移動している時の心拍数と,その人の移動する速さは,直交していない場合が多いでしょう.ゆっくり歩いている時よりも早く走っている時の方が心拍数が上がると考えられ,移動する速さの上昇に応じて心拍数が上がっていきます.このような関係の場合,それらの量は直交ではありません.

直交について,図で描くと,このようになるでしょうか?


上の図は,x軸とy軸が直交している場合です.(0,2)にあった点Pがx軸に平行に移動する場合,どこまで移動してもyの値は変わりません.yの値に関係なく,xの値を変化させ雨事ができるわけです.


しかし,x軸とy軸が直交していない場合,点Pをx軸に平行に移動すると,yの値も変わっていることがわかります.(すごく微妙な図になってしまいましたね・・・

このように,互いに作用せずに変化する量を扱えるという性質が直交した座標系にはあるのです.

ちなみに,ステレオのアナログレコードは,左右チャネルの振動がそれぞれ直角になるようなVの字に刻まれており,これによって,お互いの影響を受けず,2チャネルの振動を1本の針が読み取ることができるのです.


さて,何故ユニット名を直交を意味するOrthogonalにしようと思ったかというと,ユニット開始時点のスタイルとして想像していた,互いに互いのやっていることは気にせず,即興的にパフォーマンスしていくというスタイルが,まさに直交系のイメージに重なったからです.(※最近は互いに無干渉だと表現が発展しないということが分かってきたので,徐々に互いに干渉するようにしています.)

しかし,直交はともかく,Orthogonalは言い慣れないし,変な場所にアクセントがあるので,あんまり語感が気に入らないということで,類似の良い単語は無いかと考え,Affineにしました.

ですから,私個人としては,ユニット名はOrthogonalにしたかったのであり,Affineというユニット名自体には,殆ど意味は込められていません.

今後とも当ブログ・macaroom共々Affineもよろしくお願いいたします.

どんなユニットなのか書くのを忘れていました.長くなるので書きませんが,気になる方は,Affineが企画する最初のイベントにぜひお越しください.


2018年5月2日水曜日

「はじめての<脱>音楽 やさしい現代音楽の作曲法」にて付録記事を掲載しました 〜OpenMusicの基礎 番外編〜

随分久しぶりの投稿になってしまいました.仕事がバタバタし(これは毎年のこと),音楽活動もこれまでのmacaroomに加え,新しい活動も始めました.また,他にもいくつか個人的に引き受けたこともあり,そろそろ何足ものわらじを履くのがキツくなってきました.

そんな中の1つ,この度自由現代社から発売された「はじめての<脱>音楽 やさしい現代音楽の作曲法」において,巻末の付録部分に「OpenMusicの基礎」と題してIRCAMによる作曲支援ソフトウエアOpenMusicの初歩的な使い方を掲載する部分を執筆させていただきました.




OpenMusicは,現代音楽の作曲において多く用いられていながら,日本国内においては紹介される機会も少なく,あまり武器として使っている作曲家は見かけません.しかし,現代音楽史上でも存在感のある作曲家が多く使っていることも事実で,彼らの足跡を辿る良い手がかりにもなり得るソフトウエアです.

しかし,付録として掲載したので,簡単な操作方法の説明と,私が例題として作ったプログラム例を載せるのみにとどまってしまっています.正直な話,あの記事を読んだ結果,OpenMusicの使い方がわかったとして,それを使いこなして創作を行えるかというと,かなり難しいかもしれません.そこで,本ブログで,少しずつではありますが,本付録の補填記事を掲載していきたいと思います.(本記事を読む前に,「はじめての<脱>音楽 やさしい現代音楽の作曲法」を買って読んでくださいね〜

今回は,プログラマであれば一番気になるところ「OpenMusicプログラミングにおける制御構造」です.本来,プログラミング言語や環境を紹介するときは,これを真っ先に説明しなければならないのですが,本書は作曲法を説明する本であり,プログラミングの本ではないので,省略しました.

まず,比較のために,Maxの制御構造も確認してみましょう.今回作ったのは,非常に簡単なプログラム「100に1を足して100+1=101をコンソールに表示するプログラム」です.こんな感じ.


実践的なMaxプログラミングに慣れている方は状況に応じてもっと違った作り方をするかもしれませんが,今回は,制御構造を説明しやすいように画像のように作っています.

Maxのプログラム制御で押さえておきたいのが,

・データが第1インレットに入力されたらアウトレットからデータを出力し,次のオブジェクトに入力される(これがオブジェクトの繋がっている分だけ繰り返される)
・あるオブジェクトからの出力は,右→左の順番でデータが出力される

の2点です.これらを踏まえてこのパッチを見てみると,このような順で処理が行われているということになります.


上記2点の法則に従った順番になっていることを確認してみてください.

Maxはインタラクティブ操作を前提としたイベントドリブンプログラミングになっており,そのため,入力→出力というデータの流れが視覚的にうまく表現されている,非常に優れたプログラミング環境だと思います.

さて,同様の処理をOpenMusicでやると以下のようになります.



このパッチのprintオブジェクトを右クリックして,"Eval Box"をクリックすると,OM Listenerウィンドウに計算結果が表示されるわけです.



この,Eval Boxをクリックした時に,プログラムが実行されるのですが(Maxのインタラクティブなイベントドリブンプログラミングに慣れているとここが分かりづらい),この時,次のようなことが起こります.

・あるオブジェクトがEval Boxされると,そのオブジェクトのインレットに接続されているオブジェクトにデータを要求する
・データを要求されたオブジェクトがデータを持っていればそれを出力する
・データを要求されたオブジェクトがデータを持っていなければ,さらにそのオブジェクトのインレットに接続されているオブジェクトにデータを要求する
・要求の結果,データがインレットに入力されれば,処理してアウトレットから出力
・これをEval Boxしたオブジェクトから上のオブジェクトのつながりの数だけ繰り返す

この箇条書きで分かりましたでしょうか?とても難しいですね.これも,図に処理手順を書くと下のようになります.




Maxとは違い,下から上に要求が伝わり,データが処理されていることに注意してください.

尚,上の図において③と④の順番は,左から右の順でデータが到着しており,Maxとは逆です.この点については,私も現状そこまで詳しくないので,もしかしたら逆かもしれません.しかし,他の処理での挙動を見ていると,どうやら左から右の順でデータが処理されているように思います.

ごく簡単なパッチでのご紹介になりましたが,これがOpenMusicにおけるプログラミングの制御構造になります.このような面倒なことを知らなくても,冒頭紹介した本の付録で紹介した程度のプログラムを作成することは可能です.しかし,omloopや条件分岐等,プログラミングの醍醐味と言える処理を取り入れたパッチを作成しようと思うと,こうした制御構造の理解なしでは自分の意図通りの処理を実装することはかなり困難です.

それではよいアルゴリズム作曲ライフを!!