annotate dsp/chromagram/ConstantQ.cpp @ 515:08bcc06c38ec tip master

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