Goertzel Calculate a single DFT bin, to detect presence of a frequency
# real, imag = Goertzel.kr(in, bufsize, freq)
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.
The bufsize is 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. The freq is the target frequency. This can not be modulated.
Note: The bufsize must be an exact multiple of your SC server's control block size (typically 64).
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;