cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: QM DSP Library cannam@0: cannam@0: Centre for Digital Music, Queen Mary, University of London. cannam@0: This file copyright 2005-2006 Christian Landone. cannam@0: All rights reserved. cannam@0: */ cannam@0: cannam@0: #include cannam@0: #include cannam@16: #include "maths/MathUtilities.h" cannam@0: #include "Chromagram.h" cannam@0: cannam@0: //---------------------------------------------------------------------------- cannam@0: cannam@0: Chromagram::Chromagram( ChromaConfig Config ) cannam@0: { cannam@0: initialise( Config ); cannam@0: } cannam@0: cannam@0: int Chromagram::initialise( ChromaConfig Config ) cannam@0: { cannam@0: m_FMin = Config.min; // min freq cannam@0: m_FMax = Config.max; // max freq cannam@0: m_BPO = Config.BPO; // bins per octave cannam@0: isNormalised = Config.isNormalised; // true if frame normalisation is required cannam@0: cannam@0: // No. of constant Q bins cannam@0: m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0)); cannam@0: cannam@0: // Create array for chroma result cannam@0: m_chromadata = new double[ m_BPO ]; cannam@0: cannam@0: // Initialise FFT object cannam@0: m_FFT = new FFT; cannam@0: cannam@0: // Create Config Structure for ConstantQ operator cannam@0: CQConfig ConstantQConfig; cannam@0: cannam@0: // Populate CQ config structure with parameters cannam@0: // inherited from the Chroma config cannam@0: ConstantQConfig.FS = Config.FS; cannam@0: ConstantQConfig.min = m_FMin; cannam@0: ConstantQConfig.max = m_FMax; cannam@0: ConstantQConfig.BPO = m_BPO; cannam@0: ConstantQConfig.CQThresh = Config.CQThresh; cannam@0: cannam@0: // Initialise ConstantQ operator cannam@0: m_ConstantQ = new ConstantQ( ConstantQConfig ); cannam@0: cannam@0: // Initialise working arrays cannam@0: m_frameSize = m_ConstantQ->getfftlength(); cannam@0: m_hopSize = m_ConstantQ->gethop(); cannam@0: cannam@0: m_FFTRe = new double[ m_frameSize ]; cannam@0: m_FFTIm = new double[ m_frameSize ]; cannam@0: m_CQRe = new double[ m_uK ]; cannam@0: m_CQIm = new double[ m_uK ]; cannam@0: cannam@32: m_window = 0; cannam@32: m_windowbuf = 0; cannam@32: cannam@0: // Generate CQ Kernel cannam@0: m_ConstantQ->sparsekernel(); cannam@0: return 1; cannam@0: } cannam@0: cannam@0: Chromagram::~Chromagram() cannam@0: { cannam@0: deInitialise(); cannam@0: } cannam@0: cannam@0: int Chromagram::deInitialise() cannam@0: { cannam@32: delete[] m_windowbuf; cannam@32: delete m_window; cannam@32: cannam@0: delete [] m_chromadata; cannam@0: cannam@0: delete m_FFT; cannam@0: cannam@0: delete m_ConstantQ; cannam@0: cannam@0: delete [] m_FFTRe; cannam@0: delete [] m_FFTIm; cannam@0: delete [] m_CQRe; cannam@0: delete [] m_CQIm; cannam@0: return 1; cannam@0: } cannam@0: cannam@0: //---------------------------------------------------------------------------------- cannam@0: // returns the absolute value of complex number xx + i*yy cannam@0: double Chromagram::kabs(double xx, double yy) cannam@0: { cannam@0: double ab = sqrt(xx*xx + yy*yy); cannam@0: return(ab); cannam@0: } cannam@0: //----------------------------------------------------------------------------------- cannam@0: cannam@0: cannam@0: void Chromagram::unityNormalise(double *src) cannam@0: { cannam@0: double min, max; cannam@0: cannam@0: double val = 0; cannam@0: cannam@0: MathUtilities::getFrameMinMax( src, m_BPO, & min, &max ); cannam@0: cannam@0: for( unsigned int i = 0; i < m_BPO; i++ ) cannam@0: { cannam@0: val = src[ i ] / max; cannam@0: cannam@0: src[ i ] = val; cannam@0: } cannam@0: } cannam@0: cannam@0: cannam@32: double* Chromagram::process( const double *data ) cannam@0: { cannam@32: if (!m_window) { cannam@32: m_window = new Window(HammingWindow, m_frameSize); cannam@32: m_windowbuf = new double[m_frameSize]; cannam@32: } cannam@32: cannam@32: for (int i = 0; i < m_frameSize; ++i) { cannam@32: m_windowbuf[i] = data[i]; cannam@32: } cannam@32: m_window->cut(m_windowbuf); cannam@32: cannam@3: // FFT of current frame cannam@32: m_FFT->process(m_frameSize, 0, m_windowbuf, NULL, m_FFTRe, m_FFTIm); cannam@3: cannam@3: return process(m_FFTRe, m_FFTIm); cannam@3: } cannam@3: cannam@32: double* Chromagram::process( const double *real, const double *imag ) cannam@3: { cannam@3: // initialise chromadata to 0 cannam@3: for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0; cannam@0: cannam@0: double cmax = 0.0; cannam@0: double cval = 0; cannam@0: cannam@0: // Calculate ConstantQ frame cannam@3: m_ConstantQ->process( real, imag, m_CQRe, m_CQIm ); cannam@0: cannam@0: // add each octave of cq data into Chromagram cannam@0: const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1; cannam@3: for (unsigned octave = 0; octave <= octaves; octave++) cannam@0: { cannam@0: unsigned firstBin = octave*m_BPO; cannam@3: for (unsigned i = 0; i < m_BPO; i++) cannam@0: { cannam@0: m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]); cannam@0: } cannam@0: } cannam@0: cannam@0: if( isNormalised ) cannam@0: unityNormalise( m_chromadata ); cannam@0: cannam@0: return m_chromadata; cannam@0: } cannam@0: cannam@0: