File: Goertzel.schelp

package info (click to toggle)
supercollider-sc3-plugins 3.7.1~repack-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 14,332 kB
  • ctags: 11,704
  • sloc: cpp: 140,180; lisp: 14,746; ansic: 2,133; xml: 86; makefile: 82; haskell: 21; sh: 8
file content (91 lines) | stat: -rw-r--r-- 2,956 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
CLASS:: Goertzel
summary:: Calculate a single DFT bin, to detect presence of a frequency
categories:: UGens>Filters

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.
CLASSMETHODS::
METHOD:: kr
argument::in

argument::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.
argument::freq
target frequency. This can not be modulated.
argument::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.


EXAMPLES::
code::
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;

::