Partitioned convolution. Various additional buffers must be supplied.
Mono impulse response only! If inputting multiple channels, you'll need independent PartConvs, one for each channel.
But the charm is: impulse response can be as large as you like (CPU load increases with IR size. Various tradeoffs based on fftsize choice, due to rarer but larger FFTs. This plug-in uses amortisation to spread processing and avoid spikes).
Normalisation factors difficult to anticipate; convolution piles up multiple copies of the input on top of itself, so can easily overload.
in |
processing target. |
fftsize |
spectral convolution partition size (twice partition size). You must ensure that the blocksize divides the partition size and there are at least two blocks per partition (to allow for amortisation). |
irbufnum |
prepared buffer of spectra for each partition of the inpulse response. |
mul | |
add |
// preparation; essentially, allocate an impulse response buffer, then
// follow a special buffer preparation step to set up the data the plugin needs.
// Different options are provided commented out for loading impulse responses from soundfiles.
(
// also 4096 works on my machine; 1024 too often and amortisation too pushed, 8192 more high load FFT
~fftsize = 2048;
s.waitForBoot {
{
var ir, irbuffer, bufsize;
// // MONO ONLY
// pre-existing impulse response sound files
// (could also use any general soundfile too for cross-synthesis effects)
// irbuffer = Buffer.read(s, "/Volumes/data/audio/ir/ir2.wav");
// synthesise the honourable 'Dan Stowell' impulse response
ir = [1] ++ 0.dup(100) ++ (
(1, 0.99998 .. 0)
.collect {|f|
f = f.squared.squared;
f = if(f.coin) { 0 }{ f.squared };
f = if(0.5.coin) { 0 - f } { f }
} * 0.1
);
ir = ir.normalizeSum;
irbuffer = Buffer.loadCollection(s, ir);
s.sync;
bufsize = PartConv.calcBufSize(~fftsize, irbuffer);
// ~numpartitions= PartConv.calcNumPartitions(~fftsize, irbuffer);
~irspectrum = Buffer.alloc(s, bufsize, 1);
~irspectrum.preparePartConv(irbuffer, ~fftsize);
s.sync;
irbuffer.free; // don't need time domain data anymore, just needed spectral version
}.fork;
}
)
~target = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
(
{
var input = PlayBuf.ar(1, ~target, loop:1);
PartConv.ar(input, ~fftsize, ~irspectrum.bufnum, 0.5)
}.play
)
// convolve with live input
(
{
var input = SoundIn.ar(0);
PartConv.ar(input, ~fftsize, ~irspectrum.bufnum)
}.play
)
// should get back original impulse response (once every four seconds)
(
{
var input = Impulse.ar(0.25);
PartConv.ar(input, ~fftsize, ~irspectrum.bufnum)
}.play
)
// only free buffers once you're finished with examples
// if you free whilst PartConv is still running, the server won't crash, but PartConv output will go to zero abruptly
(
~irspectrum.free;
~target.free;
currentEnvironment.clear;
)