max/msp max8 入門 1
fendoapです。 max/mspについて入門的な記事を箇条書き的にリストアップして書いていこうと思います。
以下は制作したMax for liveなどです。
gumroadでMax for liveをリリースしています。良ければこちらの方から見ることが出来るのでよろしくお願いします。
動画です
パッチウィンドウ
maxのプログラムはパッチと言います。maxの操作画面はパッチウィンドウと言います。
オブジェクト インレット アウトレット
maxはオブジェクトと呼ばれる箱をつなげて様々な処理を書きます。
オブジェクトは画面上の選択から選ぶかダブルクリックするなどすると空白のオブジェクトを作成することが出来ます。作成したいオブジェクトの名前を入力すると任意のオブジェクトを作成できます。
オブジェクトの上は入力をつなぐインレット、下は出力をつなぐアウトレットという部分があります。それぞれのオブジェクトのインレットとアウトレットをつないで処理を書きます。
インレット、アウトレットは複数ある場合があり、左から第一インレット、第二インレットという名前で呼びます。
パッチコード
オブジェクト同士をつなぐ線をパッチコードと呼びます。オブジェクトには主に信号を扱う~チルダオブジェクトと信号以外を扱うオブジェクトの二種類があります。信号を扱うチルダオブジェクトはパッチコードが点線になります。パッチコードによってはチルダオブジェクトとそれ以外で接続できない場合があります。
信号の流れ
基本的には上から下に接続された線を通って信号が流れていきます。
インスペクターウィンドウ
各オブジェクトの詳細設定などはインスペクターウィンドウという右側の部分で行います。
ホット コールド
オブジェクトのインレットにはホット、コールドという概念があります。ホットは値が上から入力されると出力します。一方コールドは値が入力されても値を保持して出力はしません。ホットは赤色、コールドは青になっています。
ヘルプパッチ
オブジェクトを右クリックしてOpen helpを選択するとヘルプを見ることが出来ます。
ヘルプはヘルプパッチというそれ自体がプログラムになっているので実際に触ったりして理解することが出来ます。
bang
オブジェクトと信号の種類についてです。Buttonというオブジェクトはクリックするとbangという信号を出力します。bangは様々なオブジェクトに対しトリガーや処理開始の役割を与える信号です。例えばclick~はbangが入力されるとプチっという短い信号を出力します。
オブジェクト アーギュメント
オブジェクトの一番左はオブジェクト名を書きます。それからスペースをあけて様々な数値やメッセージを書いて初期値や設定を書くことが出来ます。これをアーギュメントと言います。
メッセージボックス
メッセージボックスは数値やテキストなどを扱う事の出来るオブジェクトです。それ自体がボタンになっていてクリックすると書かれた内容を出力します。
基本的な四則演算
maxでは基本的な四則演算のオブジェクトがあります。このように四則演算を行うことが出来ます。
その他の演算
その他にも剰余演算など様々な演算を行うオブジェクトがあります。
t b i 順番の指定
maxではホット、コールドという概念がありコールドでは値が出力されません。コールドで値を出力するにはトリガー(略してt)のオブジェクトを利用します。トリガーは値が入力されると指定したbangや値を右から順に出力します。例えばt b iとするとイント(整数)→bangの順に値が右から出力されます。
処理の順番を正確に行いたい場合やコールドでも値を出力したい時に利用します。
loadbang loadmess closebang
パッチが開かれたときやパッチが閉じた時にbangを出力したりするオブジェクトです。初期値の設定などに使います。
無限ループ
maxでは出力を入力につなぐと無限ループになりエラーになる場合があります。スタックオーバーフローとは実行できる回数以上の実行要求があり処理が追い付かない状態です。
このようにディレイを使いわずかにbangを遅らせると無限ループでもスタックオーバーフローにならずに動作しますが無限ループは不具合の原因になる可能性があります。
Uzi
Uziは一度に大量のbangを出力したい場合に使えます。またuziの一番右のアウトレットは何番目かの値が出力されるのでzl.groupと組み合わせると1~100の並んだ数字の配列を作成できます。
metro 一定間隔でbangを出力
metroオブジェクトを使うと一定間隔でbangを出力できます。これをつかい一定間隔の処理を行うことが出来ます。
2につづく
ここから下の話は一旦飛ばしてOK
シグナルベクターサイズ サンプリングレート
maxで簡単なタイマーのパッチを作るところから話を始めたいと思います。
まずmspオブジェクトを使って簡単な時間をカウントするパッチを作ります。時間は一定の値が増えていくことで確認できます。
例えば1秒間に値が1ずつ増えていくと秒を測ることが出来ます。+=~オブジェクトは値をどんどん足していくオブジェクトです。
これを使って1秒間に値が1ずつ増えるようにするためにサンプリングレートというのを考えます。
サンプリングレートとは1秒間にどれくらいの粒で音をとらえるのかを表したものです。例えば48000Hzなら1秒間を48000個の粒でとらえるという風な感じです。
1/48000ずつ値を増やしていくと1秒後には48000/48000=1となりちょうど一秒間に値が1ずつ増えるようになります。
この+=~ を別のオブジェクトで入れ替えてみようと思います。
+=~とは現在の値に値を足して新しい値とするという操作です。
現在の値を保持して値と足せば同じことが出来そうです。
maxでは無限ループになってしまうのでアウトレットとインレットをつなぐとエラーが起きます。
そこでtapin~ tapout~を使って信号をループしてつないでみます。しかし結果を見ると思ったように値が増えていきません。なぜでしょう。
dawやmaxでは信号はある一定時間間隔で区切りながら計算されます。これをシグナルベクターサイズ、バッファサイズと呼びます。
tapin~ tapoutも同じように一定間隔で区切りながら処理されます。なのでtapout~を0にした場合でもバッファサイズ分のディレイが発生します。これを確認してみます。
信号が何サンプル遅れているか確認するためにノコギリ波のphasor~を使います。phasor~を1Hzにしてサンプルレート倍したものを使うと信号が何サンプル遅れているか確かめることが出来ます。
phasor 1Hzを48000倍したものを測りたい部分に入力します。出てきた信号とそのままの信号を引き算します。
信号が1サンプルずれると値が1サンプルずれるので引き算すればその差がそのまま何サンプルずれているかという値になります。
これは今256サンプルずれているという事を示しています。これはシグナルベクターサイズと同じ値です。つまりtapout~が0の場合でもシグナルベクターサイズ分遅延があるという事です。
試しにdelay~というオブジェクトを使って256サンプル分信号を遅らせてみると差が0になります。
つまり信号が256サンプル=シグナルベクターサイズ分遅れていたという事が分かります。
このパッチに戻るとなぜ表示がゆっくりになるのかが分かります。これはフィードバックディレイのようになってしまっているからです。
本当は1サンプル分ずつ値が増えてほしいのにシグナルベクターサンプル=256ずつになっているのでゆっくりになっています。
これを修正するためには値の増え方をシグナルベクターに合わせた増え方にする必要があります。例えば1サンプルで1増える場合、256サンプルでは値は256増えます。
つまり値をシグナルベクターサイズ分掛ける必要があります。シグナルベクターサイズはadstatusというオブジェクトで取得できますので取得した値を用いて、シグナルベクターサイズ倍にします。
これでうまくいくかどうか確かめます。clockerというオブジェクトは時間を測ることが出来ます。ckockerはmsなので/1000すると秒になります。これを使ってうまくいっているか値を比較すると同じような値になりました。
これは常にそういう遅延があるという事ではなく最小ディレイタイムはシグナルベクターサイズであるという事を意味しています。
例えば10ms=480sampleにしてみるとちゃんと480サンプルディレイされていることが分かります。
サンプリングレート、シグナルベクターサイズによる違いはこのような場合にあります。
phasor ノコギリ波
先ほど時間は一定の値が増えていくとという話をしました。一定の値が増えていく波形にノコギリ波というものがあります。
一定の値で増えていくものをグラフにすると直線になります。時計のようにあるところからまたリセットして0から数えるようにすると波形はのこぎりのような形になります。
のこぎり波を作ってタイマーを作ってみます。ここで1時間を一番大きな区切りとします。周期を遅くするより早くすることが簡単なので一番遅い周期を選択します。
周波数というものを用います。周波数とは繰り返される回数の事です。周波数をヘルツで表します。1ヘルツは1秒間に1回繰り返すことと定義されています。
$$
Hz = \frac{1}{\text{秒}}
$$
ここで1時間は3600秒です。3600秒で1回なのでヘルツは
$$
Hz = \frac{1}{\text{3600}}
$$
となります。
のこぎり波を使って以下のようなパッチを作成します。
@phaseoffset 0. の部分はアトリビュートと言います。さまざまな設定を行うときに書きます。これは初期位相を決定しています。resetというメッセージを送ると0から波形がスタートします。
phasor~はのこぎり波を出力するオブジェクトです。今1時間に1回波形が繰り返すように設定されています。なので3600倍すると値は秒になります。
0~3600まで1時間かけて繰り返します。resetを送ると0からスタートします。
今、値は0~3600までカウントしていきます。これを0~1の繰り返しにするにはどうすればいいでしょうか。ここで使うのがmodulo~です。
modulo~は入力を特定の値で割った余りを出力します。これを剰余演算と言います。
例えばmodulo~ 1 であれば1で割った余りになります。これを使うと0~1の値の繰り返しを作ることが出来ます。そしてそれは再びノコギリ波となります。
## 少し脱線してダイアルを使って簡単な描画を作るとこんな感じのタイマーが出来ました。##
JSUIなどを使う場合もありますが、標準オブジェクトの組み合わせでも描画は作れたりします。
bangの取り出し
話をもどしてここからbangを取り出すことを考えます。のこぎり波が0になる瞬間を検知します。このためにdelta~というオブジェクトを使います。
のこぎり波が1→0になる瞬間は他の場合と違い大きな落差があります。
delta~は前の入力との変化を出力するオブジェクトです。のこぎり波が1→0になる瞬間は変化が大きく-1となるのでその部分がとげのようになります。
この部分を検出するため<~オブジェクトを使います。<~ -0.5は条件に適合するときは1それ以外は0を出力します。この場合とげになった時に1それ以外は0となります。
次にedge~というオブジェクトで信号とbangの変換を行います。edge~は0→0以外 0以外→0の時を検出してbangを出力します。この場合edge~の左0→0以外の場合を使います。
ほぼ同じなのでどちらを使っても良いですが右の場合は1サンプル遅れます。 これを用いるとのこぎり波が0になった時にbangが出力されます。
BPMに対応させる
このパッチをよく見ると3600で割って3600を掛けているのでこの部分は省略しても結果は同じになります。
そこで一旦この部分を省略して整理します。
ここでbangをオンオフするためにトグルを追加しました。
またt bというのはトリガーbangの略でトグルを操作するたびにphasor~がリセットされるようになります。
このパッチではbangは周波数に対応しています。1Hzなら1秒間に1回bangされ2Hzなら2回、3Hzなら3回bangされます。
このbangをBPMに応じたタイミングで出力するように変更します。
BPMは BPM = Beat per minute で1分当たりの4分音符の数を表します。
1分当たりなので60で割ると1秒あたりになります。
1秒当たり何回というのは周波数と同じなのでBPM/60すれば周波数になります。このような感じです。例えばBPM:120の時 周波数は2Hzとなります。
これでBPMに応じてbangを出力します。
つづき
Max for Live
max/mspによる制作
pure dataによる制作