2017/05/25

SuperColliderでディレイとフェイザ

ディレイ

ヘルプではUGen > Delaysとして分類されています。エフェクトとしてのディレイには CombC などを使います。 DelayC などはただの遅延素子なのでフィードバックはかかりません。

exception in real time: alloc failed が出るときは s.options.memSize で確保するメモリを増やしてサーバを再起動します。デフォルトでは8192KBが確保されます。

s.options.memSize = 1000000; // 1GBのメモリを確保。

SynthDef(\delay,
  { | out(0), in(0), delayTime(0.2), decaytime(16), wet(0.5) |
    var input = In.ar(in, 2);
    var dry = input * (1 - wet);
    var delay = CombC.ar(input, 4, delayTime, decaytime, wet, dry);
    OffsetOut.ar(out, delay);
  }
).add;

TempoClock.tempo = 140 / 60;

~seq = Pbind(
  \degree, Pseq([0, 2.2, 4.35, 6.67, 8.81], inf),
  \dur, 0.5,
  \amp, 0.3,
  \out, 10
);
~delay = Pfx(~seq, \delay, \delayTime, 0.63, \in, 10).play;

以下はステレオディレイの例です。 Pfxb を使う場合は SynthDef の出力チャンネル数を s.options.numOutputBusChannels 以下にしないとエラーがでるようなので注意してください。

SynthDef(\delayStereo,
  { | out(0), in(0), delayTimeL(0.2), delayTimeR(0.15), decaytime(16)
    , wet(0.5) |
    var input = In.ar(in, 2);
    var dry = input * (1 - wet);
    var delayL = CombC.ar(input[0], 4, delayTimeL, decaytime, wet, dry[0]);
    var delayR = CombC.ar(input[1], 4, delayTimeR, decaytime, wet, dry[1]);
    OffsetOut.ar(out, [delayL, delayR]);
  }
).add;

~seq1 = Pbind(
  \out, 10,
  \degree, Pseq([[0, 3], [0, 5], [2, 5], [2, 7]], inf),
  \amp, 0.2
);

~seq2 = Pbind(
  \out, 10,
  \degree, Pseq([
    Pseq([Rest], 4),
    Pseq([14, 11, 8, Rest])
  ], inf),
  \dur, 4,
  \amp, 0.2
);

~seq3 = Pbind(
  \out, 10,
  \degree, Pseq([
    Pseq([Rest], 8),
    Pseq([-10, -9, -11, -10, -9, -11, -10, -14])
  ], inf),
  \dur, 8,
  \amp, 0.4
);

~par = Ppar([~seq1, ~seq2, ~seq3]);

TempoClock.tempo = 100 / 60;

~delay = Pfxb(~par, \delayStereo,
  \in, 10,
  \delayTimeL, TempoClock.beatDur * 0.78,
  \delayTimeR, TempoClock.beatDur * 0.666,
).play;

フィードバック

フィードバックを作るときは LocalInLocalOut が使えます。

{
  var input = LocalIn.ar(2, 1) * 10;
  var osc = SinOsc.ar(input, input * 1000, MouseX.kr(0.001, 0.5, 1));
  LocalOut.ar(osc);
  OffsetOut.ar(0, [osc, osc])
}.play;

フェイザ

ノッチができるフィルタを直列につないでカットオフ周波数をLFOで揺らすとフェイザになります。

以下の例では DelayCコムフィルタを作っています。 DelayC のかわりに AllpassC などを使っても似たような効果になります。

s.options.memSize = 1000000;

SynthDef(\phaser,
  { | out(0), in(0), rate(0.2), minDelay(0.0001), maxDelay(0.001)
    , dry(1), feedback(0.5) |
    var input = In.ar(in, 2);
    var inputFeedback = DelayC.ar(LocalIn.ar(2), 0.01, 0.0001, feedback);
    var phaser = List[];

    var lfo = LFPar.ar(rate).exprange(minDelay, maxDelay);
    var temp = input.do({ |channel, index|
      var filter = channel + inputFeedback[index];
      4.do({
        filter = DelayC.ar(filter, 1, lfo, 2/7, 0-filter * 5/7)
        // filter = AllpassC.ar(filter, 1, lfo, 0.001, 2/7, 0-filter * 5/7)
      });
      phaser.add(filter)
    });

    var output = phaser + (input * dry * 5/7);
    LocalOut.ar(output);
    OffsetOut.ar(out, output)
  }
).add;

~seq = Pbind(
  \out, 10,
  \scale, Scale.chromatic,
  \degree, Pseq([
    [0, 5, 9, 14],
    [2.01, 9.01, 16, -2.5],
    [3, 6.98, 8.1, 10],
    [4.97, 9, 10, 12],
    [8, 9.99, 11.5, 19],
    [3, 7.02, 8.01, 10],
    [5, 8.96, 10, 12.01],
    [-2, 1.41, 3, 5]
  ], inf),
  \dur, 1,
);

TempoClock.tempo = 130 / 60;

~phaser = Pfx(~seq, \phaser, \in, 10, \feedback, 0.8).play;