qm-dsp
1.8
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 QM DSP Library 00005 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file 2005-2006 Christian Landone. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include <iostream> 00017 #include <cmath> 00018 #include "maths/MathUtilities.h" 00019 #include "Chromagram.h" 00020 00021 //---------------------------------------------------------------------------- 00022 00023 Chromagram::Chromagram( ChromaConfig Config ) : 00024 m_skGenerated(false) 00025 { 00026 initialise( Config ); 00027 } 00028 00029 int Chromagram::initialise( ChromaConfig Config ) 00030 { 00031 m_FMin = Config.min; // min freq 00032 m_FMax = Config.max; // max freq 00033 m_BPO = Config.BPO; // bins per octave 00034 m_normalise = Config.normalise; // if frame normalisation is required 00035 00036 // No. of constant Q bins 00037 m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0)); 00038 00039 // Create array for chroma result 00040 m_chromadata = new double[ m_BPO ]; 00041 00042 // Create Config Structure for ConstantQ operator 00043 CQConfig ConstantQConfig; 00044 00045 // Populate CQ config structure with parameters 00046 // inherited from the Chroma config 00047 ConstantQConfig.FS = Config.FS; 00048 ConstantQConfig.min = m_FMin; 00049 ConstantQConfig.max = m_FMax; 00050 ConstantQConfig.BPO = m_BPO; 00051 ConstantQConfig.CQThresh = Config.CQThresh; 00052 00053 // Initialise ConstantQ operator 00054 m_ConstantQ = new ConstantQ( ConstantQConfig ); 00055 00056 // Initialise working arrays 00057 m_frameSize = m_ConstantQ->getfftlength(); 00058 m_hopSize = m_ConstantQ->gethop(); 00059 00060 // Initialise FFT object 00061 m_FFT = new FFTReal(m_frameSize); 00062 00063 m_FFTRe = new double[ m_frameSize ]; 00064 m_FFTIm = new double[ m_frameSize ]; 00065 m_CQRe = new double[ m_uK ]; 00066 m_CQIm = new double[ m_uK ]; 00067 00068 m_window = 0; 00069 m_windowbuf = 0; 00070 00071 return 1; 00072 } 00073 00074 Chromagram::~Chromagram() 00075 { 00076 deInitialise(); 00077 } 00078 00079 int Chromagram::deInitialise() 00080 { 00081 delete[] m_windowbuf; 00082 delete m_window; 00083 00084 delete [] m_chromadata; 00085 00086 delete m_FFT; 00087 00088 delete m_ConstantQ; 00089 00090 delete [] m_FFTRe; 00091 delete [] m_FFTIm; 00092 delete [] m_CQRe; 00093 delete [] m_CQIm; 00094 return 1; 00095 } 00096 00097 //---------------------------------------------------------------------------------- 00098 // returns the absolute value of complex number xx + i*yy 00099 double Chromagram::kabs(double xx, double yy) 00100 { 00101 double ab = sqrt(xx*xx + yy*yy); 00102 return(ab); 00103 } 00104 //----------------------------------------------------------------------------------- 00105 00106 00107 void Chromagram::unityNormalise(double *src) 00108 { 00109 double min, max; 00110 00111 double val = 0; 00112 00113 MathUtilities::getFrameMinMax( src, m_BPO, & min, &max ); 00114 00115 for( unsigned int i = 0; i < m_BPO; i++ ) 00116 { 00117 val = src[ i ] / max; 00118 00119 src[ i ] = val; 00120 } 00121 } 00122 00123 00124 double* Chromagram::process( const double *data ) 00125 { 00126 if (!m_skGenerated) { 00127 // Generate CQ Kernel 00128 m_ConstantQ->sparsekernel(); 00129 m_skGenerated = true; 00130 } 00131 00132 if (!m_window) { 00133 m_window = new Window<double>(HammingWindow, m_frameSize); 00134 m_windowbuf = new double[m_frameSize]; 00135 } 00136 00137 for (int i = 0; i < m_frameSize; ++i) { 00138 m_windowbuf[i] = data[i]; 00139 } 00140 m_window->cut(m_windowbuf); 00141 00142 m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm); 00143 00144 return process(m_FFTRe, m_FFTIm); 00145 } 00146 00147 double* Chromagram::process( const double *real, const double *imag ) 00148 { 00149 if (!m_skGenerated) { 00150 // Generate CQ Kernel 00151 m_ConstantQ->sparsekernel(); 00152 m_skGenerated = true; 00153 } 00154 00155 // initialise chromadata to 0 00156 for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0; 00157 00158 double cmax = 0.0; 00159 double cval = 0; 00160 // Calculate ConstantQ frame 00161 m_ConstantQ->process( real, imag, m_CQRe, m_CQIm ); 00162 00163 // add each octave of cq data into Chromagram 00164 const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1; 00165 for (unsigned octave = 0; octave <= octaves; octave++) 00166 { 00167 unsigned firstBin = octave*m_BPO; 00168 for (unsigned i = 0; i < m_BPO; i++) 00169 { 00170 m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]); 00171 } 00172 } 00173 00174 MathUtilities::normalise(m_chromadata, m_BPO, m_normalise); 00175 00176 return m_chromadata; 00177 } 00178 00179