comparison dsp/chromagram/ConstantQ.cpp @ 0:d7116e3183f8

* Queen Mary C++ DSP library
author cannam
date Wed, 05 Apr 2006 17:35:59 +0000
parents
children 07ac3de1e53b
comparison
equal deleted inserted replaced
-1:000000000000 0:d7116e3183f8
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3 QM DSP Library
4
5 Centre for Digital Music, Queen Mary, University of London.
6 This file copyright 2005-2006 Christian Landone.
7 All rights reserved.
8 */
9
10 #include "ConstantQ.h"
11 #include "dsp/transforms/FFT.h"
12
13 //---------------------------------------------------------------------------
14 // nextpow2 returns the smallest integer n such that 2^n >= x.
15 static double nextpow2(double x) {
16 double y = ceil(log(x)/log(2.0));
17 return(y);
18 }
19
20 static double squaredModule(const double & xx, const double & yy) {
21 return xx*xx + yy*yy;
22 }
23
24 //----------------------------------------------------------------------------
25
26 ConstantQ::ConstantQ( CQConfig Config )
27 {
28 initialise( Config );
29 }
30
31 ConstantQ::~ConstantQ()
32 {
33 deInitialise();
34 }
35
36 //----------------------------------------------------------------------------
37 void ConstantQ::sparsekernel()
38 {
39 //generates spectral kernel matrix (upside down?)
40 // initialise temporal kernel with zeros, twice length to deal w. complex numbers
41
42 double* hammingWindowRe = new double [ m_FFTLength ];
43 double* hammingWindowIm = new double [ m_FFTLength ];
44 double* transfHammingWindowRe = new double [ m_FFTLength ];
45 double* transfHammingWindowIm = new double [ m_FFTLength ];
46
47 for (unsigned u=0; u < m_FFTLength; u++)
48 {
49 hammingWindowRe[u] = 0;
50 hammingWindowIm[u] = 0;
51 }
52
53
54 // Here, fftleng*2 is a guess of the number of sparse cells in the matrix
55 // The matrix K x fftlength but the non-zero cells are an antialiased
56 // square root function. So mostly is a line, with some grey point.
57 m_sparseKernelIs.reserve( m_FFTLength*2 );
58 m_sparseKernelJs.reserve( m_FFTLength*2 );
59 m_sparseKernelRealValues.reserve( m_FFTLength*2 );
60 m_sparseKernelImagValues.reserve( m_FFTLength*2 );
61
62 // for each bin value K, calculate temporal kernel, take its fft to
63 //calculate the spectral kernel then threshold it to make it sparse and
64 //add it to the sparse kernels matrix
65 double squareThreshold = m_CQThresh * m_CQThresh;
66
67 FFT m_FFT;
68
69 for (unsigned k = m_uK; k--; )
70 {
71 // Computing a hamming window
72 const unsigned hammingLength = (int) ceil( m_dQ * m_FS / ( m_FMin * pow(2,((double)(k))/(double)m_BPO)));
73 for (unsigned i=0; i<hammingLength; i++)
74 {
75 const double angle = 2*PI*m_dQ*i/hammingLength;
76 const double real = cos(angle);
77 const double imag = sin(angle);
78 const double absol = hamming(hammingLength, i)/hammingLength;
79 hammingWindowRe[ i ] = absol*real;
80 hammingWindowIm[ i ] = absol*imag;
81 }
82
83 //do fft of hammingWindow
84 m_FFT.process( m_FFTLength, 0, hammingWindowRe, hammingWindowIm, transfHammingWindowRe, transfHammingWindowIm );
85
86
87 for (unsigned j=0; j<( m_FFTLength ); j++)
88 {
89 // perform thresholding
90 const double squaredBin = squaredModule( transfHammingWindowRe[ j ], transfHammingWindowIm[ j ]);
91 if (squaredBin <= squareThreshold) continue;
92
93 // Insert non-zero position indexes, doubled because they are floats
94 m_sparseKernelIs.push_back(j);
95 m_sparseKernelJs.push_back(k);
96
97 // take conjugate, normalise and add to array sparkernel
98 m_sparseKernelRealValues.push_back( transfHammingWindowRe[ j ]/m_FFTLength);
99 m_sparseKernelImagValues.push_back(-transfHammingWindowIm[ j ]/m_FFTLength);
100 }
101
102 }
103
104 delete [] hammingWindowRe;
105 delete [] hammingWindowIm;
106 delete [] transfHammingWindowRe;
107 delete [] transfHammingWindowIm;
108
109 }
110
111 //-----------------------------------------------------------------------------
112 double* ConstantQ::process( double* fftdata )
113 {
114 for (unsigned row=0; row<2*m_uK; row++)
115 {
116 m_CQdata[ row ] = 0;
117 m_CQdata[ row+1 ] = 0;
118 }
119 const unsigned *fftbin = &(m_sparseKernelIs[0]);
120 const unsigned *cqbin = &(m_sparseKernelJs[0]);
121 const double *real = &(m_sparseKernelRealValues[0]);
122 const double *imag = &(m_sparseKernelImagValues[0]);
123 const unsigned int sparseCells = m_sparseKernelRealValues.size();
124
125 for (unsigned i = 0; i<sparseCells; i++)
126 {
127 const unsigned row = cqbin[i];
128 const unsigned col = fftbin[i];
129 const double & r1 = real[i];
130 const double & i1 = imag[i];
131 const double & r2 = fftdata[ (2*m_FFTLength) - 2*col];
132 const double & i2 = fftdata[ (2*m_FFTLength) - 2*col+1];
133 // add the multiplication
134 m_CQdata[ 2*row ] += (r1*r2 - i1*i2);
135 m_CQdata[ 2*row+1] += (r1*i2 + i1*r2);
136 }
137
138 return m_CQdata;
139 }
140
141
142 void ConstantQ::initialise( CQConfig Config )
143 {
144 m_FS = Config.FS;
145 m_FMin = Config.min; // min freq
146 m_FMax = Config.max; // max freq
147 m_BPO = Config.BPO; // bins per octave
148 m_CQThresh = Config.CQThresh;// ConstantQ threshold for kernel generation
149
150 m_dQ = 1/(pow(2,(1/(double)m_BPO))-1); // Work out Q value for Filter bank
151 m_uK = (unsigned int) ceil(m_BPO * log(m_FMax/m_FMin)/log(2.0)); // No. of constant Q bins
152
153 // work out length of fft required for this constant Q Filter bank
154 m_FFTLength = (int) pow(2, nextpow2(ceil( m_dQ*m_FS/m_FMin )));
155
156 m_hop = m_FFTLength/8; // <------ hop size is window length divided by 32
157
158 // allocate memory for cqdata
159 m_CQdata = new double [2*m_uK];
160 }
161
162 void ConstantQ::deInitialise()
163 {
164 delete [] m_CQdata;
165 }
166
167 void ConstantQ::process(double *FFTRe, double* FFTIm, double *CQRe, double *CQIm)
168 {
169 for (unsigned row=0; row<m_uK; row++)
170 {
171 CQRe[ row ] = 0;
172 CQIm[ row ] = 0;
173 }
174
175 const unsigned *fftbin = &(m_sparseKernelIs[0]);
176 const unsigned *cqbin = &(m_sparseKernelJs[0]);
177 const double *real = &(m_sparseKernelRealValues[0]);
178 const double *imag = &(m_sparseKernelImagValues[0]);
179 const unsigned int sparseCells = m_sparseKernelRealValues.size();
180
181 for (unsigned i = 0; i<sparseCells; i++)
182 {
183 const unsigned row = cqbin[i];
184 const unsigned col = fftbin[i];
185 const double & r1 = real[i];
186 const double & i1 = imag[i];
187 const double & r2 = FFTRe[ m_FFTLength- col];
188 const double & i2 = FFTIm[ m_FFTLength - col];
189 // add the multiplication
190 CQRe[ row ] += (r1*r2 - i1*i2);
191 CQIm[ row ] += (r1*i2 + i1*r2);
192 }
193 }