c@225: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@225: 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 c@225: #include c@241: #include "maths/MathUtilities.h" c@225: #include "Chromagram.h" c@225: c@225: //---------------------------------------------------------------------------- c@225: c@276: Chromagram::Chromagram( ChromaConfig Config ) : c@276: m_skGenerated(false) c@225: { c@225: initialise( Config ); c@225: } c@225: c@225: int Chromagram::initialise( ChromaConfig Config ) c@225: { c@225: m_FMin = Config.min; // min freq c@225: m_FMax = Config.max; // max freq c@225: m_BPO = Config.BPO; // bins per octave c@259: m_normalise = Config.normalise; // if frame normalisation is required c@225: c@225: // No. of constant Q bins c@414: m_uK = (int) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0)); c@225: c@225: // Create array for chroma result c@225: m_chromadata = new double[ m_BPO ]; c@225: c@225: // Create Config Structure for ConstantQ operator c@225: CQConfig ConstantQConfig; c@225: c@225: // Populate CQ config structure with parameters c@225: // inherited from the Chroma config cannam@465: ConstantQConfig.FS = Config.FS; c@225: ConstantQConfig.min = m_FMin; c@225: ConstantQConfig.max = m_FMax; c@225: ConstantQConfig.BPO = m_BPO; c@225: ConstantQConfig.CQThresh = Config.CQThresh; c@225: c@225: // Initialise ConstantQ operator c@225: m_ConstantQ = new ConstantQ( ConstantQConfig ); c@225: c@225: // Initialise working arrays c@225: m_frameSize = m_ConstantQ->getfftlength(); c@225: m_hopSize = m_ConstantQ->gethop(); c@225: c@289: // Initialise FFT object c@289: m_FFT = new FFTReal(m_frameSize); c@289: c@225: m_FFTRe = new double[ m_frameSize ]; c@225: m_FFTIm = new double[ m_frameSize ]; c@225: m_CQRe = new double[ m_uK ]; c@225: m_CQIm = new double[ m_uK ]; c@225: c@257: m_window = 0; c@257: m_windowbuf = 0; c@257: c@225: return 1; c@225: } c@225: c@225: Chromagram::~Chromagram() c@225: { c@225: deInitialise(); c@225: } c@225: c@225: int Chromagram::deInitialise() c@225: { c@257: delete[] m_windowbuf; c@257: delete m_window; c@257: c@225: delete [] m_chromadata; c@225: c@225: delete m_FFT; c@225: c@225: delete m_ConstantQ; c@225: c@225: delete [] m_FFTRe; c@225: delete [] m_FFTIm; c@225: delete [] m_CQRe; c@225: delete [] m_CQIm; c@225: return 1; c@225: } c@225: c@225: //---------------------------------------------------------------------------------- c@225: // returns the absolute value of complex number xx + i*yy c@225: double Chromagram::kabs(double xx, double yy) c@225: { c@225: double ab = sqrt(xx*xx + yy*yy); c@225: return(ab); c@225: } c@225: //----------------------------------------------------------------------------------- c@225: c@225: c@225: void Chromagram::unityNormalise(double *src) c@225: { c@225: double min, max; c@225: c@225: double val = 0; c@225: c@225: MathUtilities::getFrameMinMax( src, m_BPO, & min, &max ); c@225: c@414: for (int i = 0; i < m_BPO; i++) c@225: { c@225: val = src[ i ] / max; c@225: c@225: src[ i ] = val; c@225: } c@225: } c@225: c@225: c@257: double* Chromagram::process( const double *data ) c@225: { c@276: if (!m_skGenerated) { c@276: // Generate CQ Kernel c@276: m_ConstantQ->sparsekernel(); c@276: m_skGenerated = true; c@276: } c@276: c@257: if (!m_window) { c@257: m_window = new Window(HammingWindow, m_frameSize); c@257: m_windowbuf = new double[m_frameSize]; c@257: } c@257: c@257: for (int i = 0; i < m_frameSize; ++i) { c@257: m_windowbuf[i] = data[i]; c@257: } c@257: m_window->cut(m_windowbuf); c@257: c@339: m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm); c@228: c@228: return process(m_FFTRe, m_FFTIm); c@228: } c@228: c@257: double* Chromagram::process( const double *real, const double *imag ) c@228: { c@276: if (!m_skGenerated) { c@276: // Generate CQ Kernel c@276: m_ConstantQ->sparsekernel(); c@276: m_skGenerated = true; c@276: } c@276: c@228: // initialise chromadata to 0 c@414: for (int i = 0; i < m_BPO; i++) m_chromadata[i] = 0; c@225: c@225: // Calculate ConstantQ frame c@228: m_ConstantQ->process( real, imag, m_CQRe, m_CQIm ); c@225: c@225: // add each octave of cq data into Chromagram c@414: const int octaves = (int)floor(double( m_uK/m_BPO))-1; c@414: for (int octave = 0; octave <= octaves; octave++) c@225: { c@414: int firstBin = octave*m_BPO; c@414: for (int i = 0; i < m_BPO; i++) c@225: { c@225: m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]); c@225: } c@225: } c@225: c@259: MathUtilities::normalise(m_chromadata, m_BPO, m_normalise); c@225: c@225: return m_chromadata; c@225: } c@225: c@225: