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