PV_BinDelay Delay and Feedback on a bin by bin basis
PV_BinDelay(buffer, maxdelay, delaybuf, fbbuf, hop = 0.5)
buffer - the FFT buffer.
maxdelay - in seconds. Used at init time to create memory for the delays. Non-modulatable.
delaybuf - a buffer of (fft buffer size / 2) containing the delay times for each bin. Delay times
will be rounded to the closest bin. Smaller FFT windows will yield better time resolution.
fbbuf - a buffer of (fft buffer size / 2) containing the fb percentages for each bin.
hop - if you are using FFT with a hop value different then the default 0.5, you need to tell PV_BinDelay
so it can calculate the correct times.
WARNING! This UGen needs to allocate a large amount of real-time memory at the outset (approx.
SampleRate * maxDelayTime). This will cause a CPU spike at startup. Also, due to memory
mangement restrictions, There is a limited number of previous frames that can be stored. Right now
no more the 512 frames can be stored. With a frame size of 512 samples, this makes a hard limit
to the max delay of about 5.9 seconds at a SR of 44100 (or (FFT size * 512) / SR). Chances are,
however, that you will run out of RT memory (the memSize ServerOption) before hitting these
limits, especially at larger FFT frame sizes.
Examples:
s.boot;
(
Routine.run({
// use as multislider - del time vals on top, feedback on the bottom
// max delay time is 1 second, delaytime and fb are initialized to 0.0
// and are controlled by the GUI. The multi-slider on the top controls
// each bins delay time, the bottom controls FB.
var size, awin, bsl, car, dar, fsl, maxdel, synth, cond;
size = 128;
maxdel = 0.5;
cond = Condition.new;
s.sendMsg(\b_alloc, b=s.bufferAllocator.alloc(1), size * 2);
s.sendMsg(\b_alloc, c=s.bufferAllocator.alloc(1), size);
s.sendMsg(\b_alloc, d=s.bufferAllocator.alloc(1), size);
y = Array.fill(size, {0.0});
s.sendBundle(0.1, [\b_setn, d, 0, size] ++ y);
z = Array.fill(size, {arg i; 0.0});
s.sendBundle(0.1, [\b_setn, c, 0, size] ++ z);
s.sync(cond);
synth = SynthDef("help-noopFFT", { arg inbus,out=0,bufnum=0, dels=0, fb=0;
var in, chain;
in = Impulse.ar(0.33);
in = PlayBuf.ar(1, playbuf, loop: 1);
chain = FFT(bufnum, in, 0.25);
chain = PV_BinDelay(chain, maxdel, dels, fb, 0.25);
Out.ar(out,
in + IFFT(chain) // inverse FFT
);
}).play(s,[\out,0,\bufnum,b,\dels, c, \fb, d, \inbus, s.options.numOutputBusChannels]);
{
awin = GUI.window.new("test", Rect(200 , 450, 10 + (size * 1), 10 + (size * 2)));
awin.view.decorator = FlowLayout(awin.view.bounds);
bsl = GUI.multiSliderView.new(awin, Rect(0, 0, size * 1, size * 1));
bsl.action = {arg xb; ("Deltime index: " ++ xb.index ++" value: " ++
(xb.currentvalue * maxdel)).postln;
s.sendMsg(\b_set, c, xb.index, xb.currentvalue * maxdel);
};
fsl = GUI.multiSliderView.new(awin, Rect(0, 0, size * 1, size * 1));
fsl.action = {arg xb; ("FB index: " ++ xb.index ++" value: " ++ xb.currentvalue).postln;
s.sendMsg(\b_set, d, xb.index, xb.currentvalue);
};
car = Array.new;
size.do({arg i;
car = car.add(0);
});
bsl.value_(car);
dar = Array.new;
size.do({arg i;
dar = dar.add(0);
});
fsl.value_(car);
bsl.xOffset_(5);
bsl.thumbSize_(12.0);
fsl.xOffset_(5);
fsl.thumbSize_(12.0);
// value axis size of each blip in pixels
bsl.valueThumbSize_(15.0);
// index axis size of each blip in pixels
bsl.indexThumbSize_( bsl.bounds.width / car.size );
bsl.gap = 0;
// value axis size of each blip in pixels
fsl.valueThumbSize_(15.0);
// index axis size of each blip in pixels
fsl.indexThumbSize_( fsl.bounds.width / dar.size );
fsl.gap = 0;
awin.front;
awin.onClose_({
synth.free;
s.sendMsg(\b_free, b);
s.sendMsg(\b_free, c);
s.sendMsg(\b_free, d);
})
}.defer;
})
)