comparison dsp/chromagram/ConstantQ.cpp @ 276:4c901426b9f3

* 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 Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 04 Dec 2008 11:59:29 +0000
parents 715b0a6bcdc0
children 6cb2b3cd5356
comparison
equal deleted inserted replaced
275:cded679e12c2 276:4c901426b9f3
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];