Data チュートリアル 5:
リスト処理

イントロダクション

このチュートリアルは、大きいテーマである「リスト処理」を扱うため、大きなものになっています。ここでは zl オブジェクトで利用できるモードについて説明します。このオブジェクトはリスト処理の「中央情報センター」のような機能を提供します。また、vexpr オブジェクトを使って、リストに対して数式処理を実行する方法についても説明します。さらに、prob オブジェクトを使って、音楽作成用の確率テーブルを作る方法についても見ていきます。

Max では、リストは、最もパワフルなデータ構造の1つとして利用できます。任意の値の組み合わせをリストとして定義することができ、それをメッセージとして送信したり、オブジェクトによって処理したり、小さなテーブルとして扱ったりすることができます。その多くは、zl オブジェクトによって可能になります。このオブジェクトは、クエリの実行、リストの順序変更、リスト内の任意の要素へのアクセスといった機能を提供してくれます。リスト処理の中にvexpr を入れると、リストを個別の要素に分割せずに、リストの要素に対して数学的な処理を行なうことができます。

prob オブジェクトの使用は、多くのジェネレーティブ(発生的)なプログラムでは不可欠のものです。prob オブジェクトでは、重み付けを伴う確率テーブルを簡単に作ることができ、bang を送信するだけで、期待されるデータを発生させることができます。このチュートリアルでは、基本的なシーケンスアプリケーションのデータを作成する種(seed)としてprob オブジェクトを使用する方法について見てみます。

シーケンシングパッチの実行

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

チュートリアルを眺めてみて下さい。これは典型的なMaxパッチで、ステップシーケンサになっています。パッチを開くと、最初の2個の multislider オブジェクト(A 、B と表示されたもの)は値を供給されますが、第3のmultislider(C と表示されたもの)は空になっています。これらのmultisliderオブジェクトは、その右側にある2つの noteout オブジェクトから外部へ供給される MIDI再生システム用のシーケンスを保持しています。noteout オブジェクトをダブルクリックして、利用可能なシンセサイザを選んで下さい。左上のtoggle をクリックしてmetro をオンにして下さい。すると、シーケンスはAとB という multislider に保持されているデータによって演奏を開始します。C というmultislider をマウスでドラッグし、メロディラインの値を設定して下さい。この結果はコンピュータのシンセサイザを使ってプレイバックされます。GM(General MIDI)互換のシンセサイザを使用している場合には、上の2つのmultislider のシーケンスがドラムとして聞こえ、最もした(C)のシーケンスはピアノによって演奏されるメロディとして聞こえるはずです。これはMIDI チャンネル 10(上の noteout のアーギュメント)がドラムのチャンネルで、他の15個のチャンネルがメロディ楽器を演奏するというGM のルールに従っているためです。ほとんどのシンセサイザはこの動作を設定することができます。Macintosh や Windows のビルトイン・シンセサイザはこのような動作を行ないます。

パッチの右側には、zl オブジェクトを使った数多くの編集ルーチンがあります。これに関してはすぐ後で詳しく見ていきます。multislider A に格納されているシーケンスを回転させたり、multislider B に格納されているシーケンスを逆にしたりすることができます。この編集ルーチンを実行させる button オブジェクトをクリックし、変更が直ちに multislider が保持するデータに適用されることを確認して下さい。

ステップシーケンサの基本的な機能については、よくご存知でしょう。metro は32 の段階を持つ counter を動かします。counter の出力は3つの multislider オブジェクトのための fetch メッセージに変えられます。multislider の出力は2つの異なった makenote/noteout の組み合わせに対して送信されます。2つのドラム用multislider からのデータは MIDI チャンネル 10(ドラム用チャンネル) を割り当てられた noteoutオブジェクトに送信され、メロディのデータは MIDI チャンネル1 (汎用インストゥルメントチャンネル、デフォルトではピアノの音になります)を割り当てられたnoteout オブジェクトに送信されます。

ドラムチャンネル用の2つのシステムは、簡略化されたドラム選択の方法を用いています。上の2つの multislider オブジェクトはそれぞれ3つの値だけを持つように制限されています。この2つのオブジェクトと共に使用されている select オブジェクトは、multislider のデータ(0、1、2)をドラムの楽器(それぞれ、なし、キックドラム/クローズドハイハット、スネアドラム/オープンハイハット)に再マップするために使われています。このように、multislider は範囲全体にわたって重要性を持ち、出力される値は容易に機能することができます。

A と B の multislider オブジェクトのシーケンス全体を 0 にして下さい(オブジェクトの下の方で、オブジェクトを横切るようにマウスをドラッグします)。シーケンスのドラム音がストップします。様々なパターンを加えて、オブジェクトの中の数値がいろいろな音にマップされ、どのように聞こえるかを感じ取ってみて下さい。

prob(probabilities:確率)の使用

ドラムシーケンスの初期設定は、パッチの中の3つのmultislider オブジェクトの下にある generate new patterns(新しいパターンの生成)というセクションで行なわれます。このセクションの動作を見るために、hi-hats という表示のある uzi オブジェクトに接続された button をクリックしてください。A という multislider がかき混ぜられたように変化しますが、中のデータは値 1 を強調する傾向があります(これは、閉じたハイハットに対応します)。これは確率テーブルの設定によって生じるもので、prob オブジェクトによって行なわれています。

確率テーブルの設定は、大きなメッセージボックスによって行なわれています。このメッセージボックスはパッチが開かれたときに loadbang オブジェクトによってトリガされます。この確率テーブルの動作は推移則に基づいています。重み付けの値は、現在の値から他の値へ推移する可能性を決定するために用いられます。したがって、例えば、0 1 2は、0 から 1 へ推移する可能性が 2 であるということを意味します。この 2 は何を意味しているのでしょうか?この値は実際には特に意味を持ちませんが、すべての可能性に対するその推移の確率を定義するだけのものです。結果として、これを推移の重み付けと考えることができます。

ハイハットの確率テーブルのために用いられるメッセージボックスでは、3つの値(0 - 2)の間の組み合わせによって作られる、すべての可能な推移を設定しています。1度に1つの状態しか取ることができないため、確率はその値のステートに基づいて決まります。現在の状態(ステップ)が 0 である場合の確率の計算を見てみましょう。

次のステップ: 0;重み: 3;確率: 3/8(37.5%)
次のステップ: 1;重み: 3;確率: 3/8(37.5%)
次のステップ: 2;重み: 2;確率: 2/8(25.0%)

重みの値の計算を理解するためには、現在のステップで得られる重みの値を合計する必要があります。そして、この値を使って個別の重み付け係数を割ります。この例では、現在のステップが 0 である場合、すべてのケースの重みの合計値は 8 になります。これによって、計算を行なうための分母が与えられます。したがって、ハイハットが鳴らないケースからオープンハイハットに推移する確率は 1/4 になります。全体の 75 % では、クローズハイハットか無音の状態に分かれることになります。

現在のステップが 2(オープンハイハット)の場合を見てみると、2 へ推移する場合(オープンハイハットの繰り返し)の重みが 0 であるのに対し、0 と 1 に推移する場合の重みは4 になっています。これは、prob オブジェクトのテーブルは、オープンハイハットが決して連続しないようにしているということを意味します。現在の値 2 の次に 2 が繰り返される確率は 0 % しかありません。

prob オブジェクトは 32 個の bang メッセージを出力するように設定されたuzi オブジェクトによって動作させられています(したがって 32 個の値を出力します)。しかし、これらが個々の値として送信されるのに対し、multislider の設定は 32個の値によるリストを必要とします。これらのメッセージすべてをどのように結合しているのでしょうか?

zl の使用

zl オブジェクトは、リストを使って作業する場合に重要なオブジェクトです。これは、1つのオブジェクトでほぼ 20 の違ったモード(オブジェクトの第1アーギュメントで設定します)で動作します。これらのモードは、すべて便利なリスト処理機能を実行します。ここで紹介するドラム用のシーケンスジェネレータの場合、zl オブジェクトは group モードで使用され、アーギュメントは 32 になっています。これは、このオブジェクトが 32 個の値を集め、これらを1つのリストにグループ化し、左アウトレットからリストとして出力するということを意味しています。この方法は、データのストリームを定義済みリストにまとめる場合に、迅速で非常に効果的です。そして、そうでなければ煩わしい作業を、1つのオブジェクトによる1つの作業に変えてしまいます。

チュートリアルパッチでは、zl オブジェクトの数多くの使用法について、その中でも特に編集機能について示しています。このモードでは、zl オブジェクトは右インレットでリストを受け取り、左インレットで bang を受信するまでこれを格納します。zl reg オブジェクトは、実質的には int、float、value というオブジェクトと同じものですが、リストの格納用に設計されています。

各編集ルーチンに接続された button をクリックすると、zl reg から他のリスト処理オブジェクトいリストが出力されます。編集ルーチンの内のいくつかでは、リスト操作のためにzlが(別のモードで)使われています。例えば、"rotate A" というルーチンでは、zl を rot モード(アーギュメントは 1 です)で使用し、値を要素1つずつ回転させています。これは、すべての値が1つずつ右に移動し、最後の要素が先頭に移動するものです。"reverse B" ルーチンでは、zl rev を使って、入力されたリストの順序を逆にしています。これに対し、"sort parts of C" では、3 個の zl 処理オブジェクトを組み合わせ、リストの分割(iter)、ソート、そして再構築(group)を行なっています。ほとんどの zl のモードでは、第2アーギュメントを取るか、右インレットでパラメータを変更する数値を受信します。例えば、zl iter オブジェクトはリストをいくつかのサブリストに分割(ここでは 4 つに分割しています)するものですが、右インレットに数値を送信することによって、この分割数を変更することもできます。zl iter オブジェクトに接続されたナンバーボックスの値を 32 (シーケンス全体の長さ)に変更し、button をクリックすると、multislider C に格納されているメロディは低い値から高い値にソートされます。

zl が持っているすべての処理モードを見たい場合には、おそらく zl のヘルプファイルを見るのが最も良い方法でしょう。パッチをアンロックして、zl オブジェクトを選択し、コンテキストメニュー、またはアプリケーションの help メニューから "Open zl help" を選んで下さい。zl には非常に多くのモードがあるため、ヘルプファイルは3つの部分に分かれていますが、ここでは、zl を使って Maxの リストを曲げたり、追ったり、切断したりする方法をすべて見ることができます。

vexpr の使用

リストを使って作業する場合、時として、リストの要素すべてに対して数式を実行したいことがあります。標準のMax の演算オブジェクト(+ など)を使う場合、リストを分割し、処理して、さらに再構築するようになるでしょう。これは、この問題を扱う最も効果的な方法ではありません。これには解決法があります。それは vexpr オブジェクトを使用することです。

その名の示す通り、vexpr オブジェクトは、すでに学んだexpr オブジェクトと非常に良く似ています。違いは、このオブジェクトがリスト処理に特化されているという点です。"transport C" というルーチンの vexpr の使い方を見てみると、おなじみの $i1 という構文を使ってリストの個々の整数値を参照し、それぞれの値に数値1を加えて(または引いて)いることがわかります。したがって、zl reg オブジェクトが 32個の値を持つリスト(もともとは multislider C から送信されたものです)を出力すると、それぞれの要素はインクリメント(増加)、あるいはデクリメント(減少)され、32 個の値を持つリストとして出力されます。

"randomize C" ルーチンは、入力として 2 つのリストを受け取るvexpr の使用法を示しています。ルーチンの右側では、-1 から 1 の範囲に変更された 32 個の乱数によるリストを生成します。(uzi からの bang によって random 3 オブジェクト、- 1 オブジェクトで値が生成され zlgroup に送信されます)。このリストが vexpr の右インレットに入力されます。vexpr の左インレットでは、multislider C から送られた32 個の値を持つリストが受信されます。これは、zl reg に格納されていたものです。vexpr オブジェクトは右インレットからの要素($i2 で参照されます)と左インレットからの要素($i1 で参照されます)の加算を行い、これをリスト全体を通して繰り返します。この処理によって、リストの個々の要素は、別の乱数の要素によって変更され、multislider の内容が僅かにランダマイズされる結果となります。このmultislider の内容に対するランダマイズを何回も行なうことによって、メロディを徐々に新しいパターンにモーフィングすることが可能であるという点に注意して下さい。

結び

このチュートリアルでは、確率テーブルについて学習し、それを使ってmultislider オブジェクトの内容としてデータの「種(seed)」を作成することを学びました。そこから、multislider オブジェクトの内容(リストとして与えられます)をzl オブジェクトや vexpr オブジェクトを使って処理する方法について、いくつか説明しました。リストは、Max 環境における重要なデータ構造であるため、これらのオブジェクトは、あなたのプログラム用ツールキットの一部として頻繁に用いられるものになるでしょう。

参照

prob 重み付けのある乱数のシリーズを作ります。
zl オールインワンのリスト処理オブジェクト。
vexpr expr オブジェクトのベクタバージョン。