comparison constant-q-cpp/misc/yeti/icqt.yeti @ 366:5d0a2ebb4d17

Bring dependent libraries in to repo
author Chris Cannam
date Fri, 24 Jun 2016 14:47:45 +0100
parents
children
comparison
equal deleted inserted replaced
365:112766f4c34b 366:5d0a2ebb4d17
1 /*
2 Constant-Q library
3 Copyright (c) 2013-2014 Queen Mary, University of London
4
5 Permission is hereby granted, free of charge, to any person
6 obtaining a copy of this software and associated documentation
7 files (the "Software"), to deal in the Software without
8 restriction, including without limitation the rights to use, copy,
9 modify, merge, publish, distribute, sublicense, and/or sell copies
10 of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the names of the Centre for
25 Digital Music; Queen Mary, University of London; and Chris Cannam
26 shall not be used in advertising or otherwise to promote the sale,
27 use or other dealings in this Software without prior written
28 authorization.
29 */
30
31 module icqt;
32
33 cqt = load cqt;
34 cm = load may.matrix.complex;
35 framer = load may.stream.framer;
36 win = load may.signal.window;
37 mm = load may.mathmisc;
38 vec = load may.vector;
39 resamp = load may.stream.resample;
40 manip = load may.stream.manipulate;
41 mat = load may.matrix;
42
43 icqt cq =
44 (kdata = cq.kernel;
45
46 // kdata.kernel is the kernel matrix for a single octave. It has
47 // width kdata.fftSize and height kdata.binsPerOctave *
48 // kdata.atomsPerFrame.
49 //
50 // kdata.fftHop is the overlap between kernel matrices in a single
51 // octave.
52 //
53 // cq.sampleRate is the output stream sample rate and cq.octaves
54 // the number of octaves.
55 //
56 // cq.cqComplex is the list of complex matrices containing the CQ
57 // output. Each has width kdata.atomsPerFrame * 2^(cq.octaves-1)
58 // and height kdata.binsPerOctave * cq.octaves.
59
60 bpo = kdata.binsPerOctave;
61 atomsPerFrame = kdata.atomsPerFrame;
62 octaves = cq.octaves;
63
64 // transform a single block, all octaves tall, into an array
65 // (indexed by octave) of lists of individual columns (valid
66 // values for that octave only)
67 decomposeOctaves mat = array
68 (map do oct:
69 inverted = cm.fromRows (reverse (cm.asRows mat));
70 octMat = cm.rowSlice inverted (bpo * oct) (bpo * (oct + 1));
71 gap = (mm.pow 2 oct) - 1;
72 pickFrom cols =
73 case cols of
74 c::cs: c::(pickFrom (drop gap cs));
75 _: [];
76 esac;
77 pickFrom (cm.asColumns octMat);
78 done [0..octaves-1]);
79
80 // transform a list of the arrays produced by decomposeOctaves
81 // into a single array (indexed by octave) of lists of the
82 // individual columns
83 flattenOctaves decomposed =
84 (flattenAux acc decomposed =
85 case decomposed of
86 chunk::rest:
87 flattenAux
88 (array
89 (map do oct:
90 acc[oct] ++ chunk[oct]
91 done [0..octaves-1]))
92 rest;
93 _: acc;
94 esac;
95 flattenAux (array (map \[] [0..octaves-1])) decomposed);
96
97 // given a list of columns, deinterleave and pile up each sequence
98 // of atomsPerFrame columns into a single tall column and return
99 // the resulting list of tall columns
100 pile cols =
101 (pileAux acc cols =
102 if (length cols) >= atomsPerFrame then
103 atoms = take atomsPerFrame cols;
104 juggled = concat (reverse (cm.asRows (cm.fromColumns atoms)));
105 pileAux (juggled :: acc) (drop atomsPerFrame cols);
106 else
107 reverse acc
108 fi;
109 pileAux [] cols);
110
111 octaveColumnLists =
112 map pile (list (flattenOctaves (map decomposeOctaves cq.cqComplex)));
113
114 for octaveColumnLists do l: println "octave column list length: \(length l)" done;
115
116 kernel = cm.transposed kdata.kernel; // right way around for the multiply
117
118 spectra =
119 map do l:
120 map do col:
121 res = cm.transposed (cm.product kernel (cm.newComplexColumnVector col));
122 cm.columnSlice res 0 (kdata.fftSize / 2 + 1)
123 done l;
124 done octaveColumnLists;
125
126 eprintln "calculated spectra, now to ifft, overlap-add...";
127
128 rates = map do oct: cq.sampleRate / (mm.pow 2 oct) done [0..cq.octaves-1];
129
130 resynthesised =
131 map2 do frames rate:
132 framer.complexStreamed rate kdata.fftSize
133 [ FrequencyDomain true, Window win.boxcar, Hop kdata.fftHop ]
134 frames;
135 done spectra rates;
136
137 eprintln "have streams:";
138 for resynthesised eprintln;
139
140 resampled = map (resamp.resampledTo cq.sampleRate) resynthesised;
141
142 manip.sum resampled;
143 );
144
145 {icqt}