tn8's SuperCollider site
tdfc

Audio Tutorial 2

2. How to use UGens


■2.1 UGenとは何か。

Ugenはunit generatorを略したものです。

さて、ではユニット・ジェネレータとは何でしょうか。
ユニット・ジェネレータは、音を処理、または生成するオブジェクトです。
ユニット・ジェネレータには多くのクラスがあり、そして、その全てはクラスUGenから導かれるものです。 SCにはたくさんのユニット・ジェネレータがあります。すべてのユニット・ジェネレータクラスの一覧は[UGen_Ref_Sheet]にあります。

SuperColliderフォルダ>Help>Unit Generators>UGen_Ref_Sheet.help

SCの操作的な話になりますが、あるクラス名の上をダブルクリックしてクラスを選択し、コマンド+Hで、そのユニット・ジェネレータのヘルプファイルを参照することができます。 ユニットジェネレータのヘルプを見ているとオシレータ、ノイズ、フィルター、などなど沢山のUGenがあるのが解ります。

たくさんのユニット・ジェネレータをみていくのは大変ですが、例えば、example filesを見ていて、知らないクラスがあれば、そのつどヘルプを参照していくととても勉強になります。 また、ヘルプファイルには実行できるサンプルもついていたりするので、参考にしましょう。。

■2.2 UGenのつくりかた

では、そのUGenをつくってみましょう。

ユニット・ジェネレータは、ユニット・ジェネレータのクラス・オブジェクトに『ar』ま たは『kr』メッセージを送ることによってつくられます。 『ar』メッセージは、オーディオ・レイトで動作するユニット・ジェネレータをつくりま す。
『kr』メッセージは、コントロール・レイトで動作するユニット・ジェネレータをつくま す。
コントロール・レイトユニット・ジェネレータは、低い周波数またはゆっくり変わってい くようなコントロール信号のために使われます。
コントロール・レイトユニット・ジェネレータは、バッファにつき一つのサンプルだけを 生むので、オーディオ・レイトユニット・ジェネレータよりも少ない処理パワーを使 います。

コントロール・レイトのユニット・ジェネレータは、低周波またはゆっくりと変化するコ ントロール信号として用います。コントロール・レイトのユニット・ジェネレータ は、ブロックごとに1サンプルしか発生しないため、オーディオ・レイトのユニット・ ジェネレータよりも処理能力が少なくて済みます。一般的なブロックサイズは64サン プルなので、コントロール・レイトのユニット・ジェネレータは、オーディオ・レイトの ものよりも少ない処理能力だけで済みます。
一般的なブロックサイズは64サンプルなので、理論的には1/64の処理能力で済むことにな りますが、 ブロックサイズはセットアップのオーバーヘッドに依存するので、必ずしも理論通りでは ありません。
しかし、このような処理能力の節約は重要であり、適切に使用する場合にはコントロー ル・レイトのユニット・ジェネレータが役に立ちます。 マシンパワーが日に日にあがっているような世の中ですが(笑)、処理能力を節約するこ とは重要であり、適切な用途に対してはコントロール・レイトのユニット・ジェネレータ を使いましょう。 では、オシレータを作ってみましょう。

SinOsc.ar(800, 0, 0.1).postln; // オーディオ・レイトのサイン波オシレータの作成

SinOsc.kr(8, 0, 0.1).postln; // コントロール・レイトのサイン波オシレータの作成

上述の例では、オシレータが作られただけなので、音はでません。 次はサウンドを生成してみましょう(実際にきこえる音をだしてみましょう)。 サウンドを生成するためには、SynthクラスのUgenGraph関数の中で、ユニット・ジェネ レータを作る必要があります。サウンドの生成をするためにはSynthクラスがとても 重要なのです。

Synth.play({ SinOsc.ar(800, 0, 0.1) });

■2.3Ugenでの算術処理

ユニット・ジェネレータでは算術処理をすることができます。ユニット・ジェネレータになんらかの算術処理を行った結果もやはり、ユニット・ジェネレータになります。 この算術処理は、シグナルそのものを計算するのではなく、ユニット・ジェネレータのネットワークをビルドし、それらはSynthの中で実行され再生されます。

これは理解しなければならない大切なことです。 シンセシス・ネットワーク、換言すれば、シグナル・フロー・グラフは、ユニット・ジェネレータの式を実行することによって作られます。 次の式は、+オペレーションを行うBinaryオペレータUGenのインスタンスを基にして、フロー・グラフを作成します。
Binaryオペレータを直訳すると「2項演算子」で、2つの項を必要とする演算子のことです。例えば、a + b(aとbを足す) やmax(a, b)(aとbの大きい方の値)などという使い方をします。SC2.2.10には36のBinaryオペレータがあります。

さっきの式の話に戻りましょう。下の式ですが、 FSinOscとBrownNoiseというユニット・ジェネレータを使っています。ちなみに、FSinOscは高速な固定周波数のサイン波オシレータであり、BrownNoiseは低域の周波数を強調したノイズ・ジェネレータで、http://www.wowow.co.jp/drama_anime/southpark/episode.htmlには、「ブラウンノイズと呼ばれる人の下腹部の筋肉を弛緩させウンコを漏らさせるといわれる周波数を探し、ついに発見。ブラウンノイズで全世界は大混乱!」と書かれています。

FSinOsc.ar(800, 0.2) + BrownNoise.ar(0.2); //コマンド+Pを押して実行してください。

Synth.play({ FSinOsc.ar(800, 0.2) + BrownNoise.ar(0.2) }); // それを再生します

Synth.scope({ FSinOsc.ar(800, 0.2) + BrownNoise.ar(0.2) }); // それを表示します

Synth.scope({ FSinOsc.ar(800, 0.4) * BrownNoise.ar(0.5) }); // それらをかけ算したものを再生/表示します

■2.4 シグナル・レベル

オーディオを生成するユニット・ジェネレータの殆どの出力レベルは-1から+1の範囲のなかにおさまります。しかしいくつかの例外もあります。COscの出力レベルの範囲は-2から+2ですし、 LFPulseの範囲は0〜+1です。いろいろなユニット・ジェネレータの出力レベルの範囲は、Synthクラスのplotメソッドを使い、実際に表示をさせて確かめることができます。

Synth.plot({ FSinOsc.ar(200) }); // 200Hzのサイン波

Synth.plot({ WhiteNoise.ar }); // ホワイトノイズ

Synth.plot({ BrownNoise.ar }); // ブラウンノイズ

// ピンク・ノイズは-1から+1までの出力範囲を持ちますが、統計的にはそのようになりません。

Synth.plot({ PinkNoise.ar }); // ピンクノイズ 

Synth.plot({ LFPulse.ar(500, 0.3) }); //500Hz,0.3のサイクルをもったパルス波

上のようにオシレータなどのユニット・ジェネレータの出力レベルはアーギュメントとして直接指定することができますが、 フィルタやディレイのようなユニット・ジェネレータの出力レベルは、入力するユニット・ジェネレータのレベルと一定のコントロールの設定に左右されます。

■2.5 MulとAddの入力

たくさんのユニット・ジェネレータはmul(multiplyの略)とaddという入力をもち、これで ユニット・ジェネレータのシグナルの乗算(かけ算)と加算(たし算)をすることができ ます。*オペレータや+オペレータを用いても同じ結果を得ることができますが、mulやadd を用いる方がより効果的です。
また、モジュレーションの特定な望ましい範囲に合うように、コントロールの為ののユ ニット・ジェネレータの値をスケーリングしたりオフセットを加えるために、mulとaddを 用いることが多くあります。

mulのデフォルト値は1、addのデフォルト値0で、デフォルトを使用した場合は、出力を変 化させることはありません。デフォルト値を用いれば乗算と加算は最適化されるので、こ れらを計算する処理の負担がかかりません。

// 200Hzのサイン波(mulとaddはデフォルト)
Synth.plot({ FSinOsc.ar(200) });

// 200Hzのサイン波、mul=0.2(addはデフォルト)
Synth.plot({ FSinOsc.ar(200, 0.2) });

// 200Hzのサイン波、mul=0.2, add=0.2
Synth.plot({ FSinOsc.ar(200, 0.2, 0.2) });

// 200Hzのサイン波、mul=0.5, add=0.5
Synth.plot({ FSinOsc.ar(200, 0.5, 0.5) });

// 200Hzのサイン波、mul=0.5, add=-0.5
Synth.plot({ FSinOsc.ar(200, 0.5, -0.5) });

コントロール・レイトのユニットジェネレータをオーディオ・レイトのユニット・ジェネ レータのmulとaddの入力にすることができます。また、逆にオーディオ・レイトのユニッ ト・ジェネレータをコントロール・レイトのユニットジェネレータのmulとaddの入力にす ることができます。しかしそれはCPUのパワーを無駄に消費することになります。
何故なら、コントロール・レイトのユニットジェネレータはオーディオ・レイトのユニッ ト・ジェネレータよりも低いサンプリングレイトでしか動作しないからです。

■2.6 モジュレーション

ユニット・ジェネレータのシグナル入力は他のユニット・ジェネレータやスカラー、ま たはユニット・ジェネレータやスカラーの配列を繋ぐことができます。 配列を入力に用いることについてはチュートリアルの「 multiple channels」の章で解説 しています。
あるユニット・ジェネレータを他のユニットジェネレータの入力として使用しているサン プルをいくつかここに紹介します。
次の例ではサイン波のオシレータの周波数をLine関数によりモジュレートしています。 つまりはSinOscユニットジェネレータの周波数をLineユニット・ジェネレータでコント ロールしているということです。

(
// シンプルな周波数の連続的変化

Synth.scope({
SinOsc.ar( // サイン波のオシレータをつくる。
Line.kr( // Lineユニット・ジェネレータでSinOscの周波数を変調。
4000, // Lineのはじまりの値
100, // Lineのおわりの値
10 // Line変化にかける時間。秒数で指定。
),
0, // 位相 0
0.1 // 振幅 0.1
)
})
)

Lineは開始値から終了値までリニアな(直線的な)変化をしますが、XLineは指数的な変 化をします。
次の例題は上述の例題をコメントなしで、短く表記したものと、XLineを使ったもので す。
LineとXLineの違いを聞き比べてみましょう。

Synth.scope({ SinOsc.ar(Line.kr(4000,100,2), 0, 0.1) });

Synth.scope({ SinOsc.ar(XLine.kr(4000,100,2), 0, 0.1) });

次は周波数変調にLineではなく、Sin波のオシレータを利用してみます。

(
// LFO変調
Synth.scope({
SinOsc.ar( // サイン波のオシレータをつくる。

SinOsc.kr( // 周波数変調のためのもう一つのサイン波オシレータ。
0.5, // 2秒で一周期のサイン波で変調させます。
0, // 位相 0
300, // mul は 300
700 // add は 700
//この場合のmulとaddの設定では、周波数は-300+700Hzから //+300+700HZの 範囲、つまり、400Hzから1000Hzの範囲で //変化することになります。

),
0, // 位相 0
0.1 // 振幅 0.1
)
})
)

次は時間が経つにつれてモジュレーションスピートが変化するような変調をさせて みましょう。

(
// LFO周波数の連続的変化
Synth.scope({
SinOsc.ar( // サイン波のオシレータをつくる。

SinOsc.kr( // 周波数変調のためのもう一つのサイン波オシレータ。
// さらにもう一つのユニット・ジェネレータXLineをつかって、
// 周波数が指数的に加速していくように周波数変調をします。

XLine.kr( // XLineジェネレータを用いる
0.5, // はじまりの値 0.5Hz
100, // おわりの値 100Hz
30 // 変化にかける時間。30秒。
),
0, // 位相 0
300, // mul は 300
700 // add は 700
// 上述の例と同じくこのmulとaddの設定では、
// 400Hzから1000Hzの範囲で変化することになります。
),
0, // 位相 0
0.1 // 振幅 0.1

)
})
)

さて、プログラムがちょっと長くなってきてしまいました。
上の例のように入れ子状に書かれたプログラムは読みづらく(そもそも書きにくい)なります。
そこで、プログラムを読み書きしやすくするために、変数を使用してみましょう。

(
Synth.scope({
var lfofreq, freq; //まず、この関数で用いる変数を宣言します。

lfofreq = XLine.kr( // XLineジェネレータをつくります。
// 指数的lineジェネレータを作成します。
0.5, // はじまりの値 0.5Hz、
100, // おわりの値 100Hz
30 // 変化にかける時間。30秒。
);

freq = SinOsc.kr( // 周波数変調のためのサイン波オシレータをつくります。
lfofreq, // LFO周波数を変調するためのにXLineジェネレータを用います。
0, // 位相 0
300, // mul は 300
700 // add は 700
);

SinOsc.ar( // サイン波オシレータをつくります。
freq, // 周波数モジュレータ
0, // 位相 0
0.1 // 振幅 0.1

)
})
)