tn8's SuperCollider site
tdfc

Audio Tutorial 4

4. Multi Channel


(このチュートリアルの殆どのテクストは [02 MultiChannel]から複写したものです)



■4.1 マルチチャンネルでのサウンド出力方法

マルチチャンネルのオーディオを記述する場合は、配列(Array)を利用します。

// 1チャンネル
{ Blip.ar(800,4,0.1) }.play

// 2チャンネル
{ [ Blip.ar(800,4,0.1), WhiteNoise.ar(0.1) ] }.scope

それぞれのチャンネルはSynth.playに送られ、異なるスピーカーから出力されます。 ここでは二つのステレオスピーカーで再生するのが限界ですが、マルチチャンネルをサポートしたサウンドカードを使えば、サウンドカードがサポートしているだけけのチャンネル数で出力することができます。

■4.2 出力プロキシ

すべてのユニット・ジェネレータは一つの出力しか持っていません。この決まりごとにより、マルチチャンネル構造の操作は配列の操作をすることによって、簡単に行うことができます。

マルチチャンネル出力を実行するために、まず、OutputProxyユニット・ジェネレータが作られます。ユニット・ジェネレータはそれぞれの出力を、OutputProxyに入れます。OutputProxyは、マルチチャンネルユニットジェネレータの出力のための、ただの場所(というか容れ物みたいなもの)です。OutputProxyは内部的に作られるので、自分で作る必要はありません。しかしそういうものが存在すると知っておいた方がよいでしょう。(OutputProx.help参照)

// Pan2の出力を見てください

Pan2.ar(PinkNoise.ar(0.1), FSinOsc.kr(3)).dump;

play({ Pan2.ar(PinkNoise.ar(0.1), FSinOsc.kr(1)); });

■4.3 マルチチャンネルでの表現

ユニット・ジェネレータの入力に 配列が与えられた場合は、そのユニット・ジェネレータの複数のコピーの配列が作られます。 それらのユニット・ジェネレータはそれぞれ入力された配列に応じた異なった値を持っています。 これは、マルチチャンネル展開(multichannel expansion)と呼ばれています。

{ Blip.ar(500,8,0.1) }.play // 1チャンネル

// 周波数の入力を配列とした場合、2つのBlipが作られる:
{ Blip.ar([499,600],8,0.1) }.play // 2チャンネル

Blip.ar(500,8,0.1).postln // 1つのユニット・ジェネレータが作られる

Blip.ar([500,601],8,0.1).dump // 2つのユニット・ジェネレータが作られる

■4.4 マルチチャンネル展開の拡大性

マルチチャンネル展開は拡大性を持っています。例えば下の例では、Sawユニット・ジェネレータは配列の入力を持っているので、マルチチャンネル展開により、2つのSawができます。そして、このSawは他のユニット・ジェネレータ = RLPFの入力になっているので、さらに他の配列 = 2つのRLPFが作られるのです。(ちなみに2つのRLPFはひとつのXLineを共有しています。)

(
{
RLPF.ar( //レゾナント・ローパスフィルタを作る
Saw.ar( // ノコギリ波のオシレータを作る
[100,250], // マルチチャンネル展開を引き起こす配列
0.05 // mul
),
XLine.kr(8000,400,5), //8000から400に5秒間かけて変化する
0.05
)
}.play;
)


■4.5 複数の入力による展開

2つ、またはそれ以上の配列がパラメータに与えられた場合は、もっとも多くの要素をもった配列と同じ数のチャンネル数になります。短い配列は包み込まれます。 例えば次の例:

Pulse.ar([400, 500, 600],[0.5, 0.1], 0.2)

は、次のように評価されます:

[ Pulse.ar(400,0.5,0.2), Pulse.ar(500,0.1,0.2), Pulse.ar(600,0.5,0.2) ]

もっとも多くの要素をもった配列は、Pulseの周波数にあたる、[400, 500, 600]ですから、3チャンネル作られます。Pluseのwidthにあたる配列の要素の数は2つしかないので、3番目の配列には0.5が適応されています。また、Pulseの振幅は3つとも0.2が適応されています。

上のSawの例よりも複雑な例を下に紹介します。 この例では、XLineは2つ作られます。ひとつのXLineは8000から500へ、もうひとつのXLineは400から7000へ移り変わります。これら2つのXLineと、2つのSawオシレータは結びついており(英文ではare 'married')、それぞれが2つのRLPFのパラメータになります。つまり、左のチャンネルでは、100HzのSawオシレータに8000 Hzから400 Hzまでのフィルタがかけられ、右のチャンネルでは、250HzのSawオシレータに500 Hz to 7000 Hzまでのフィルタがかけられることになります。

{ RLPF.ar(Saw.ar([100,250],0.05), XLine.kr([8000,500],[400,7000],5), 0.05) }.play;

■4.6 展開から配列を保護する

例えばKlankのような幾つかのユニット・ジェネレータは入力として配列を必要とします。 全ての配列は展開されてしまうので、このような場合には配列を展開から保護してあげなければなりません。そのためにはRefオブジェクトを使用します。Refインスタンスはvalueという名前のひとつのスロットをもったオブジェクトであり、オブジェクトの容れ物として役割を成します。Refをつくる一つの方法は Ref.new(object) ですが、バッククォート`を利用することにより、もっと簡単に書くことができます。バッククォートは単項オペレータで、Ref.new(something)を呼び出すのと等価です。

Klankなどのユニット・ジェネレータの入力に配列を利用する例:

Klank.ar(`[[400,500,600],[1,2,1]], z)

次のように記述した場合は複数のKlankができる:

Klank.ar([ `[[400,500,600],[1,2,1]], `[[700,800,900],[1,2,1]] ], z)

上記の例は次のように評価される:

[ Klank.ar(`[[400,500,600],[1,2,1]], z), Klank.ar(`[[700,800,900],[1,2,1]], z)]

■4.7 Mixを用いたマルチチャンネル展開のダイエット法

Mixユニット・ジェネレータを用いれば、マルチチャンネルの配列を1チャンネルに纏めることができます。

Mix.ar([a, b, c]) // チャンネルの配列

これは次のように評価されます

a + b + c // 1つにミックスされる Mixは + を使うよりも効率的です。何故ならそれは一度に複数の加算を実行することができるからです。しかし、もっと重要な利点は、チャンネルの数が、任意またはランタイムに決定される場合に応じることができることです。

// 3チャンネルのPulseを1つに纏める
{ Mix.ar( Pulse.ar([400, 501, 600], [0.5, 0.1], 0.1) ) }.play

マルチチャンネル展開はMixにより異なった動作をします。Mixは配列(Refにより保護されていないもの)というひとつの入力を持っています。その配列はMixのコピーがつくられないようにします。つまり、配列の全ての要素はひとつのMixオブジェクトでmixされます。一方では、配列がひとつ、またはそれ以上の配列を含む場合は、マルチチャンネル展開は1レベル下で行われます。これはステレオの(2つの要素をもった)配列をmixした結果が、2チャンネルの配列になるのを可能にします。次の例を見て下さい:

Mix.ar( [ [a, b], [c, d], [e, f] ] ) // 3つのステレオのペアの配列を入力とする

これは次のように評価されます:

[ Mix.ar( [a, c, e] ), Mix.ar( [b, d, f] ) ] // ひとつのステレオのペアにmixされる。

下は3つの2チャンネルの構造をmixする例です:

(
{
Mix.ar([
Pan2.ar(Blip.ar(500, 8), FSinOsc.kr(1.0), 0.1),
Pan2.ar(PinkNoise.ar, FSinOsc.kr(1.3), 0.1),
Pan2.ar(FSinOsc.ar(1400), FSinOsc.kr(1.7), 0.1)
])
}.scope
)

現在、配列の配列の配列の上でMixを使うことはできません。下のコードは実行しようとするとエラーがでます。

(
{
Mix.ar([
Pan2.ar(Blip.ar([100,500], 8), FSinOsc.kr(1.0), 0.1)
])
}.scope)


■4.8 もう一つの例

マルチチャンネル展開とMixについてのより複雑な例を示しましょう。 変数 'n'の値をかえことにより、このパッチのボイスの数を変えることができます。 さて、あなたのマシンは何ボイスまで処理できるでしょうか?(注:ボイスの数が増えると処理が増えるので)

(
{
var n;
n = 8; // ボイスの数
Mix.ar( // 全てをステレオ2チャンネルにミックスダウンする
Pan2.ar( // ボイスをステレオに定位する
CombL.ar( // 弦のレゾネータとしてコムフィルターを使う
Dust.ar( // 励起関数としてのランダムなインパルス // Dustをnチャンネルへ展開する配列
// 1は一秒に平均1のインパルスを生成
Array.fill(n, 1),
0.3 // 振幅
),
0.01, // 最大ディレイタイム(秒)
Array.fill(n, {0.004.rand+0.0003}),
// それぞれの'弦'を違ったランダムな長さにする配列
4 // ディケイタイム(秒)
),
Array.fill(n,{1.0.rand2}) // それぞれのボイスに異なった音像定位置を与える
)
)
}.play;
)