annotate yeti/cqtkernel.yeti @ 3:53711c07ae3f

Generate the actual kernels
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 24 Oct 2013 14:43:36 +0100
parents 0106107cb972
children e026003433e5
rev   line source
c@1 1
c@1 2 module cqtkernel;
c@1 3
c@3 4 vec = load may.vector;
c@3 5 bf = load may.vector.blockfuncs;
c@3 6 complex = load may.complex;
c@3 7 window = load may.signal.window;
c@3 8 fft = load may.transform.fft;
c@3 9
c@2 10 { pow, round, floor, ceil, nextPowerOfTwo } = load may.mathmisc;
c@1 11
c@1 12 fs = 48000;
c@1 13
c@1 14 fmax = fs/2;
c@1 15
c@1 16 bins = 24;
c@1 17
c@1 18 q = 1;
c@1 19
c@1 20 atomHopFactor = 0.25;
c@1 21
c@1 22 thresh = 0.0005;
c@1 23
c@1 24 fmin = (fmax/2) * (pow 2 (1/bins));
c@1 25
c@1 26 bigQ = q / ((pow 2 (1/bins)) - 1);
c@1 27
c@1 28 nk_max = round(bigQ * fs / fmin);
c@1 29
c@1 30 nk_min = round(bigQ * fs / (fmin * (pow 2 ((bins-1)/bins))));
c@1 31
c@1 32 atomHop = round(nk_min * atomHopFactor);
c@1 33
c@1 34 first_center = atomHop * Math#ceil(Math#ceil(nk_max/2) / atomHop);
c@1 35
c@1 36 fftLen = nextPowerOfTwo (first_center + Math#ceil(nk_max/2));
c@1 37
c@1 38 println "fs = \(fs), fmax = \(fmax), bins = \(bins), q = \(q), atomHopFactor = \(atomHopFactor), thresh = \(thresh)";
c@1 39
c@1 40 println "fmin = \(fmin), bigQ = \(bigQ), nk_max = \(nk_max), nk_min = \(nk_min), atomHop = \(atomHop), first_center = \(first_center), fftLen = \(fftLen)";
c@1 41
c@2 42 winNr = floor((fftLen - ceil(nk_max/2) - first_center) / atomHop) + 1;
c@2 43
c@2 44 last_center = first_center + (winNr - 1) * atomHop;
c@2 45
c@2 46 fftHop = (last_center + atomHop) - first_center;
c@2 47
c@2 48 fftOverlap = ((fftLen - fftHop) / fftLen) * 100; // as % -- why? just for diagnostics?
c@2 49
c@2 50 println "winNr = \(winNr), last_center = \(last_center), fftHop = \(fftHop), fftOverlap = \(fftOverlap)%";
c@2 51
c@3 52 fftFunc = fft.forward fftLen;
c@2 53
c@3 54 // Note the MATLAB uses exp(2*pi*1i*x) for a complex generating
c@3 55 // function. We can't do that here; we need to generate real and imag
c@3 56 // parts separately as real = cos(2*pi*x), imag = sin(2*pi*x).
c@2 57
c@3 58 kernels = map do k:
c@3 59
c@3 60 nk = round(bigQ * fs / (fmin * (pow 2 ((k-1)/bins))));
c@3 61 println "k = \(k) -> nk = \(nk)";
c@3 62
c@3 63 win = bf.divideBy nk (bf.sqrt (window.blackmanHarris nk));
c@3 64
c@3 65 fk = fmin * (pow 2 ((k-1)/bins));
c@3 66
c@3 67 println "fk = \(fk)";
c@3 68
c@3 69 genKernel f = bf.multiply win
c@3 70 (vec.fromList (map do i: f (2 * pi * fk * i / fs) done [0..nk-1]));
c@3 71
c@3 72 reals = genKernel cos;
c@3 73 imags = genKernel sin;
c@3 74
c@3 75 atomOffset = first_center - ceil(nk/2);
c@3 76
c@3 77 map do i:
c@3 78
c@3 79 shift = atomOffset + ((i-1) * atomHop);
c@3 80
c@3 81 specKernel = fftFunc
c@3 82 (complex.complexArray
c@3 83 (vec.concat [vec.zeros shift, reals])
c@3 84 (vec.concat [vec.zeros shift, imags]));
c@3 85
c@3 86 map do c:
c@3 87 if complex.magnitude c < thresh then complex.zero else c fi
c@3 88 done specKernel;
c@3 89
c@3 90 done [1..winNr];
c@3 91
c@3 92 done [1..bins];
c@3 93
c@3 94 println "kernels = \(kernels)";
c@2 95
c@1 96 ();
c@1 97