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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<meta name="CocoaVersion" content="824.48">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Helvetica}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
p.p5 {margin: 0.0px 0.0px 0.0px 57.2px; text-indent: -29.5px; font: 12.0px Helvetica}
p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #a61d0e}
p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #606060}
p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #aa180d}
span.s1 {font: 18.0px Helvetica}
span.s2 {color: #0000ff}
span.s3 {color: #0022b8}
span.s4 {color: #000000}
span.s5 {color: #606060}
span.s6 {color: #001fb8}
span.s7 {color: #aa180d}
span.Apple-tab-span {white-space:pre}
</style>
</head>
<body>
<p class="p1"><span class="s1"><b>Goertzel<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></b></span><b>Calculate a single DFT bin, to detect presence of a frequency</b></p>
<p class="p2"><br></p>
<p class="p3"><b># real, imag = Goertzel.kr(in, bufsize, freq, hop)</b></p>
<p class="p2"><br></p>
<p class="p3">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.</p>
<p class="p4"><br></p>
<p class="p5"><b>bufsize</b> 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.</p>
<p class="p5"><b>freq</b> is the target frequency. This can not be modulated.</p>
<p class="p5"><b>hop</b> has the same meaning as in the <a href="SC://FFT"><span class="s2">FFT</span></a> 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.</p>
<p class="p4"><br></p>
<p class="p3">Note: The bufsize must be an exact multiple of your SC server's control block size (typically 64). The hopsize in frames (i.e. hop * bufsize) must also meet this criterion.</p>
<p class="p4"><br></p>
<p class="p4"><br></p>
<p class="p6"><b>Examples</b></p>
<p class="p4"><br></p>
<p class="p2"><br></p>
<p class="p7">s.boot</p>
<p class="p7">(</p>
<p class="p7">x = {</p>
<p class="p7"><span class="s3">var</span> freq, amp, sig, real, imag, mag, bufsize=4096;</p>
<p class="p2"><br></p>
<p class="p8">// try changing freq to a matching or nonmatching frequency to what we're looking for</p>
<p class="p8"><span class="s4">freq = 220; </span>// or try MouseY.kr(110, 440, 1);</p>
<p class="p7">amp = <span class="s3">MouseX</span>.kr;</p>
<p class="p7">sig = <span class="s3">SinOsc</span>.ar(freq, 0, amp);</p>
<p class="p7"># real, imag = <span class="s3">Goertzel</span>.kr(sig, bufsize, 220);</p>
<p class="p2"><br></p>
<p class="p8">// Calc the magnitude. We also normalise it against buffer size here.</p>
<p class="p7">mag = (real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;</p>
<p class="p2"><br></p>
<p class="p7">amp.poll(label: <span class="s5">"Input amplitude"</span>);</p>
<p class="p9"><span class="s4">mag.poll(label: </span>"Measured amplitude"<span class="s4">);</span></p>
<p class="p7">(sig * 0.1).dup</p>
<p class="p7">}.play</p>
<p class="p7">)</p>
<p class="p2"><br></p>
<p class="p7">// This one is similar but on control-rate data:</p>
<p class="p7">(</p>
<p class="p7">x = {</p>
<p class="p7"><span class="s3">var</span> freq, amp, sig, real, imag, mag, bufsize=100;</p>
<p class="p2"><br></p>
<p class="p8">// try changing freq to a matching or nonmatching frequency to what we're looking for</p>
<p class="p8"><span class="s4">freq = 22; </span>// or try MouseY.kr(11, 44, 1);</p>
<p class="p7">amp = <span class="s3">MouseX</span>.kr;</p>
<p class="p7">sig = <span class="s3">SinOsc</span>.kr(freq, 0, amp);</p>
<p class="p7"># real, imag = <span class="s3">Goertzel</span>.kr(sig, bufsize, 22);</p>
<p class="p2"><br></p>
<p class="p8">// Calc the magnitude. We also normalise it against buffer size here.</p>
<p class="p7">mag = (real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;</p>
<p class="p2"><br></p>
<p class="p7">amp.poll(label: <span class="s5">"Input amplitude"</span>);</p>
<p class="p9"><span class="s4">mag.poll(label: </span>"Measured amplitude"<span class="s4">);</span></p>
<p class="p7">(sig * 0.1).dup</p>
<p class="p7">}.play</p>
<p class="p7">)</p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p2"><br></p>
<p class="p10">// OK, now let's do a kind of spectrogram, but focused on a specific frequency region of interest</p>
<p class="p7">(</p>
<p class="p7">~binfreqs = (300, 310 .. 400);</p>
<p class="p7">w = <span class="s6">Window</span>.new.front;</p>
<p class="p7">m = <span class="s6">MultiSliderView</span>(w,<span class="s6">Rect</span>(10,10,~binfreqs.size*13+2,100)); <span class="s7">//default thumbWidth is 13</span></p>
<p class="p7">~bus = <span class="s6">Bus</span>.control(s, ~binfreqs.size);</p>
<p class="p7">x = {</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="s6">var</span> sig, mags, bufsize=4096, real, imag;</p>
<p class="p7"><span class="Apple-tab-span"> </span>sig = <span class="s6">SinOsc</span>.ar(<span class="s6">MouseX</span>.kr(~binfreqs.first, ~binfreqs.last));</p>
<p class="p7"><span class="Apple-tab-span"> </span>mags = ~binfreqs.collect{<span class="s6">|binfreq|</span></p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span># real, imag = <span class="s6">Goertzel</span>.kr(sig, bufsize, binfreq);</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>(real.squared + imag.squared).sqrt * (bufsize / 2).reciprocal;</p>
<p class="p7"><span class="Apple-tab-span"> </span>};</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="s6">Out</span>.kr(~bus, mags);</p>
<p class="p7"><span class="Apple-tab-span"> </span>(sig * 0.1).dup</p>
<p class="p7">}.play;</p>
<p class="p7">t = <span class="s6">Task</span>{</p>
<p class="p7"><span class="Apple-tab-span"> </span>loop{</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>0.1.wait;</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>~bus.getn(~binfreqs.size, {<span class="s6">|vals|</span></p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>{m.value = vals}.defer;</p>
<p class="p7"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>})</p>
<p class="p7"><span class="Apple-tab-span"> </span>}</p>
<p class="p7">}.play;</p>
<p class="p7">w.onClose_{~bus.free; x.free; t.stop; };</p>
<p class="p7">)</p>
<p class="p7">w.close;</p>
<p class="p2"><br></p>
</body>
</html>
|