Hello all
I’ve wanted for a while to have access to an old school vocoder in SC but I haven’t really sat down and worked on it before now. I would love some feedback.
What I mean by old school vocoder is something that happens in the time domain where the signal is split using bandpass filters instead of FFT decomposition.
Anyways, here is what I came up with today. It’s pretty good but not perfect. It creates different versions of the synthdef with different numbers of bands where each band has it’s own controls for attack, release and gain. What do you think?
b = Buffer.read(s, Platform.systemAppSupportDir +/+ "sounds" +/+ "a11wlk01.wav");
(
[8, 16, 32, 64].do{|numbands|
var defname = "vocoder%bands".format(numbands).asSymbol.postln;
SynthDef(defname, {|out=0|
// Input signal. Should be replaced with Input.ar
var sig = PlayBuf.ar(numChannels:1, bufnum:b, rate:BufRateScale.kr(b), trigger:1.0, startPos:0.0, loop:1.0, doneAction:0);
var inputSig = SawDPW.ar(\freq.ar(100));
var bandrq = \rq.kr(0.05);
sig = Array.fill(numbands, {|bandNum|
var bandfreq = bandNum.linexp(0,numbands-1, \minFreq.ir(100), \maxFreq.ir(8000));
var filtered = BPF.ar(in:sig, freq:bandfreq, rq:bandrq, mul:1.0, add:0.0);
var osc = BPF.ar(inputSig, bandfreq, bandrq);
var thisGain = "bandGain%".format(bandNum+1).asSymbol.kr(1);
var atk = "bandAttack%".format(bandNum+1).asSymbol.kr(0.01);
var rel = "bandRelease%".format(bandNum+1).asSymbol.kr(0.01);
osc * thisGain * Amplitude.ar(in:filtered, attackTime:atk, releaseTime:rel) * bandrq.reciprocal
});
sig = sig.sum!2;
Out.ar(out, sig * \amp.kr(1))
}).add;
}
)
// Pretty straightforward
(
~synth = Synth(\vocoder16bands, [
\rq, 0.05,
\freq, 100,
]);
)
~synth.set(\freq, 550);
~synth.set(\freq, 50, \rq, 0.01);
(
~synth2 = Synth(\vocoder8bands, [
\rq, 0.05,
\freq, 250,
\bandAttack1, 0.005, \bandAttack2, 0.001, \bandAttack3, 0.0005,
\bandRelease1, 0.05, \bandRelease2, 0.01, \bandRelease3, 0.005,
\bandGain1, 1, \bandGain2, 2, \bandGain3, 2, \bandgain4, 4,
]);
)