12. 


複数の部分からなるシンセシス


シンセシスのプロセスを部分に分割することは、モジュラー・デザインとコンポーネントの再利用を促進します。このことが意味するのは、小さく、うまく設計されたタスクを成し遂げる様にSynthDefを作るということには、しばしば〜があるということです。そのようにすることで、複雑なシンセシスのネットワークを構築するためにSynthDefを組み合わせたり、様々な方法で組み替えたりすることが可能になるのです。


(

// ディスクからサウンド・ファイルを読み込む

b = Buffer.read(s, "sounds/a11wlk01.wav");


// モノのサンプル・プレーヤー ... 1チャンネルのみ

SynthDef("aMonoSamplePlayer", { arg bus = 0, bufnum = 0, rateScale = 1;

Out.ar(

bus,

PlayBuf.ar(

1,

bufnum,

BufRateScale.kr(bufnum) * rateScale

)

*

EnvGen.kr(Env.sine(BufDur.kr(bufnum)))

)

}).load(s);

)


(

// SynthDefをテストする ... 動く?(はい、大丈夫。左チャンネルで再生する。)

Synth("aMonoSamplePlayer", [\bus, 0, \bufNum, b.bufnum]);

)



(

// コンポーネントの再利用の非常にシンプルな例 ... 

// \busアーギュメントを使用して、同じSynthDefから作られたシンセを別のチャンネルにアサインする

// この場合には、1チャンネルのサウンド・ファイルを2チャンネルで再生する

// それぞれのチャンネルの再生レートを変えることで効果を明白にする

Synth("aMonoSamplePlayer", [\bus, 0, \bufNum, b.bufnum, \rateScale, 0.99]);

Synth("aMonoSamplePlayer", [\bus, 1, \bufNum, b.bufnum, \rateScale, 1.01])

)


////////////////////////////////////////////////////////////////////////////////////////////////////


どのようにして情報を取得するか


前の例ではBufRateScaleとBufDurというUGenを使って、PlayBufがサウンド・ファイルをプレイするレートと、PlayBufに適用されるエンベロープの長さをコントロールしています。


BufRateScaleはサウンド・ファイルが録音されたときのレートでプレイバックされることを保証します。BufDurはバッファの長さを返します。これら両方のクラスはInfoUGenbaseまたはBufInfoUGenBaseを継承するUGenのファミリーです。


そのようなUGenの完全なリストを表示するためのコードがこれです。


InfoUGenBase.dumpClassSubtree


このコードを実行すると次の様に表示されます。


InfoUGenBase

[

  NumRunningSynths

  NumBuffers

  NumControlBuses

  NumAudioBuses

  NumInputBuses

  NumOutputBuses

  ControlRate

  RadiansPerSample

  SampleDur

  SampleRate

]

InfoUGenBase



BufInfoUGenBase.dumpClassSubtree


このコードを実行すると次の様に表示されます。


BufInfoUGenBase

[

  BufChannels

  BufDur

  BufSamples

  BufFrames

  BufRateScale

  BufSampleRate

]

BufInfoUGenBase



////////////////////////////////////////////////////////////////////////////////////////////////////


実行の順序


もう一度、次の例はどのようにしてシンセをソースとエフェクトのグループに配置するのかを示します。2つのグループは2つのシンセが適切な順序で実行されることを保証します。


(

// エンベロープなしのフィルター ー永遠にとどまる

SynthDef("soundFileFilter", { arg bus = 0, freq = 440, rq = 0.05;

ReplaceOut.ar(

bus,

BPF.ar( // a bandpass filter

In.ar(0, 2),

[freq * 0.99, freq * 1.5],

rq

)

)

}).load(s);

)


// 2つのグループを作成する。1つはソース用、他の1つはエフェクト用

(

~source = Group.head(s);

~effect = Group.tail(s);

)


// シンセをそれぞれ適切なグループの先頭に追加する

// シンセを適切なグループの最後に追加しても同じ結果になる

(

Synth.head(~effect, "soundFileFilter", [\out, 0, \freq, 500.rrand(1000), \rq, 0.04.rrand(0.1)]);

Synth.head(~source, "aMonoSamplePlayer", [\bus, 0, \bufNum, b.bufnum]);

)


////////////////////////////////////////////////////////////////////////////////////////////////////


サンプルをループする


サウンド・ファイルを何度も何度も繰り返し再生するには、PlayBufのloopアーギュメント(コントロール)を使います。


しかし、PlayBufのインスタンスのloopアーギュメントに任せてファイル全体をループする代わりに、正確な繰り返しが起きる様にスケジューリングすることで、より細かくコントロールすることもできます。



////////////////////////////////////////////////////////////////////////////////////////////////////


この例は3つのSynthDefを使用しています。第1のSynthDefはサンプル・プレーヤーで、バッファ全体を永遠にループし続けます。第2のSynthDefはその入力をリング変調します。第3のSynthDefはその入力に対してローパス・フィルターを適用します。


3つのシンセはチェーンを形成します。第1のシンセはソース・シンセです。第2と第3のシンセは、それぞれのソースに対して処理を加えます。つまり、ソースに対して振幅変調を加え、振幅変調を行ったソースに対してローパス・フィルターをかけます。


処理の順序、つまり振幅変調とローパス・フィルターのどちらが最初でどちらが2番目かは任意です。それはどちらの方法でも定義することができます。


(

// サウンド・ファイルを読み込む

b = Buffer.read(s, "sounds/a11wlk01.wav");


// サウンド・ファイル全体をループ再生するサンプル・プレーヤーを定義する

SynthDef("aLoopingSamplePlayer", { arg outBus = 0, bufnum = 0, rateScale = 1, mul = 1;

Out.ar(

outBus,

PlayBuf.ar(

1,

bufnum,

BufRateScale.kr(bufnum) * rateScale + LFNoise1.kr(2.reciprocal, 0.05),

loop: 1 // 停止することなくサウンド・ファイルを繰り返し再生する

)

*

mul

)

}).load(s);


// オーディオ・ソースに振幅変調を適用する

SynthDef("ampMod", { arg inBus = 0, outBus = 0, modFreq = 1;

Out.ar(

outBus,

[In.ar(inBus, 1) * SinOsc.kr(modFreq), In.ar(inBus, 1) * SinOsc.kr(modFreq - 0.02)]

)

}).load(s);


// オーディオ・ソースにローパス・フィルターを適用する

SynthDef("aLowPassFilter", { arg inBus = 0, outBus = 0, freq = 300, freqDev = 50, boost = 1;

Out.ar(

outBus,

RLPF.ar(

In.ar(inBus, 2),

Lag.kr(LFNoise0.kr(1, freqDev, freq), 1),

0.1

)

*

boost

)

}).load(s);

)


// 2つのグループを定義する。1つはソースのためで、他方はエフェクトのため

(

~source = Group.head(s);

~effect = Group.tail(~s);

)


(

// ソース・グループにサンプル・プレーヤーを追加する

Synth.head(

~source, 

"aLoopingSamplePlayer", [\outBus, 3, \bufNum, b.bufnum, \rateScale, 1, \mul, 0.051]);

// エフェクト・グループの先頭に振幅変調シンセを追加する

Synth.head(

~effect,

"ampMod", [\inBus, 3, \outBus, 5, \modFreq, 1]);

// エフェクト・グループの最後にフィルタリングを追加する

Synth.tail(

~effect,

"aLowPassFilter", [\inBus, 5, \outBus, 0, \boost, 5])

)


このシンセシスのネットワークを文字による図で表すと、この様になります。


Group (RootNode, ID 0)

      /\

     /  \

~source  ~effects // ~source~effectsはグループ

 |        |      \

 |        |       \

 synth    synth    synth

  


////////////////////////////////////////////////////////////////////////////////////////////////////


ここでは、シンセとグループの配置は同じです。一部のアーギュメント(コントロール)を変えることでエフェクトの音色が劇的に変わります。


(

~source = Group.head(s);

~effect = Group.tail(~s);

)


(

Synth.head(

~source, 

"aLoopingSamplePlayer", [\outBus, 3, \bufNum, b.bufnum, \rateScale, 1, \mul, 0.051]);

Synth.head(

~effect,

"ampMod", [\inBus, 3, \outBus, 5, \modFreq, 1000]);

Synth.tail(

~effect,

"aLowPassFilter", [\inBus, 5, \outBus, 0, \freq, 500, \freqDev, 200, \boost, 7])

)


////////////////////////////////////////////////////////////////////////////////////////////////////