class:: UnpackFFT
summary:: Unpack an FFT chain into separate demand-rate FFT bin streams
categories:: UGens>FFT
related:: Classes/PackFFT, Classes/Unpack1FFT

description::
Takes an FFT chain and separates the magnitude and phase data into separate demand-rate streams, for arithmetic manipulation etc.

This is technically a demand-rate UGen. The actual "demand" is usually created by PackFFT later on in the graph, which requests the values in order to re-pack the data. This allows for processing to occur in between...

See also pvcollect, pvcalc and pvcalc2 methods ( in link::Classes/PV_ChainUGen:: ) which provide convenient ways to process audio in the frequency domain. The help for pvcollect includes notes on efficiency considerations.

classmethods::
private:: categories

method:: new
argument:: chain
FFT chain
argument:: bufsize
FFT buffer size
argument:: frombin
limiting analysis to the bins of interest
argument:: tobin
limiting analysis to the bins of interest
returns::
A list from DC up to Nyquist of code:: [mag[0], phase[0], mag[1], phase[1], ... mag[nyquist], phase[nyquist]]. ::
discussion::
Note that you do have to decide your FFT buffer size in advance, since this determines how many values the UGen will output.
code::
#magsphases = UnpackFFT(chain, bufsize)
::

examples::
code::
(
s.waitForBoot({
	var fftsize = 1024;
	b = Buffer.alloc(s, fftsize, 1);
	c = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
})
)

// This one just drags out various the values and posts them - a little bit pointless!
(
x = {
	var sig, chain, unp;
	sig = SinOsc.ar;
	sig = PlayBuf.ar(1, c, BufRateScale.kr(c), loop: 1);
	chain = FFT(b, sig);

	// Using the frombin & tobin args makes it much more efficient, limiting analysis to the bins of interest
	unp = UnpackFFT(chain, b.numFrames, frombin: 0, tobin: 4);

	// Demand some data from the unpacker.
	// NOTE: At present, Demand.kr is unable to handle more than 32 inputs,
	// so using frombin & tobin to limit the number of bins is compulsory.
	Demand.kr(chain>=0, 0, unp).collect{|anunp, index|
		anunp.poll(chain>=0, if(index % 2 == 0,  "Magnitude", "Phase")+(index/2).floor);
	};

	(sig*0.1).dup;
}.play(s);
)
x.free;

// Now a simple frequency-domain manipulation, square-rooting the magnitudes AND phases.
(
x = {
	var in, chain, magsphases;
	in = PlayBuf.ar(1, c, BufRateScale.kr(c), loop: 1);
	chain = FFT(b, in);
	magsphases = UnpackFFT(chain, b.numFrames);
	magsphases = magsphases.collect(_.sqrt);
	PackFFT(chain, b.numFrames, magsphases);
	Out.ar(0, 0.25 * IFFT(chain).dup);
}.play(s);
)
x.free;
::

