SuperCollider CLASSES (extension)

Goertzel
ExtensionExtension

Calculate a single DFT bin, to detect presence of a frequency

Description

The Goertzel algorithm is a way to calculate the magnitude and phase of a signal's content at a single specified frequency. It's the equivalent of running an FFT, and then only looking at the output corresponding to a single bin. If you're only interested in a small number of bins then it is more efficient; if you're interested in the majority of bins, you typically want to do an FFT instead.

Class Methods

*kr (in: 0, bufsize: 1024, freq, hop: 1)

Arguments:

in
bufsize

used in the same way as an FFT buffer size - the larger this value, the better the frequency resolution, but the worse the time resolution.

freq

target frequency. This can not be modulated.

hop

same meaning as in the FFT UGen. Supply a value between zero and one, for the amount of overlap between Goertzel "frames". The default is a hop of 1 (meaning no overlap between frames). If you specify 0.5 then the analysis value will be produced twice as often; 0.25, four times as often.

Inherited class methods

Instance Methods

Inherited instance methods

Examples

s.boot
(
x = {
var freq, amp, sig, real, imag, mag, bufsize=4096;

// try changing freq to a matching or nonmatching frequency to what we're looking for
freq = 220; // or try MouseY.kr(110, 440, 1);
amp = MouseX.kr;
sig = SinOsc.ar(freq, 0, amp);
# real, imag = Goertzel.kr(sig, bufsize, 220);

// Calc the magnitude. We also normalise it against buffer size here.
mag = (real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;

amp.poll(label: "Input amplitude");
mag.poll(label: "Measured amplitude");
(sig * 0.1).dup
}.play
)

// This one is similar but on control-rate data:
(
x = {
var freq, amp, sig, real, imag, mag, bufsize=100;

// try changing freq to a matching or nonmatching frequency to what we're looking for
freq = 22; // or try MouseY.kr(11, 44, 1);
amp = MouseX.kr;
sig = SinOsc.kr(freq, 0, amp);
# real, imag = Goertzel.kr(sig, bufsize, 22);

// Calc the magnitude. We also normalise it against buffer size here.
mag = (real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;

amp.poll(label: "Input amplitude");
mag.poll(label: "Measured amplitude");
(sig * 0.1).dup
}.play
)


// OK, now let's do a kind of spectrogram, but focused on a specific frequency region of interest
(
~binfreqs = (300, 310 .. 400);
w = Window.new.front;
m = MultiSliderView(w,Rect(10,10,~binfreqs.size*13+2,100)); //default thumbWidth is 13
~bus = Bus.control(s, ~binfreqs.size);
x = {
var sig, mags, bufsize=4096, real, imag;
sig = SinOsc.ar(MouseX.kr(~binfreqs.first, ~binfreqs.last));
mags = ~binfreqs.collect{|binfreq|
# real, imag = Goertzel.kr(sig, bufsize, binfreq);
(real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;
};
Out.kr(~bus, mags);
(sig * 0.1).dup
}.play;
t = Task{
loop{
0.1.wait;
~bus.getn(~binfreqs.size, {|vals|
{m.value = vals}.defer;
})
}
}.play;
w.onClose_{~bus.free; x.free; t.stop; };
)
w.close;