Mercurial > hg > qm-dsp
comparison dsp/chromagram/ConstantQ.cpp @ 51:114e833c07ac
* Do not calculate CQ sparse kernel when chromagram is constructed: only
when it's actually used
* Pre-calculate CQ sparse kernels in the sizes required for the default
configurations of some of our transforms
author | cannam |
---|---|
date | Thu, 04 Dec 2008 11:59:29 +0000 |
parents | 3dff6e3e2121 |
children | 6cb2b3cd5356 |
comparison
equal
deleted
inserted
replaced
50:980b1a3b9cbe | 51:114e833c07ac |
---|---|
9 | 9 |
10 #include "ConstantQ.h" | 10 #include "ConstantQ.h" |
11 #include "dsp/transforms/FFT.h" | 11 #include "dsp/transforms/FFT.h" |
12 | 12 |
13 #include <iostream> | 13 #include <iostream> |
14 | |
15 #include "CQprecalc.cpp" | |
16 | |
17 static bool push_precalculated(int uk, int fftlength, | |
18 std::vector<unsigned> &is, | |
19 std::vector<unsigned> &js, | |
20 std::vector<double> &real, | |
21 std::vector<double> &imag) | |
22 { | |
23 if (uk == 76 && fftlength == 16384) { | |
24 push_76_16384(is, js, real, imag); | |
25 return true; | |
26 } | |
27 if (uk == 144 && fftlength == 4096) { | |
28 push_144_4096(is, js, real, imag); | |
29 return true; | |
30 } | |
31 if (uk == 65 && fftlength == 2048) { | |
32 push_65_2048(is, js, real, imag); | |
33 return true; | |
34 } | |
35 if (uk == 84 && fftlength == 65536) { | |
36 push_84_65536(is, js, real, imag); | |
37 return true; | |
38 } | |
39 return false; | |
40 } | |
14 | 41 |
15 //--------------------------------------------------------------------------- | 42 //--------------------------------------------------------------------------- |
16 // nextpow2 returns the smallest integer n such that 2^n >= x. | 43 // nextpow2 returns the smallest integer n such that 2^n >= x. |
17 static double nextpow2(double x) { | 44 static double nextpow2(double x) { |
18 double y = ceil(log(x)/log(2.0)); | 45 double y = ceil(log(x)/log(2.0)); |
23 return xx*xx + yy*yy; | 50 return xx*xx + yy*yy; |
24 } | 51 } |
25 | 52 |
26 //---------------------------------------------------------------------------- | 53 //---------------------------------------------------------------------------- |
27 | 54 |
28 ConstantQ::ConstantQ( CQConfig Config ) | 55 ConstantQ::ConstantQ( CQConfig Config ) : |
56 m_sparseKernel(0) | |
29 { | 57 { |
30 initialise( Config ); | 58 initialise( Config ); |
31 } | 59 } |
32 | 60 |
33 ConstantQ::~ConstantQ() | 61 ConstantQ::~ConstantQ() |
36 } | 64 } |
37 | 65 |
38 //---------------------------------------------------------------------------- | 66 //---------------------------------------------------------------------------- |
39 void ConstantQ::sparsekernel() | 67 void ConstantQ::sparsekernel() |
40 { | 68 { |
69 // std::cerr << "ConstantQ: initialising sparse kernel, uK = " << m_uK << ", FFTLength = " << m_FFTLength << "..."; | |
70 | |
71 SparseKernel *sk = new SparseKernel(); | |
72 | |
73 if (push_precalculated(m_uK, m_FFTLength, | |
74 sk->is, sk->js, sk->real, sk->imag)) { | |
75 m_sparseKernel = sk; | |
76 return; | |
77 } | |
78 | |
41 //generates spectral kernel matrix (upside down?) | 79 //generates spectral kernel matrix (upside down?) |
42 // initialise temporal kernel with zeros, twice length to deal w. complex numbers | 80 // initialise temporal kernel with zeros, twice length to deal w. complex numbers |
43 | 81 |
44 double* hammingWindowRe = new double [ m_FFTLength ]; | 82 double* hammingWindowRe = new double [ m_FFTLength ]; |
45 double* hammingWindowIm = new double [ m_FFTLength ]; | 83 double* hammingWindowIm = new double [ m_FFTLength ]; |
50 { | 88 { |
51 hammingWindowRe[u] = 0; | 89 hammingWindowRe[u] = 0; |
52 hammingWindowIm[u] = 0; | 90 hammingWindowIm[u] = 0; |
53 } | 91 } |
54 | 92 |
55 | |
56 // Here, fftleng*2 is a guess of the number of sparse cells in the matrix | 93 // Here, fftleng*2 is a guess of the number of sparse cells in the matrix |
57 // The matrix K x fftlength but the non-zero cells are an antialiased | 94 // The matrix K x fftlength but the non-zero cells are an antialiased |
58 // square root function. So mostly is a line, with some grey point. | 95 // square root function. So mostly is a line, with some grey point. |
59 m_sparseKernelIs.reserve( m_FFTLength*2 ); | 96 sk->is.reserve( m_FFTLength*2 ); |
60 m_sparseKernelJs.reserve( m_FFTLength*2 ); | 97 sk->js.reserve( m_FFTLength*2 ); |
61 m_sparseKernelRealValues.reserve( m_FFTLength*2 ); | 98 sk->real.reserve( m_FFTLength*2 ); |
62 m_sparseKernelImagValues.reserve( m_FFTLength*2 ); | 99 sk->imag.reserve( m_FFTLength*2 ); |
63 | 100 |
64 // for each bin value K, calculate temporal kernel, take its fft to | 101 // for each bin value K, calculate temporal kernel, take its fft to |
65 //calculate the spectral kernel then threshold it to make it sparse and | 102 //calculate the spectral kernel then threshold it to make it sparse and |
66 //add it to the sparse kernels matrix | 103 //add it to the sparse kernels matrix |
67 double squareThreshold = m_CQThresh * m_CQThresh; | 104 double squareThreshold = m_CQThresh * m_CQThresh; |
109 // perform thresholding | 146 // perform thresholding |
110 const double squaredBin = squaredModule( transfHammingWindowRe[ j ], transfHammingWindowIm[ j ]); | 147 const double squaredBin = squaredModule( transfHammingWindowRe[ j ], transfHammingWindowIm[ j ]); |
111 if (squaredBin <= squareThreshold) continue; | 148 if (squaredBin <= squareThreshold) continue; |
112 | 149 |
113 // Insert non-zero position indexes, doubled because they are floats | 150 // Insert non-zero position indexes, doubled because they are floats |
114 m_sparseKernelIs.push_back(j); | 151 sk->is.push_back(j); |
115 m_sparseKernelJs.push_back(k); | 152 sk->js.push_back(k); |
116 | 153 |
117 // take conjugate, normalise and add to array sparkernel | 154 // take conjugate, normalise and add to array sparkernel |
118 m_sparseKernelRealValues.push_back( transfHammingWindowRe[ j ]/m_FFTLength); | 155 sk->real.push_back( transfHammingWindowRe[ j ]/m_FFTLength); |
119 m_sparseKernelImagValues.push_back(-transfHammingWindowIm[ j ]/m_FFTLength); | 156 sk->imag.push_back(-transfHammingWindowIm[ j ]/m_FFTLength); |
120 } | 157 } |
121 | 158 |
122 } | 159 } |
123 | 160 |
124 delete [] hammingWindowRe; | 161 delete [] hammingWindowRe; |
125 delete [] hammingWindowIm; | 162 delete [] hammingWindowIm; |
126 delete [] transfHammingWindowRe; | 163 delete [] transfHammingWindowRe; |
127 delete [] transfHammingWindowIm; | 164 delete [] transfHammingWindowIm; |
128 | 165 |
166 /* | |
167 using std::cout; | |
168 using std::endl; | |
169 | |
170 cout.precision(28); | |
171 | |
172 int n = sk->is.size(); | |
173 int w = 8; | |
174 cout << "static unsigned int sk_i_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; | |
175 for (int i = 0; i < n; ++i) { | |
176 if (i % w == 0) cout << " "; | |
177 cout << sk->is[i]; | |
178 if (i + 1 < n) cout << ", "; | |
179 if (i % w == w-1) cout << endl; | |
180 }; | |
181 if (n % w != 0) cout << endl; | |
182 cout << "};" << endl; | |
183 | |
184 n = sk->js.size(); | |
185 cout << "static unsigned int sk_j_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; | |
186 for (int i = 0; i < n; ++i) { | |
187 if (i % w == 0) cout << " "; | |
188 cout << sk->js[i]; | |
189 if (i + 1 < n) cout << ", "; | |
190 if (i % w == w-1) cout << endl; | |
191 }; | |
192 if (n % w != 0) cout << endl; | |
193 cout << "};" << endl; | |
194 | |
195 w = 2; | |
196 n = sk->real.size(); | |
197 cout << "static double sk_real_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; | |
198 for (int i = 0; i < n; ++i) { | |
199 if (i % w == 0) cout << " "; | |
200 cout << sk->real[i]; | |
201 if (i + 1 < n) cout << ", "; | |
202 if (i % w == w-1) cout << endl; | |
203 }; | |
204 if (n % w != 0) cout << endl; | |
205 cout << "};" << endl; | |
206 | |
207 n = sk->imag.size(); | |
208 cout << "static double sk_imag_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; | |
209 for (int i = 0; i < n; ++i) { | |
210 if (i % w == 0) cout << " "; | |
211 cout << sk->imag[i]; | |
212 if (i + 1 < n) cout << ", "; | |
213 if (i % w == w-1) cout << endl; | |
214 }; | |
215 if (n % w != 0) cout << endl; | |
216 cout << "};" << endl; | |
217 | |
218 cout << "static void push_" << m_uK << "_" << m_FFTLength << "(vector<unsigned int> &is, vector<unsigned int> &js, vector<double> &real, vector<double> &imag)" << endl; | |
219 cout << "{\n is.reserve(" << n << ");\n"; | |
220 cout << " js.reserve(" << n << ");\n"; | |
221 cout << " real.reserve(" << n << ");\n"; | |
222 cout << " imag.reserve(" << n << ");\n"; | |
223 cout << " for (int i = 0; i < " << n << "; ++i) {" << endl; | |
224 cout << " is.push_back(sk_i_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; | |
225 cout << " js.push_back(sk_j_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; | |
226 cout << " real.push_back(sk_real_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; | |
227 cout << " imag.push_back(sk_imag_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; | |
228 cout << " }" << endl; | |
229 cout << "}" << endl; | |
230 */ | |
231 // std::cerr << "done\n -> is: " << sk->is.size() << ", js: " << sk->js.size() << ", reals: " << sk->real.size() << ", imags: " << sk->imag.size() << std::endl; | |
232 | |
233 m_sparseKernel = sk; | |
234 return; | |
129 } | 235 } |
130 | 236 |
131 //----------------------------------------------------------------------------- | 237 //----------------------------------------------------------------------------- |
132 double* ConstantQ::process( const double* fftdata ) | 238 double* ConstantQ::process( const double* fftdata ) |
133 { | 239 { |
240 if (!m_sparseKernel) { | |
241 std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl; | |
242 return m_CQdata; | |
243 } | |
244 | |
245 SparseKernel *sk = m_sparseKernel; | |
246 | |
134 for (unsigned row=0; row<2*m_uK; row++) | 247 for (unsigned row=0; row<2*m_uK; row++) |
135 { | 248 { |
136 m_CQdata[ row ] = 0; | 249 m_CQdata[ row ] = 0; |
137 m_CQdata[ row+1 ] = 0; | 250 m_CQdata[ row+1 ] = 0; |
138 } | 251 } |
139 const unsigned *fftbin = &(m_sparseKernelIs[0]); | 252 const unsigned *fftbin = &(sk->is[0]); |
140 const unsigned *cqbin = &(m_sparseKernelJs[0]); | 253 const unsigned *cqbin = &(sk->js[0]); |
141 const double *real = &(m_sparseKernelRealValues[0]); | 254 const double *real = &(sk->real[0]); |
142 const double *imag = &(m_sparseKernelImagValues[0]); | 255 const double *imag = &(sk->imag[0]); |
143 const unsigned int sparseCells = m_sparseKernelRealValues.size(); | 256 const unsigned int sparseCells = sk->real.size(); |
144 | 257 |
145 for (unsigned i = 0; i<sparseCells; i++) | 258 for (unsigned i = 0; i<sparseCells; i++) |
146 { | 259 { |
147 const unsigned row = cqbin[i]; | 260 const unsigned row = cqbin[i]; |
148 const unsigned col = fftbin[i]; | 261 const unsigned col = fftbin[i]; |
184 } | 297 } |
185 | 298 |
186 void ConstantQ::deInitialise() | 299 void ConstantQ::deInitialise() |
187 { | 300 { |
188 delete [] m_CQdata; | 301 delete [] m_CQdata; |
302 delete m_sparseKernel; | |
189 } | 303 } |
190 | 304 |
191 void ConstantQ::process(const double *FFTRe, const double* FFTIm, | 305 void ConstantQ::process(const double *FFTRe, const double* FFTIm, |
192 double *CQRe, double *CQIm) | 306 double *CQRe, double *CQIm) |
193 { | 307 { |
308 if (!m_sparseKernel) { | |
309 std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl; | |
310 return; | |
311 } | |
312 | |
313 SparseKernel *sk = m_sparseKernel; | |
314 | |
194 for (unsigned row=0; row<m_uK; row++) | 315 for (unsigned row=0; row<m_uK; row++) |
195 { | 316 { |
196 CQRe[ row ] = 0; | 317 CQRe[ row ] = 0; |
197 CQIm[ row ] = 0; | 318 CQIm[ row ] = 0; |
198 } | 319 } |
199 | 320 |
200 const unsigned *fftbin = &(m_sparseKernelIs[0]); | 321 const unsigned *fftbin = &(sk->is[0]); |
201 const unsigned *cqbin = &(m_sparseKernelJs[0]); | 322 const unsigned *cqbin = &(sk->js[0]); |
202 const double *real = &(m_sparseKernelRealValues[0]); | 323 const double *real = &(sk->real[0]); |
203 const double *imag = &(m_sparseKernelImagValues[0]); | 324 const double *imag = &(sk->imag[0]); |
204 const unsigned int sparseCells = m_sparseKernelRealValues.size(); | 325 const unsigned int sparseCells = sk->real.size(); |
205 | 326 |
206 for (unsigned i = 0; i<sparseCells; i++) | 327 for (unsigned i = 0; i<sparseCells; i++) |
207 { | 328 { |
208 const unsigned row = cqbin[i]; | 329 const unsigned row = cqbin[i]; |
209 const unsigned col = fftbin[i]; | 330 const unsigned col = fftbin[i]; |