cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: /* cannam@0: QM DSP Library cannam@0: cannam@0: Centre for Digital Music, Queen Mary, University of London. Chris@84: This file 2005-2006 Christian Landone. Chris@84: Chris@84: This program is free software; you can redistribute it and/or Chris@84: modify it under the terms of the GNU General Public License as Chris@84: published by the Free Software Foundation; either version 2 of the Chris@84: License, or (at your option) any later version. See the file Chris@84: COPYING included with this distribution for more information. cannam@0: */ cannam@0: cannam@0: #include "ConstantQ.h" cannam@0: #include "dsp/transforms/FFT.h" cannam@0: cannam@20: #include cannam@20: cannam@73: #ifdef NOT_DEFINED cannam@73: // see note in CQprecalc cannam@73: cannam@51: #include "CQprecalc.cpp" cannam@51: cannam@51: static bool push_precalculated(int uk, int fftlength, cannam@51: std::vector &is, cannam@51: std::vector &js, cannam@51: std::vector &real, cannam@51: std::vector &imag) cannam@51: { cannam@51: if (uk == 76 && fftlength == 16384) { cannam@51: push_76_16384(is, js, real, imag); cannam@51: return true; cannam@51: } cannam@51: if (uk == 144 && fftlength == 4096) { cannam@51: push_144_4096(is, js, real, imag); cannam@51: return true; cannam@51: } cannam@51: if (uk == 65 && fftlength == 2048) { cannam@51: push_65_2048(is, js, real, imag); cannam@51: return true; cannam@51: } cannam@51: if (uk == 84 && fftlength == 65536) { cannam@51: push_84_65536(is, js, real, imag); cannam@51: return true; cannam@51: } cannam@51: return false; cannam@51: } cannam@73: #endif cannam@51: cannam@0: //--------------------------------------------------------------------------- cannam@0: // nextpow2 returns the smallest integer n such that 2^n >= x. cannam@0: static double nextpow2(double x) { cannam@0: double y = ceil(log(x)/log(2.0)); cannam@0: return(y); cannam@0: } cannam@0: cannam@0: static double squaredModule(const double & xx, const double & yy) { cannam@0: return xx*xx + yy*yy; cannam@0: } cannam@0: cannam@0: //---------------------------------------------------------------------------- cannam@0: cannam@51: ConstantQ::ConstantQ( CQConfig Config ) : cannam@51: m_sparseKernel(0) cannam@0: { cannam@0: initialise( Config ); cannam@0: } cannam@0: cannam@0: ConstantQ::~ConstantQ() cannam@0: { cannam@0: deInitialise(); cannam@0: } cannam@0: cannam@0: //---------------------------------------------------------------------------- cannam@0: void ConstantQ::sparsekernel() cannam@0: { cannam@51: // std::cerr << "ConstantQ: initialising sparse kernel, uK = " << m_uK << ", FFTLength = " << m_FFTLength << "..."; cannam@51: cannam@51: SparseKernel *sk = new SparseKernel(); cannam@51: cannam@73: #ifdef NOT_DEFINED cannam@51: if (push_precalculated(m_uK, m_FFTLength, cannam@51: sk->is, sk->js, sk->real, sk->imag)) { cannam@73: // std::cerr << "using precalculated kernel" << std::endl; cannam@51: m_sparseKernel = sk; cannam@51: return; cannam@51: } cannam@73: #endif cannam@73: cannam@0: //generates spectral kernel matrix (upside down?) cannam@0: // initialise temporal kernel with zeros, twice length to deal w. complex numbers cannam@0: cannam@0: double* hammingWindowRe = new double [ m_FFTLength ]; cannam@0: double* hammingWindowIm = new double [ m_FFTLength ]; cannam@0: double* transfHammingWindowRe = new double [ m_FFTLength ]; cannam@0: double* transfHammingWindowIm = new double [ m_FFTLength ]; cannam@0: cannam@0: for (unsigned u=0; u < m_FFTLength; u++) cannam@0: { cannam@0: hammingWindowRe[u] = 0; cannam@0: hammingWindowIm[u] = 0; cannam@0: } cannam@0: cannam@0: // Here, fftleng*2 is a guess of the number of sparse cells in the matrix cannam@0: // The matrix K x fftlength but the non-zero cells are an antialiased cannam@0: // square root function. So mostly is a line, with some grey point. cannam@51: sk->is.reserve( m_FFTLength*2 ); cannam@51: sk->js.reserve( m_FFTLength*2 ); cannam@51: sk->real.reserve( m_FFTLength*2 ); cannam@51: sk->imag.reserve( m_FFTLength*2 ); cannam@0: cannam@0: // for each bin value K, calculate temporal kernel, take its fft to cannam@0: //calculate the spectral kernel then threshold it to make it sparse and cannam@0: //add it to the sparse kernels matrix cannam@0: double squareThreshold = m_CQThresh * m_CQThresh; cannam@0: cannam@64: FFT m_FFT(m_FFTLength); cannam@0: cannam@0: for (unsigned k = m_uK; k--; ) cannam@0: { cannam@3: for (unsigned u=0; u < m_FFTLength; u++) cannam@3: { cannam@3: hammingWindowRe[u] = 0; cannam@3: hammingWindowIm[u] = 0; cannam@3: } cannam@3: cannam@0: // Computing a hamming window cannam@0: const unsigned hammingLength = (int) ceil( m_dQ * m_FS / ( m_FMin * pow(2,((double)(k))/(double)m_BPO))); cannam@3: cannam@3: unsigned origin = m_FFTLength/2 - hammingLength/2; cannam@3: cannam@0: for (unsigned i=0; iis.push_back(j); cannam@51: sk->js.push_back(k); cannam@0: cannam@0: // take conjugate, normalise and add to array sparkernel cannam@51: sk->real.push_back( transfHammingWindowRe[ j ]/m_FFTLength); cannam@51: sk->imag.push_back(-transfHammingWindowIm[ j ]/m_FFTLength); cannam@0: } cannam@0: cannam@0: } cannam@0: cannam@0: delete [] hammingWindowRe; cannam@0: delete [] hammingWindowIm; cannam@0: delete [] transfHammingWindowRe; cannam@0: delete [] transfHammingWindowIm; cannam@0: cannam@51: /* cannam@51: using std::cout; cannam@51: using std::endl; cannam@51: cannam@51: cout.precision(28); cannam@51: cannam@51: int n = sk->is.size(); cannam@51: int w = 8; cannam@51: cout << "static unsigned int sk_i_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; cannam@51: for (int i = 0; i < n; ++i) { cannam@51: if (i % w == 0) cout << " "; cannam@51: cout << sk->is[i]; cannam@51: if (i + 1 < n) cout << ", "; cannam@51: if (i % w == w-1) cout << endl; cannam@51: }; cannam@51: if (n % w != 0) cout << endl; cannam@51: cout << "};" << endl; cannam@51: cannam@51: n = sk->js.size(); cannam@51: cout << "static unsigned int sk_j_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; cannam@51: for (int i = 0; i < n; ++i) { cannam@51: if (i % w == 0) cout << " "; cannam@51: cout << sk->js[i]; cannam@51: if (i + 1 < n) cout << ", "; cannam@51: if (i % w == w-1) cout << endl; cannam@51: }; cannam@51: if (n % w != 0) cout << endl; cannam@51: cout << "};" << endl; cannam@51: cannam@51: w = 2; cannam@51: n = sk->real.size(); cannam@51: cout << "static double sk_real_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; cannam@51: for (int i = 0; i < n; ++i) { cannam@51: if (i % w == 0) cout << " "; cannam@51: cout << sk->real[i]; cannam@51: if (i + 1 < n) cout << ", "; cannam@51: if (i % w == w-1) cout << endl; cannam@51: }; cannam@51: if (n % w != 0) cout << endl; cannam@51: cout << "};" << endl; cannam@51: cannam@51: n = sk->imag.size(); cannam@51: cout << "static double sk_imag_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl; cannam@51: for (int i = 0; i < n; ++i) { cannam@51: if (i % w == 0) cout << " "; cannam@51: cout << sk->imag[i]; cannam@51: if (i + 1 < n) cout << ", "; cannam@51: if (i % w == w-1) cout << endl; cannam@51: }; cannam@51: if (n % w != 0) cout << endl; cannam@51: cout << "};" << endl; cannam@51: cannam@51: cout << "static void push_" << m_uK << "_" << m_FFTLength << "(vector &is, vector &js, vector &real, vector &imag)" << endl; cannam@51: cout << "{\n is.reserve(" << n << ");\n"; cannam@51: cout << " js.reserve(" << n << ");\n"; cannam@51: cout << " real.reserve(" << n << ");\n"; cannam@51: cout << " imag.reserve(" << n << ");\n"; cannam@51: cout << " for (int i = 0; i < " << n << "; ++i) {" << endl; cannam@51: cout << " is.push_back(sk_i_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; cannam@51: cout << " js.push_back(sk_j_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; cannam@51: cout << " real.push_back(sk_real_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; cannam@51: cout << " imag.push_back(sk_imag_" << m_uK << "_" << m_FFTLength << "[i]);" << endl; cannam@51: cout << " }" << endl; cannam@51: cout << "}" << endl; cannam@51: */ cannam@51: // std::cerr << "done\n -> is: " << sk->is.size() << ", js: " << sk->js.size() << ", reals: " << sk->real.size() << ", imags: " << sk->imag.size() << std::endl; cannam@51: cannam@51: m_sparseKernel = sk; cannam@51: return; cannam@0: } cannam@0: cannam@0: //----------------------------------------------------------------------------- cannam@32: double* ConstantQ::process( const double* fftdata ) cannam@0: { cannam@51: if (!m_sparseKernel) { cannam@51: std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl; cannam@51: return m_CQdata; cannam@51: } cannam@51: cannam@51: SparseKernel *sk = m_sparseKernel; cannam@51: cannam@0: for (unsigned row=0; row<2*m_uK; row++) cannam@0: { cannam@0: m_CQdata[ row ] = 0; cannam@0: m_CQdata[ row+1 ] = 0; cannam@0: } cannam@51: const unsigned *fftbin = &(sk->is[0]); cannam@51: const unsigned *cqbin = &(sk->js[0]); cannam@51: const double *real = &(sk->real[0]); cannam@51: const double *imag = &(sk->imag[0]); cannam@51: const unsigned int sparseCells = sk->real.size(); cannam@0: cannam@0: for (unsigned i = 0; i fft length = " << m_FFTLength << ", hop = " << m_hop << std::endl; cannam@20: cannam@0: // allocate memory for cqdata cannam@0: m_CQdata = new double [2*m_uK]; cannam@0: } cannam@0: cannam@0: void ConstantQ::deInitialise() cannam@0: { cannam@0: delete [] m_CQdata; cannam@51: delete m_sparseKernel; cannam@0: } cannam@0: cannam@32: void ConstantQ::process(const double *FFTRe, const double* FFTIm, cannam@32: double *CQRe, double *CQIm) cannam@0: { cannam@51: if (!m_sparseKernel) { cannam@51: std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl; cannam@51: return; cannam@51: } cannam@51: cannam@51: SparseKernel *sk = m_sparseKernel; cannam@51: cannam@0: for (unsigned row=0; rowis[0]); cannam@51: const unsigned *cqbin = &(sk->js[0]); cannam@51: const double *real = &(sk->real[0]); cannam@51: const double *imag = &(sk->imag[0]); cannam@51: const unsigned int sparseCells = sk->real.size(); cannam@0: cannam@0: for (unsigned i = 0; i