見出し画像

12.SupuerColliderのバスとエフェクト

今回は、SynthDefの出力をバスに送ってエフェクトをかけた状態の音源をPbindでシーケンスする、ということについて書きます。
初めて扱うクラスがたくさん出てきます。

まず、題材として下記のようなSynthDefとPbindを用意しました。
(これはまだエフェクトを通していない例です。このシーケンスにエフェクトを通します。)

(
SynthDef(\tone0, {
	arg freq=220, gate=1;
	var sig, env;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(0, sig * env);
}).add;
)
(
~pb = Pbind(
	\instrument, \tone0,
	\midinote, Pseq([38, 36, 38, 45, 50, 45, 24, 36], inf),
	\dur, 0.5,
	\sustain, 0.1
);
)
~pb.play(TempoClock(180/60));

少し見慣れない部分がありますので簡単に解説します。
SynthDefのほうは外から(Pbindから)シーケンスさせたいのでピッチとゲート(freqとgate)をarg(アーギュメント)に登録しています。
エンベロープはasrを採用しました。adsrのディケイの無いものです。
Pulse.arのピッチについては、ステレオ・パンニングの回で紹介した方法で左右のピッチに差をもたせています。。
[freq, freq*2]
このように書いてますので、例えばピッチが440のとき[440, 880]となって右チャンネルでは左チャンネルのオクターブ上が鳴ります。

Pbindのほうは、いつもならば
Pbind(音階や各パラメータ).play;
とするところなのですが、Pbindをそのままplayせずに一度変数に入れて、変数をplayしました。
リバーブ付きでシーケンスする場合、そのほうが都合がいいので。
~(チルダ)付きの変数の作り方は前回紹介しましたので、早速使ってみました。
pbはPbindの略のつもりです。


BUS


ではバスに送ってエフェクトをかける作業を始めます。
SynthDefの出力をバスに送りたいので、エフェクト用のバスを作ります。

~rvbBus = Bus.audio(s, 2);

これでOKです。簡単。
Bus.audio(s, 何チャンネルのバスか)
これでバスが作成されるので、作成されたバスをそのまま変数(空箱)に入れました。
このバスにオーディオ信号を送ることでリバーブをかけたいので、リバーブバスの略のつもりで変数名を~rvbBusにしています。

では、先ほどのSynthDefを少し改造します。

(
SynthDef(\tone1, {
	arg freq=220, gate=1;
	var sig, env;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(~rvbBus, sig * env);
}).add;
)

題材ではSynthDefの名前がtone0でしたがtone1に変更しました。
そして、Out.arの出力先を0から~rvbBusに変更しました。

これで、tone1の音は~rvbBusに送られます。
では送られた音を受けるには、、音を受ける用のSynthDefを作ります。
イメージ的には下図のような感じです。

図の右側のSynthDefの役割としては
・Pulse.arの出力を受け取って(Inというクラスを使用)
・リバーブ(FreeVerbというクラスを使用)をかけて出力する
のふたつです。
では実際に右側のSynthDefを書きます。

(
SynthDef(\reverb, {
	var eff, sig;
	sig = In.ar(~rvbBus, 2);
	eff = FreeVerb.ar(sig, 0.5, 0.6, 0.95);
	Out.ar(0, eff);
}).add;
)

In.arは、バスの信号を入力するだけの機能です。
In.ar(どのバスか, チャンネル数)
という使い方で、この場合tone1のSynthDefで出力した~rvbBusからの信号を受け取ります。sigという変数に入れています。

FreeVerb.arはリバーブです。
使い方はRLPF.ar(レゾナンス付きローパスフィルター)やPan2.ar(2chパンニング)などと同じで、
FreeVerb.ar(エフェクトする信号, 各パラメータ)
という使い方です。

そして最終的なアウトプットは、いつものように0です。
ステレオ信号なので(0を指定しておけば)0と1からアウトプットされます。

Inというクラスが少し特殊なので面食らってしまうかもしれませんが、下記のようにSaw.arだとしたら見慣れていますよね。
(
SynthDef(\reverb, {
var eff, sig;
sig = Saw.ar(440, 0.3);
eff = FreeVerb.ar(sig, 1.0, 0.6, 0.95);
Out.ar(0, eff);
}).add;
)
このSaw.arの代わりに~rvbBusからの入力信号を使いたいためIn.arを使っているのが先ほどのSynthDefです。

Pulse.arが鳴るSynthDef(\tone1)と、
その信号を受けてリバーブ処理するSynthDef(\reverb)
が揃いました。
\tone1をシーケンスすればリバーブ付きの音色で鳴るのですが、Pbindのほうにも一手間必要です。

Pfx


通常だと
Pbind(音階や各パラメータ).play;
とすることでシーケンス再生しますが、、エフェクト付きでシーケンスする場合Pfxというパターンを使います。

Pfx(ここにPbind(), \reverb).play;

↑こんなフォーマットで使います。\reverbはエフェクト側のSynthDefの名前です。

ここで一番最初に「題材」として紹介したPbindを振り返ります。
※\instrumentを\tone0から\tone1に変更しています。


(
~pb = Pbind(
\instrument, \tone1,
\midinote, Pseq([38, 36, 38, 45, 50, 45, 24, 36], inf),
\dur, 0.5,
\sustain, 0.1
);
)

この~pbをエフェクト付きでシーケンスさせたいので、先ほどのフォーマットにあてはめると
Pfx(~pb, \reverb).play;
こうなります。

では改めて、必要なコードをまとめます。
下記を順に実行すると、エフェクト付きでシーケンスされます。

バスを作成

~rvbBus = Bus.audio(s, 2);

音源をリバーブバスに送る

(
SynthDef(\tone1, {
	arg freq=220, gate=1;
	var sig, env;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(~rvbBus, sig * env);
}).add;
)

リバーブバスから信号を受けるSynthDef

(
SynthDef(\reverb, {
	var eff, sig;
	sig = In.ar(~rvbBus, 2);
	eff = FreeVerb.ar(sig, 0.5, 0.6, 0.95);
	Out.ar(0, eff);
}).add;
)

Pbind

(
~pb = Pbind(
	\instrument, \tone1,
	\midinote, Pseq([38, 36, 38, 45, 50, 45, 24, 36], inf),
	\dur, 0.5,
	\sustain, 0.1
)
)

Pfxで再生(テンポ180)

Pfx(~pb, \reverb).play(TempoClock(180/60));


FreeVerb.arのパラメータは下記のとおりですので、数値を変えていろいろと試してみてください。
※一度シーケンスを止めてパラメータ変更して再度シーケンスを走らせる必要があります。
※\tone1のSynthDefはシーケンスを走らせながらパラメータを変えることができます。

ひとつ目は、処理する信号です。
FreeVerb.ar(sig,

ふたつ目は、dry/wetのミックスバランス。0がdryで1がwetです。
FreeVerb.ar(sig, 0.5,

みっつ目は、ルームサイズ。0〜1です。
FreeVerb.ar(sig, 0.5, 0.6,

よっつ目は、高域のダンプ(高域をカットする)、0〜1で1に近いほどカットです。
FreeVerb.ar(sig, 0.5, 0.6, 0.95)


FreeVerb2


SC3のリバーブにはFreeVerbのほかにGVerbやFreeVerb2があります。
FreeVerb2は左右のチャンネルが完全独立したリバーブのようで、使い方に少し工夫が必要なので書いておきます。

FreeVerb2.arのパラメータをcommand+dで調べると、まずin, in2と書いています。(そのあとのパラメータはFreeVerbと同じです。)
つまりin(左チャンネル、つまりoutput0)と、in2(右チャンネル、つまりoutput1)を別々に設定しないといけないです。

sigのアウトプット[0, 1]からoutput0だけの出力を取り出すには
sig[0]
と書けばOKです。
また、sigのアウトプット[0, 1]からoutput1だけの出力を取り出すには
sig[1]
と書けばOK。

そういうわけで、FreeVerb2を使う場合は下記のように書きます。

(
SynthDef(\reverb, {
	var eff, sig;
	sig = In.ar(~rvbBus, 2);
	eff = FreeVerb2.ar(sig[0], sig[1], 0.5, 0.6, 0.95);
	Out.ar(0, eff);
}).add;
)

FreeVerbとは違うリバーブの空間を感じられます。


センド


FreeVerbにせよFreeVerb2にせよ、dry/wetのバランスを\reverbのSynthDef側で設定するのはちょっと不便、と感じる人がいるかもしれません。
というのも、\reverb側ではwet100%にしておいて、\tone1側で送りのレベルを操作する方法のほうが通常DAWで使う方法に近いですから。
また、例えば音源のSynthDefが複数ある場合などは便利、ということもあります。
使い方は人それぞれなのでどちらが正解ということは無いですが、送りレベルを操作できる方法を書いておきます。

(
SynthDef(\tone1, {
	arg freq=220, gate=1;
	var sig, env, aux=0.5;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = SinOsc.ar([freq, freq*2]);
	Out.ar(~rvbBus, sig * env * aux);
	Out.ar(0, sig * env);
}).add;
)

このようにOut.arを2個使います。
2個目のoutputは0で、これはドライな音がそのまま出力されます。
もうひとつのoutputは~rvbBusで、このレベルを操作することでリバーブの深さを操作できます。
auxという変数を使って~rvbBusに送っているsigのレベルを操作できるようにしています。
※もしargに登録すれば、リバーブへの送りレベルをPbindからも操作でき便利です。


ディレイ


ディレイについてもリバーブと同じ方法で使うことができますので、例としてコードを書いておきます。

SC3にはCombやAllpassといったディレイが用意されています。
Combを例にとると、CombC, CombL, CombNという3種類がありますが、この3つについては処理負荷の違い、ということのようです。
CombCは処理負荷が高い代わりにきめ細かく、CombL → CombN の順に処理負荷は軽くなります。使用する場合は実際にCombC/L/Nを聴き比べて決めるのがよいと思います。
ここではCombCを使いました。

~dlyBus = Bus.audio(s, 2);
(
SynthDef(\tone2, {
	arg freq=220, env, gate=1;
	var sig, aux=0.4;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(~dlyBus, sig * env * aux);
	Out.ar(0, sig * env);
}).add;
)
(
SynthDef(\delay, {
	var eff, sig;
	sig = In.ar(~dlyBus, 2);
	eff = CombC.ar(sig, 0.25, 0.25, 2.0);
	Out.ar(0, eff);
}).add;
)
(
~pb = Pbind(
	\instrument, \tone2,
	\midinote, Pseq([38, 36, 38, 45, 50, 45, 24, 36], inf),
	\dur, 0.5,
	\sustain, 0.1
)
)
Pfx(~pb, \delay).play(TempoClock(40/60));

ディレイの効果がわかりやすいように、テンポを遅くしています。

なお、SC3にはDelayC, DelayL, DelayNというディレイもありますが、こちらはフィードバックが無く音声信号を単に遅らせるものです。いわゆる「ディレイエフェクト」と聞いて想像する効果はCombのほうだと思います。


組み合わせ


今回はリバーブとディレイを紹介したのですが、用意されたエフェクトをそのまま使うのではなく、いろいろと組み合わせたりエディットすることも可能です。
例えば下記のような感じでいくつかのエフェクトを直列につなぐだけでも面白い効果が得られます。
\delayのSynthDefを改造しましたので、これを実行したあとPfxを再生してみると確認できます。

(
SynthDef(\delay, {
	var eff, sig;
	sig = In.ar(~dlyBus, 2);
	eff = CombC.ar(sig, 0.25, 0.25, 2.0);
	eff = RLPF.ar(eff, 2500, 0.2);
	eff = DelayC.ar(eff, 0.15, 0.15);
	eff = FreeVerb.ar(eff, 0.7, 0.7, 0.95);
	Out.ar(0, eff);
}).add;
)

まずCombCを通した音にRLPF(ローパスフィルター)をかけました。
そしてDelayCをプリディレイ的に使用した後リバーブをかけています。

このほか何でも、エンベロープを使うこともできますし、(次回詳しく扱いますが)特定のパラメータをモジュレーションすることも可能です!


バスのナンバー


ステレオの回で書きましたが、オーディオインターフェイスが持っているアウト数以降のoutput先は、すべてバスとして使えます。全部で1024のバスを使うことができます。

16ch出力のオーディオインターフェイスを使っている方は、
output0 ~ output15は、リアルな16個のアウトプットで
output16以降は仮想アウトプットなのでバスとして使えます。

2ch出力のオーディオインターフェイスやPCの標準出力でSC3を使っている方は、
output0 ~ output1は、リアルな2個のアウトプットで
output2以降は仮想アウトプットなのでバスとして使えます。

サーバをリブートした直後に下記のコードを実行してみると、
~rvbBus = Bus.audio(s, 2);
~dlyBus = Bus.audio(s, 2);

Post windowに下記のように表示されますが
-> Bus(audio, 2, 2, localhost)
-> Bus(audio, 4, 2, localhost)

これは、
オーディオバス、output2から2ch分(つまりoutput2と3)
オーディオバス、output4から2ch分(つまりoutput4と5)
という意味です。
Bus.audio(s, 2)とすることで、空いている仮想outputに(若いナンバーから順に)バスが割り当てられているということです。

豆知識として、このバスの割り当てを任意のoutputにすることもできます。
例えば下記のように、直接outputナンバーを書いてあげるだけです。

(
SynthDef(\tone2, {
	arg freq=220, env, gate=1;
	var sig, aux=0.4;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(100, sig * env * aux);
	Out.ar(0, sig * env);
}).add;
)
(
SynthDef(\delay, {
	var eff, sig;
	sig = In.ar(100, 2);
	eff = CombC.ar(sig, 0.25, 0.25, 2.0);
	Out.ar(0, eff);
}).add;
)

\tone2で100番のoutputに出力して
\delayで100番からの信号を受けています。

Pfxをplayすると、~dlyBusを使ったものと同様に動作するのを確認できます。

今回やったようにバスを~dlyBusなどの変数名に入れておけば自動的に空きバスに割り当ててくれるので楽だと思うのですが、何かの理由で自分でバスの番号を管理したい場合は、この手法が使えます。


1回の実行で音を鳴らす


今回は、説明のためにSynthDefやPfxなど分割してコードを書きましたが、下記のように全部のコードを(カッコ)でくくれば、一発の実行でシーケンス再生できますので、念のため書いておきます。

(
~dlyBus = Bus.audio(s, 2);

SynthDef(\tone2, {
	arg freq=220, env, gate=1;
	var sig, aux=0.4;
	env = EnvGen.kr(Env.asr(0.01, 1.0, 0.05), gate, doneAction:2);
	sig = Pulse.ar([freq, freq*2]);
	Out.ar(~dlyBus, sig * env * aux);
	Out.ar(0, sig * env);
}).add;

SynthDef(\delay, {
	var eff, sig;
	sig = In.ar(~dlyBus, 2);
	eff = CombC.ar(sig, 0.25, 0.25, 2.0);
	Out.ar(0, eff);
}).add;


~pb = Pbind(
	\instrument, \tone2,
	\midinote, Pseq([38, 36, 38, 45, 50, 45, 24, 36], inf),
	\dur, 0.5,
	\sustain, 0.1
);

Pfx(~pb, \delay).play(TempoClock(40/60));
)


今回はこんなところで終わります。
次回はモジュレーションについて書きます。


今日のまとめ


・Bus.audio(s, 2)でバスを作成(自動的に空いているoutputに割り当ててくれる)
・Out.arの出力先をバスに送る
・In.arでバスの信号を受け取る
・Pfx(Pbind(), \reverb).play;
・FreeVerb, FreeVerb2, GVerbはリバーブ
・sigのアウトプット[0, 1]からoutput0, output1別々に出力を取り出すにはsig[0], sig[1]
・Out.arを2個並べてもよい
・DelayC, DelayL, DelayNはサンプルディレイ
・フィードバック付きディレイはCombC, CombL, CombN, AllpassC, AllpassL, AllpassN


<目次>にも今回のリンクを作っておきます。https://note.com/sc3/n/nb08177c4c01

いいなと思ったら応援しよう!