2011-03-02 07:37:39 -05:00
|
|
|
/* -*- 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 <iostream>
|
|
|
|
#include <cmath>
|
|
|
|
#include "maths/MathUtilities.h"
|
|
|
|
#include "Chromagram.h"
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Chromagram::Chromagram( ChromaConfig Config ) :
|
|
|
|
m_skGenerated(false)
|
|
|
|
{
|
|
|
|
initialise( Config );
|
|
|
|
}
|
|
|
|
|
|
|
|
int Chromagram::initialise( ChromaConfig Config )
|
2016-10-05 18:16:44 -04:00
|
|
|
{
|
2011-03-02 07:37:39 -05:00
|
|
|
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
|
2016-10-05 18:16:44 -04:00
|
|
|
m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0));
|
2011-03-02 07:37:39 -05:00
|
|
|
|
|
|
|
// 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;
|
2016-10-05 18:16:44 -04:00
|
|
|
|
2011-03-02 07:37:39 -05:00
|
|
|
// Initialise ConstantQ operator
|
|
|
|
m_ConstantQ = new ConstantQ( ConstantQConfig );
|
|
|
|
|
|
|
|
// Initialise working arrays
|
|
|
|
m_frameSize = m_ConstantQ->getfftlength();
|
|
|
|
m_hopSize = m_ConstantQ->gethop();
|
|
|
|
|
2016-10-05 18:16:44 -04:00
|
|
|
// Initialise FFT object
|
2011-03-02 07:37:39 -05:00
|
|
|
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) {
|
2016-10-05 18:16:44 -04:00
|
|
|
// Generate CQ Kernel
|
2011-03-02 07:37:39 -05:00
|
|
|
m_ConstantQ->sparsekernel();
|
|
|
|
m_skGenerated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_window) {
|
|
|
|
m_window = new Window<double>(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);
|
|
|
|
|
2016-10-05 18:16:44 -04:00
|
|
|
m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm);
|
2011-03-02 07:37:39 -05:00
|
|
|
|
|
|
|
return process(m_FFTRe, m_FFTIm);
|
|
|
|
}
|
|
|
|
|
|
|
|
double* Chromagram::process( const double *real, const double *imag )
|
|
|
|
{
|
|
|
|
if (!m_skGenerated) {
|
2016-10-05 18:16:44 -04:00
|
|
|
// Generate CQ Kernel
|
2011-03-02 07:37:39 -05:00
|
|
|
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 );
|
2016-10-05 18:16:44 -04:00
|
|
|
|
2011-03-02 07:37:39 -05:00
|
|
|
// add each octave of cq data into Chromagram
|
|
|
|
const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1;
|
2016-10-05 18:16:44 -04:00
|
|
|
for (unsigned octave = 0; octave <= octaves; octave++)
|
2011-03-02 07:37:39 -05:00
|
|
|
{
|
|
|
|
unsigned firstBin = octave*m_BPO;
|
2016-10-05 18:16:44 -04:00
|
|
|
for (unsigned i = 0; i < m_BPO; i++)
|
2011-03-02 07:37:39 -05:00
|
|
|
{
|
|
|
|
m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
|
|
|
|
|
|
|
|
return m_chromadata;
|
|
|
|
}
|
|
|
|
|
|
|
|
|