Thursday, September 17, 2009

Comb Filter Effect

Another handy snippet of code pulled from the SC-Users list once again. Credit for this goes to Kernal, kernel@audiospillage.com.
The gui should be mostly self explanatory I think, but if you want to use this with other inputs besides the test sound you'll need to set the input bus and send your sound through that.


// parrallel comb filters implemented as effect return

// send the synth defs(
(
SynthDef("ImpulseTest", {|bus = 3|

Out.ar(bus, [Impulse.ar(SinOsc.kr(0.23).range(0.5,23), 0.5)]);

}).send(s);
);

(
SynthDef("CombUnit",{| d1 = 0.001, d2 = 0.001, d3 = 0.001, d4 = 0.001, d5 = 0.001,
t1 = 1, t2 = 1, t3 = 1, t4 = 1, t5 = 1,
f1 = 20000, f2 = 20000, f3 = 20000, f4 = 20000, f5 = 20000,
vol = 1, inBus = 3, outBus = 0|

var in, out, c1, c2, c3, c4, c5;

in = In.ar(inBus, 1);

c1 = LPF.ar(CombC.ar(in, 1, d1, t1), f1);
c2 = LPF.ar(CombC.ar(in, 1, d2, t2), f2);
c3 = LPF.ar(CombC.ar(in, 1, d3, t3), f3);
c4 = LPF.ar(CombC.ar(in, 1, d4, t4), f4);
c5 = LPF.ar(CombC.ar(in, 1, d5, t5), f5);

out = (c1 + c2 + c3 + c4 + c5) * 0.2;

Out.ar([outBus, outBus + 1], out * vol);

}).send(s);
);
)



// create the synth
(
var grp, node, testNode, wComb, testRunning = 0, inputBus = 3;

s.sendMsg("s_new", "CombUnit", node = s.nextNodeID, 1, 1);
// s.sendMsg("g_new",grp = s.nextNodeID,1,1); // create group @ tail of default node

wComb = SCWindow("C O M A", Rect(100, 300, 720, 220))
.onClose_({
if(testRunning == 1, s.sendMsg("n_free", testNode));
s.sendMsg("n_free", node);
})
.front;

// input bus
SCNumberBox(wComb, Rect(10, 10, 30, 20))
.value_(3)
.action_({|v|
inputBus = v.value;
s.sendMsg("n_set", node, "inBus", inputBus);
if(testRunning == 0, s.sendMsg("n_set", testNode, "bus", inputBus));
});

SCStaticText(wComb, Rect(45, 10, 100, 20))
.string_("Input Bus");

// output bus
SCNumberBox(wComb, Rect(150, 10, 30, 20))
.value_(0)
.action_({|v| s.sendMsg("n_set", node, "outBus", v.value)});

SCStaticText(wComb, Rect(185, 10, 100, 20))
.string_("Output Bus");

// audio test
SCButton(wComb, Rect(300, 10, 100, 20))
.states_([
["Start Test", Color.green, Color.black],
["Stop Test", Color.red, Color.black]
])
.action_({
if(testRunning == 0, {
s.sendMsg("s_new", "ImpulseTest", testNode = s.nextNodeID, 0, 1, "bus", inputBus);
testRunning = 1;
},{
s.sendMsg("n_free", testNode);
testRunning = 0;
});
});

// comb frequencies
SCStaticText(wComb, Rect(10, 40, 100, 20)).string_("Comb Frequencies");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(10, 60 + (i * 25), 40, 20))
.value_(950);

SCStaticText(wComb, Rect(55, 60 + (i * 25), 15, 20)).string_("Hz");

SCSlider(wComb, Rect(80, 60 + (i * 25), 130, 20))
.value_(0.5)
.action_({|v| var time, freq;
freq = [1, 20000, 6].asSpec.map(v.value);
time = 1.0 / freq;
s.sendMsg("n_set", node, i, time);
box.value_(freq.asInteger);
})
};

// resonances
SCStaticText(wComb, Rect(250, 40, 100, 20)).string_("Resonances");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(250, 60 + (i * 25), 30, 20))
.value_(50);

SCStaticText(wComb, Rect(285, 60 + (i * 25), 15, 20)).string_("%");

SCSlider(wComb, Rect(300, 60 + (i * 25), 150, 20))
.value_(0.5)
.action_({|v|
s.sendMsg("n_set", node, i+5, [0, 9, 4].asSpec.map(v.value));
box.value_(v.value * 100);
});
};

// low pass frequencies
SCStaticText(wComb, Rect(555, 40, 100, 20)).string_("Low Pass Frequencies");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(490, 60 + (i * 25), 40, 20)).value_(20000);
SCStaticText(wComb, Rect(535, 60 + (i * 25), 15, 20)).string_("Hz");

SCSlider(wComb, Rect(555, 60 + (i * 25), 150, 20))
.value_(1)
.action_({ |v| var freq;
freq = [20, 20000, \exp].asSpec.map(v.value);
s.sendMsg("n_set", node, i+10, freq);
box.value_(freq);
});
};

// volume control
SCStaticText(wComb, Rect(10, 190, 70, 20)).string_("Volume");
SCSlider(wComb, Rect(80, 190, 625, 20))
.value_(1)
.action_({|v| s.sendMsg("n_set", node, "vol", [0, 1, 4].asSpec.map(v.value))});
)