【TidalCycles】roomリバーブのカスタム

TidalCyclesの標準で用意されているエフェクト(グローバルエフェクト)にroomリバーブがありますが、個人的にこのリバーブ感がとても好きなので重宝しています。

ただ、実はこのroomリバーブのリバーブ音はほぼモノラルなので、音の位置に拘った演奏・曲作りする際には結構不便です。

なので書き換えちゃいましょう。

Macの場合は

`~/Library/Application Support/SuperCollider/downloaded-quarks/SuperDirt/synths/core-synths-global.scd`を書き換えるか、起動時に上書きするようにするのがいいと思います。今回は起動時に上書きする場合のコードを紹介します(書き換えるだけの場合は`~dirt.numChannels`を`numChannels`のままにしておけば動くはずです)

```supercollider
Server.default.waitForBoot{
    ~dirt = SuperDirt(2, Server.default);

    // 音源を読み込んだり
    // ~dirt.loadSoundFiles(thisProcess.nowExecutingPath.dirname ++ "/samples/*");
	// Server.default.sync;
	~dirt.loadSoundFiles;
	Server.default.sync;

    // ここにグローバルエフェクトの定義を書く(後述)
    ...

    // wait load
	Server.default.sync;
	~dirt.start(57120, 0 ! 12);
}
```


# 実装

```diff_super_collider
-SynthDef("dirt_reverb" ++ numChannels, { |dryBus, effectBus, gate = 1, room = 0, size = 0.1, dry = 0|
+SynthDef("dirt_reverb" ++ ~dirt.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.ar(dryBus, ~dirt.numChannels);
	
	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) };
+	4.do { in = AllpassN.ar(in, 0.03, { Rand(0.005, 0.02) }, 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 = LocalIn.ar(~dirt.numChannels) * { depth + Rand(0, 0.05) };
	loop = OnePole.ar(loop, 0.5);  // 0-1
	
-	loop = AllpassN.ar(loop, 0.05, { Rand(0.01, 0.05) }.dup(numChannels), 2);
+	loop = AllpassN.ar(loop, 0.05, { Rand(0.01, 0.05) }, 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 = AllpassN.ar(loop, 0.05, { Rand(0.03, 0.15) }, 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;
```


# 完成

```supercollider
SynthDef("dirt_reverb" ++ ~dirt.numChannels, { |dryBus, effectBus, gate = 1, room = 0, size = 0.1, dry = 0|
	var in, snd, loop, depth;
	
	in = In.ar(dryBus, ~dirt.numChannels);
	
	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) }, 1) };
	
	depth = size.lag(0.02).linexp(0, 1, 0.01, 0.98); // change depth between 0.1 and 0.98
	loop = LocalIn.ar(~dirt.numChannels) * { depth + Rand(0, 0.05) };
	loop = OnePole.ar(loop, 0.5);  // 0-1
	
	loop = AllpassN.ar(loop, 0.05, { Rand(0.01, 0.05) }, 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) }, 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;
```