FFTSubbandPower - Spectral power, divided into subbands

#[power1, power2, ... powerN+1] = FFTSubbandPower.kr(chain, [cutfreq1, cutfreq2, ... cutfreqN], square)

Calculates the spectral power measure, in the same manner as FFTPower, but divides the spectrum into (adjacent, non-overlapping) subbands, so returns separate power measures for the different subbands.

The cutfreqs parameter must be an array of frequencies. For example, to divide a 44100Hz signal into three subbands we might specify [ 5512, 11025 ] as the cutfreqs, giving subbands of 0-5512Hz, 5512-11025Hz, and 11025-22050Hz. (Frequencies above the Nyquist frequency are not included.)

The third parameter square performs the same role as in FFTPower. (The normalisation is also the same as FFTPower, meaning the sum of the outputs of this unit should be the same as that of FFTPower, in either mode.)

cutfreqs and square can only be specified on initialisation - they can't be modulated.

Examples

// Simple example

s = Server.local.boot; //Server.internal.boot;

b = Buffer.alloc(s,2048,1);

(

x = {

var in, chain, powers, cutfreqs;

in = LPF.ar(WhiteNoise.ar, MouseX.kr(10,10000, 1));

chain = FFT(b.bufnum, in);

powers = FFTSubbandPower.kr(chain, [100, 200, 400, 800, 1600, 3200, 6400, 12800]);

Out.ar(0, in * 0.1);

powers.collect{|pow, index| pow.poll(label: "band"+index)};

powers.sum.poll(label: "sum");

}.play(s);

)

x.free;

In this next example we create a graphic EQ meter. The subband power measurements are written out to a control bus, then on the language side we create a task which polls the values and updates a multi-slider to display the power distribution in the familiar home hi-fi style.

s = Server.local.boot;

b = Buffer.alloc(s,2048,1);

(

var win, size=8;

c = Bus.control(s, size); // Values will be written to control busses

win = SCWindow("EQ meter", Rect(100, 200, 360, 110));

~slider = SCMultiSliderView(win, Rect(0, 0, 350, 100));

~slider.value_(0.dup(size)).size_(size).isFilled_(true).indexThumbSize_(350/8);

win.front;

)

(

var size=8;

x = {

var in, chain, powers, cutfreqs;

in = BPF.ar(WhiteNoise.ar, MouseX.kr(10,14000, 1), MouseY.kr(0.1, 2, 1));

chain = FFT(b.bufnum, in);

cutfreqs = [100, 200, 400, 800, 1600, 3200, 6400];

powers = FFTSubbandPower.kr(chain, cutfreqs, 1);

powers = powers * #[32, 32, 16, 8, 4, 2, 1, 1]; // the subbands are different widths so we scale them to match (divide by width)

Out.ar(0, (in * 0.1).dup);

Out.kr(c.index, powers);

}.play(s);

t = Task({

loop{

0.1.wait;

c.getn(size, {|vals| {

~slider.value_((vals.log2 + 7 * 0.1).max(0).min(1));

}.defer});

};

}).start;

)

x.free;

t.stop;