1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SuperCollider】インパルス応答からリバーブをかける方法

Last updated at Posted at 2024-07-18

はじめに

一般的にデジタルリバーブをかける場合、選択肢は二つあります。

  • アルゴリズミックリバーブ
  • コンボリューションリバーブ

アルゴリズミックリバーブ

Schroeder Reverbなどで検索するといろいろ出てきますが、デジタルで残響音をつくり出すためのアルゴリズムです。

image.png
出典: https://maxforlive.com/library/device/9181/schroeder-reverb

Schroeder Reverbは最初に考案されたアルゴリズミックリバーブですが、少ないマシンパワーでもリアルタイムにエフェクトをかけられるため現在でも使われています。
もちろんSuperColliderでも実装できます。
https://doc.sccode.org/Tutorials/Mark_Polishook_tutorial/Japanese_version/13.html#リバーブレーション

コンボリューションリバーブ

アルゴリズミックリバーブが現実の残響ではなく機械的に作ったものであるのに対して、コンボリューションリバーブは現実の残響を利用するものです。

インパルス応答

たとえば一瞬だけ鳴る破裂音があるとします。これを空間の中で再生すると、その空間の響き方によって残響が変わります。
このときこの残響を含めた音をインパルス応答といって、これがあればどんな音にでも同じ残響音を付与することができます。(元の音にインパルス応答の波形の値を時間方向にかけてあげるだけ)
image.png
出典: http://www.ari-web.com/service/soft/reverb-4.htm

この計算方法は感覚的にもわかりやすいですが、実際には計算回数が多いためこのままだとリアルタイム処理には向きません。

フーリエ変換

そこで活躍するのがフーリエ変換(FFT)で、サンプルの数だけ乗算しないといけなかったのがFFT後の世界では一度の乗算で計算が完了してしまいます。あとはこれを逆フーリエ変換(IFFT)するだけです。
image.png
出典: http://www.ari-web.com/service/soft/reverb-4.htm

インパルス応答データ

ちなみにインパルス応答を録音するためには、静寂な環境で理想的なインパルス音源(周波数に偏りがなく、音も限りなく短い大音量なノイズ)である必要があります。
もちろん手を叩いた音を録音することでもある程度代用できますが、高品質なインパルス応答を得るのは少し難しいです。
そこでOpenAirというWebサイトでは高品質なインパルス応答が無料で公開されているため、こちらをダウンロードして使ってみるのが最初はいいかもしれません。
https://www.openair.hosted.york.ac.uk/?page_id=36

コンボリューションリバーブの実装

SuperColliderで実装します。

デフォルトのパッケージだと畳み込み演算の処理が遅いので、EZConvというクラスをインストールして使っていきます。

EZConvのインストール方法

SuperColliderのエディタを開き、

Quarks.install("https://github.com/davidgranstrom/EZConv.git");

を実行するだけでインストールできます。

実行後はSuperColliderを再起動するか、Recompile Class LibraryすればEZConvクラスが使用できるようになると思います。

image.png

EZConvの使い方

こんなフォルダ構成になっているものとします。

$ tree
.
├── IRs
│   └── residential_area.wav
└── test.scd

residential_area.wavは住宅街で録音した簡易インパルス応答ですが、こちらからダウンロードできます。

下記のようなtest.scdを用意して、それぞれCmd+Enter(WindowsはCtrl+Enter)して実行してみてください。

test.scd
// Load your IR.
(
~path=thisProcess.nowExecutingPath.dirname ++ "/IRs/residential_area.wav";
~ezConv=EZConv(~path, fftSize: 2048);
)

// Unload the IR. You might want to do this before loading a new one.
// ~ezConv.free;

// 以下をCmd+Enterで実行すると残響音付きのカエルのような声がでます
// 1行目のwetが残響音、dryが原音なので調整すると遊べます。
(
SynthDef("frog", { arg out, pan=0, variation=0.9, wet=0.9, dry=0.1;
	var dt, n, freq, mul, t, u, p, amp=0.1;
	n = Rand(7, 35);
	dt = 25.0 + Rand(-1.7, 1.7);
	dt = dt + LFNoise2.kr(2, variation) * 0.001;
	freq = 901 + Rand(0, 65);
	t = Impulse.ar(dt.reciprocal, 0, 100);
	mul = PulseCount.ar(t) < n;
	u = BPF.ar(mul * t, freq, 0.1);
	u = BPF.ar(u, freq, 0.2);
	u = u!2 * 5;
	// コンボリューションリバーブ
    // *0.03部分は、インパルス応答音源のボリューム調整
	p=~ezConv.ar([u[0],u[1]],0,1)*0.03; //(signals, leak, mult)
	u=(p*wet)+(u*dry);
	// 残響音がなくなってからnodeを解放するためDetectSilenceを使用
	DetectSilence.ar(u, doneAction:2);
	Out.ar(out, u*amp);
}).play;
)

SuperDirt, TidalCyclesのためのリバーブエフェクト追加

自分はこのコンボリューションリバーブをグローバルエフェクトとして定義したかったので、以下のようにSuperDirtを変更しています。

  • residential_area.wavを下記ディレクトリに配置(Mac)
    ~/Library/Application Support/SuperCollider/downloaded-quarks/SuperDirt/synths/

  • ~/Library/Application Support/SuperCollider/downloaded-quarks/SuperDirt/classes/DirtOrbit.scを以下のように編集

DirtOrbit.sc
...

	initDefaultGlobalEffects {
		this.globalEffects = [
			// all global effects sleep when the input is quiet for long enough and no parameters are set.
			GlobalDirtEffect(\dirt_delay, [\delaytime, \delayfeedback, \delaySend, \delayAmp, \lock, \cps]),
			GlobalDirtEffect(\dirt_reverb, [\size, \room, \dry]),
+			GlobalDirtEffect(\residential_area_reverb, [\resi]),
			GlobalDirtEffect(\dirt_leslie, [\leslie, \lrate, \lsize]),
			GlobalDirtEffect(\dirt_rms, [\rmsReplyRate, \rmsPeakLag]).alwaysRun_(true),
			GlobalDirtEffect(\dirt_monitor, [\limitertype]).alwaysRun_(true),
		]
	}

...
  • ~/Library/Application Support/SuperCollider/downloaded-quarks/SuperDirt/synths/core-synths-global.scdを以下のように編集
core-synths-global.scd
...

{
	var numChannels = ~dirt.numChannels;
+   var residentialAreaIRPath=thisProcess.nowExecutingPath.dirname ++ "/residential_area.wav";
+   var residentialAreaConv=EZConv(residentialAreaIRPath, fftSize: 2048);

...

SynthDef("dirt_reverb" ++ numChannels, { |dryBus, effectBus, gate = 1, room = 0, size = 0.1, dry = 0|
		var in, snd, loop, depth;

		in = In.ar(dryBus, numChannels).asArray.sum;

		in = in * room.lag(LFNoise1.kr(1).range(0.01, 0.02)); // regulate input

		4.do { in = AllpassN.ar(in, 0.03, { Rand(0.005, 0.02) }.dup(numChannels), 1) };

		depth = size.lag(0.02).linexp(0, 1, 0.01, 0.98); // change depth between 0.1 and 0.98
		loop = LocalIn.ar(numChannels) * { depth + Rand(0, 0.05) }.dup(numChannels);
		loop = OnePole.ar(loop, 0.5);  // 0-1

		loop = AllpassN.ar(loop, 0.05, { Rand(0.01, 0.05) }.dup(numChannels), 2);

		loop = DelayN.ar(loop, 0.3, [0.19, 0.26] + { Rand(-0.003, 0.003) }.dup(2));
		loop = AllpassN.ar(loop, 0.05, { Rand(0.03, 0.15) }.dup(numChannels), 2);

		loop = loop + in;
		loop = LeakDC.ar(loop);

		LocalOut.ar(loop);

		snd = loop;
		snd = snd * (1 - dry).lag(LFNoise1.kr(1).range(0.01, 0.02));

		DirtPause.ar(snd, graceTime:4);

		snd = snd * EnvGen.kr(Env.asr, gate, doneAction:2);

		Out.ar(effectBus, snd);

	}, [\ir, \ir]).add;

+   SynthDef("residential_area_reverb" ++ ~dirt.numChannels, { |dryBus, effectBus, resi|
+		var signal = In.ar(dryBus, ~dirt.numChannels);
+		var process, gate = 1;
+
+		process=residentialAreaConv.ar([signal[0],signal[1]],0,1)*0.03; //(signals, leak, mult)
+		signal=(process*resi)+(signal*(1-resi));
+
+		signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2);
+
+		DirtPause.ar(signal, graceTime:4);
+
+		Out.ar(effectBus, signal);
+	}, [\ir, \ir]).add;

...

TidalCyclesでresiエフェクトを使いたいので、BootTidal.hsに以下を追加

BootTidal.hs
...

+ :{
+ resi = pF "resi"
+ :}

...

これで、

sample.tidal
d1
	$ s "bd"
 	# resi 1

のようにすればresiエフェクトが使えるようになると思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?