TITLE:: PV_BinDelay
summary:: Delay and Feedback on a bin by bin basis.
categories:: Libraries>JoshUGens, UGens>FFT

DESCRIPTION::
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.
::

CLASSMETHODS::

METHOD:: new

ARGUMENT:: buffer
The FFT buffer.

ARGUMENT:: maxdelay
In seconds. Used at init time to create memory for the delays. Non-modulatable.

ARGUMENT:: 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.

ARGUMENT:: fbbuf
A buffer of (fft buffer size / 2) containing the fb percentages for each bin.

ARGUMENT:: 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.


INSTANCEMETHODS::


EXAMPLES::

code::
(
// 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.

s.boot;
s.doWhenBooted({
	var size, fftSize, awin, delaySilder, fbSlider, maxdel, synth, cond, playbuf;
	var setup, onReadyFunc, fftBuffer, delTimeBuffer, fbAmtBuffer, createGUI, liveInputMix;

	size = 128;
	fftSize = size * 2;
	maxdel = 0.5;
	cond = Condition.new;
	liveInputMix = 0.0; // change to 1 to hear sound from live input, otherwise, an Impulse

	SynthDef(\helpBinDelay, { arg inbus=0, inMix = 0.0, out=0, fftBuf=0, delayBuf=0, fbBuf=0;
		var in, chain;
		in = (Impulse.ar(0.33) * (1.0 - inMix)) + (In.ar(inbus, 1) * inMix);
		chain = FFT(fftBuf, in, 0.25);
		chain = PV_BinDelay(chain, maxdel, delayBuf, fbBuf, 0.25);
		Out.ar(out,
			in + IFFT(chain) * -24.dbamp// inverse FFT
		);
	}).add;

	/* Functions that allocate buffers and call onReadyFunc when done */
	setup = {
		Routine.run({
			"Allocating FFT buffer".postln;
			fftBuffer = Buffer.alloc(s, fftSize, 1);
			"Allocating DelTime buffer".postln;
			delTimeBuffer = Buffer.alloc(s, size, 1);
			"Allocating FB buffer".postln;
			fbAmtBuffer = Buffer.alloc(s, size, 1);
			s.sync(cond);
			onReadyFunc.value()
		});
	};

	createGUI = {

		awin = Window("test", Rect(200 , 450, 10 + (size * 1), 10 + (size * 2)));
		awin.view.decorator = FlowLayout(awin.view.bounds);

		delaySilder = MultiSliderView(awin, Rect(0, 0, size * 1, size * 1));
		delaySilder.action = {arg xb;
			("Deltime index: " ++ xb.index ++" value: " ++ (xb.currentvalue * maxdel)).postln;
			delTimeBuffer.set(xb.index, xb.currentvalue * maxdel)
		};

		fbSlider = MultiSliderView(awin, Rect(0, 0, size * 1, size * 1));
		fbSlider.action = {arg xb;
			("FB index: " ++ xb.index ++" value: " ++ xb.currentvalue).postln;
			fbAmtBuffer.set(xb.index, xb.currentvalue)
		};

		[delaySilder, fbSlider].do({arg thisSliderView;
			var initDataArray;
			initDataArray = Array.fill(size, {0.0});
			thisSliderView.value_(initDataArray);
			thisSliderView.xOffset_(5);
			thisSliderView.thumbSize_(12.0);

			// value axis size of each blip in pixels
			thisSliderView.valueThumbSize_(15.0);
			// index axis size of each blip in pixels
			thisSliderView.indexThumbSize_( thisSliderView.bounds.width / initDataArray.size );
			thisSliderView.gap = 0;
		});

		awin.front;

		awin.onClose_({
			synth.free;
			fftBuffer.free;
			fbAmtBuffer.free;
			delTimeBuffer.free;
		})
	};

	onReadyFunc = {
		createGUI.defer();

		synth = Synth(\helpBinDelay, [
			\inbus, s.options.numOutputBusChannels,
			\inMix, liveInputMix,
			\out, 0,
			\fftBuf, fftBuffer.bufnum,
			\delayBuf, delTimeBuffer.bufnum,
			\fbBuf, fbAmtBuffer.bufnum,
		]);
	};

	setup.value();
})
)
::
