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