ConstantQ.cpp
Go to the documentation of this file.
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 2005-2006 Christian Landone.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 #include "ConstantQ.h"
16 #include "dsp/transforms/FFT.h"
17 #include "base/Window.h"
18 
19 #include <iostream>
20 
21 //----------------------------------------------------------------------------
22 
24  m_sparseKernel(0)
25 {
26  initialise(config);
27 }
28 
30 {
31  deInitialise();
32 }
33 
34 static double squaredModule(const double & xx, const double & yy) {
35  return xx*xx + yy*yy;
36 }
37 
39 {
40  SparseKernel *sk = new SparseKernel();
41 
42  double* windowRe = new double [ m_FFTLength ];
43  double* windowIm = new double [ m_FFTLength ];
44  double* transfWindowRe = new double [ m_FFTLength ];
45  double* transfWindowIm = new double [ m_FFTLength ];
46 
47  // for each bin value K, calculate temporal kernel, take its fft
48  // to calculate the spectral kernel then threshold it to make it
49  // sparse and add it to the sparse kernels matrix
50 
51  double squareThreshold = m_CQThresh * m_CQThresh;
52 
53  FFT fft(m_FFTLength);
54 
55  for (int j = m_uK - 1; j >= 0; --j) {
56 
57  for (int i = 0; i < m_FFTLength; ++i) {
58  windowRe[i] = 0;
59  windowIm[i] = 0;
60  }
61 
62  // Compute a complex sinusoid windowed with a hamming window
63  // of the right length
64 
65  int windowLength = (int)ceil
66  (m_dQ * m_FS / (m_FMin * pow(2, (double)j / (double)m_BPO)));
67 
68  int origin = m_FFTLength/2 - windowLength/2;
69 
70  for (int i = 0; i < windowLength; ++i) {
71  double angle = (2.0 * M_PI * m_dQ * i) / windowLength;
72  windowRe[origin + i] = cos(angle);
73  windowIm[origin + i] = sin(angle);
74  }
75 
76  // Shape with hamming window
77  Window<double> hamming(HammingWindow, windowLength);
78  hamming.cut(windowRe + origin);
79  hamming.cut(windowIm + origin);
80 
81  // Scale
82  for (int i = 0; i < windowLength; ++i) {
83  windowRe[origin + i] /= windowLength;
84  }
85  for (int i = 0; i < windowLength; ++i) {
86  windowIm[origin + i] /= windowLength;
87  }
88 
89  // Input is expected to have been fftshifted, so do the
90  // same to the input to the fft that contains the kernel
91  for (int i = 0; i < m_FFTLength/2; ++i) {
92  double temp = windowRe[i];
93  windowRe[i] = windowRe[i + m_FFTLength/2];
94  windowRe[i + m_FFTLength/2] = temp;
95  }
96  for (int i = 0; i < m_FFTLength/2; ++i) {
97  double temp = windowIm[i];
98  windowIm[i] = windowIm[i + m_FFTLength/2];
99  windowIm[i + m_FFTLength/2] = temp;
100  }
101 
102  fft.process(false, windowRe, windowIm, transfWindowRe, transfWindowIm);
103 
104  // convert to sparse form
105  for (int i = 0; i < m_FFTLength; i++) {
106 
107  // perform thresholding
108  double mag = squaredModule(transfWindowRe[i], transfWindowIm[i]);
109  if (mag <= squareThreshold) continue;
110 
111  // Insert non-zero position indexes
112  sk->is.push_back(i);
113  sk->js.push_back(j);
114 
115  // take conjugate, normalise and add to array for sparse kernel
116  sk->real.push_back( transfWindowRe[i] / m_FFTLength);
117  sk->imag.push_back(-transfWindowIm[i] / m_FFTLength);
118  }
119  }
120 
121  delete [] windowRe;
122  delete [] windowIm;
123  delete [] transfWindowRe;
124  delete [] transfWindowIm;
125 
126  m_sparseKernel = sk;
127 }
128 
130 {
131  m_FS = Config.FS; // Sample rate
132  m_FMin = Config.min; // Minimum frequency
133  m_FMax = Config.max; // Maximum frequency
134  m_BPO = Config.BPO; // Bins per octave
135  m_CQThresh = Config.CQThresh; // Threshold for sparse kernel generation
136 
137  // Q value for filter bank
138  m_dQ = 1/(pow(2,(1/(double)m_BPO))-1);
139 
140  // No. of constant Q bins
141  m_uK = (int)ceil(m_BPO * log(m_FMax/m_FMin)/log(2.0));
142 
143  // Length of fft required for this Constant Q filter bank
145 
146  // Hop from one frame to next
147  m_hop = m_FFTLength / 8;
148 
149  // allocate memory for cqdata
150  m_CQdata = new double [2*m_uK];
151 }
152 
154 {
155  delete [] m_CQdata;
156  delete m_sparseKernel;
157 }
158 
159 //-----------------------------------------------------------------------------
160 double* ConstantQ::process( const double* fftdata )
161 {
162  if (!m_sparseKernel) {
163  std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl;
164  return m_CQdata;
165  }
166 
168 
169  for (int row=0; row < 2 * m_uK; row++) {
170  m_CQdata[ row ] = 0;
171  m_CQdata[ row+1 ] = 0;
172  }
173  const int *fftbin = &(sk->is[0]);
174  const int *cqbin = &(sk->js[0]);
175  const double *real = &(sk->real[0]);
176  const double *imag = &(sk->imag[0]);
177  const int sparseCells = int(sk->real.size());
178 
179  for (int i = 0; i < sparseCells; i++) {
180  const int row = cqbin[i];
181  const int col = fftbin[i];
182  if (col == 0) continue;
183  const double & r1 = real[i];
184  const double & i1 = imag[i];
185  const double & r2 = fftdata[ (2*m_FFTLength) - 2*col - 2 ];
186  const double & i2 = fftdata[ (2*m_FFTLength) - 2*col - 2 + 1 ];
187  // add the multiplication
188  m_CQdata[ 2*row ] += (r1*r2 - i1*i2);
189  m_CQdata[ 2*row+1] += (r1*i2 + i1*r2);
190  }
191 
192  return m_CQdata;
193 }
194 
195 void ConstantQ::process(const double *FFTRe, const double* FFTIm,
196  double *CQRe, double *CQIm)
197 {
198  if (!m_sparseKernel) {
199  std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl;
200  return;
201  }
202 
204 
205  for (int row = 0; row < m_uK; row++) {
206  CQRe[ row ] = 0;
207  CQIm[ row ] = 0;
208  }
209 
210  const int *fftbin = &(sk->is[0]);
211  const int *cqbin = &(sk->js[0]);
212  const double *real = &(sk->real[0]);
213  const double *imag = &(sk->imag[0]);
214  const int sparseCells = int(sk->real.size());
215 
216  for (int i = 0; i<sparseCells; i++) {
217  const int row = cqbin[i];
218  const int col = fftbin[i];
219  if (col == 0) continue;
220  const double & r1 = real[i];
221  const double & i1 = imag[i];
222  const double & r2 = FFTRe[ m_FFTLength - col ];
223  const double & i2 = FFTIm[ m_FFTLength - col ];
224  // add the multiplication
225  CQRe[ row ] += (r1*r2 - i1*i2);
226  CQIm[ row ] += (r1*i2 + i1*r2);
227  }
228 }
int m_FFTLength
Definition: ConstantQ.h:61
std::vector< double > real
Definition: ConstantQ.h:68
void process(const double *FFTRe, const double *FFTIm, double *CQRe, double *CQIm)
Definition: ConstantQ.cpp:195
double CQThresh
Definition: ConstantQ.h:28
double m_dQ
Definition: ConstantQ.h:57
int BPO
Definition: ConstantQ.h:27
double FS
Definition: ConstantQ.h:24
static double squaredModule(const double &xx, const double &yy)
Definition: ConstantQ.cpp:34
SparseKernel * m_sparseKernel
Definition: ConstantQ.h:71
double m_FMax
Definition: ConstantQ.h:56
double m_FS
Definition: ConstantQ.h:54
int m_BPO
Definition: ConstantQ.h:60
double max
Definition: ConstantQ.h:26
Definition: FFT.h:18
double min
Definition: ConstantQ.h:25
std::vector< double > imag
Definition: ConstantQ.h:67
void cut(T *src) const
Definition: Window.h:61
double * m_CQdata
Definition: ConstantQ.h:53
void initialise(CQConfig config)
Definition: ConstantQ.cpp:129
void process(bool inverse, const double *realIn, const double *imagIn, double *realOut, double *imagOut)
Carry out a forward or inverse transform (depending on the value of inverse) of size nsamples...
Definition: FFT.cpp:91
int m_uK
Definition: ConstantQ.h:62
std::vector< int > is
Definition: ConstantQ.h:65
double m_FMin
Definition: ConstantQ.h:55
std::vector< int > js
Definition: ConstantQ.h:66
static int nextPowerOfTwo(int x)
Return the next higher integer power of two from x, e.g.
int m_hop
Definition: ConstantQ.h:59
void sparsekernel()
Definition: ConstantQ.cpp:38
double m_CQThresh
Definition: ConstantQ.h:58
ConstantQ(CQConfig config)
Definition: ConstantQ.cpp:23
void deInitialise()
Definition: ConstantQ.cpp:153