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