annotate dsp/chromagram/Chromagram.cpp @ 298:255e431ae3d4

* Key detector: when returning key strengths, use the peak value of the three underlying chromagram correlations (from 36-bin chromagram) corresponding to each key, instead of the mean. Rationale: This is the same method as used when returning the key value, and it's nice to have the same results in both returned value and plot. The peak performed better than the sum with a simple test set of triads, so it seems reasonable to change the plot to match the key output rather than the other way around. * FFT: kiss_fftr returns only the non-conjugate bins, synthesise the rest rather than leaving them (perhaps dangerously) undefined. Fixes an uninitialised data error in chromagram that could cause garbage results from key detector. * Constant Q: remove precalculated values again, I reckon they're not proving such a good tradeoff.
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 05 Jun 2009 15:12:39 +0000
parents befe5aa6b450
children e5907ae6de17
rev   line source
c@225 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@225 2
c@225 3 /*
c@225 4 QM DSP Library
c@225 5
c@225 6 Centre for Digital Music, Queen Mary, University of London.
c@225 7 This file copyright 2005-2006 Christian Landone.
c@225 8 All rights reserved.
c@225 9 */
c@225 10
c@225 11 #include <iostream>
c@225 12 #include <cmath>
c@241 13 #include "maths/MathUtilities.h"
c@225 14 #include "Chromagram.h"
c@225 15
c@225 16 //----------------------------------------------------------------------------
c@225 17
c@276 18 Chromagram::Chromagram( ChromaConfig Config ) :
c@276 19 m_skGenerated(false)
c@225 20 {
c@225 21 initialise( Config );
c@225 22 }
c@225 23
c@225 24 int Chromagram::initialise( ChromaConfig Config )
c@225 25 {
c@225 26 m_FMin = Config.min; // min freq
c@225 27 m_FMax = Config.max; // max freq
c@225 28 m_BPO = Config.BPO; // bins per octave
c@259 29 m_normalise = Config.normalise; // if frame normalisation is required
c@225 30
c@225 31 // No. of constant Q bins
c@225 32 m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0));
c@225 33
c@225 34 // Create array for chroma result
c@225 35 m_chromadata = new double[ m_BPO ];
c@225 36
c@225 37 // Create Config Structure for ConstantQ operator
c@225 38 CQConfig ConstantQConfig;
c@225 39
c@225 40 // Populate CQ config structure with parameters
c@225 41 // inherited from the Chroma config
c@225 42 ConstantQConfig.FS = Config.FS;
c@225 43 ConstantQConfig.min = m_FMin;
c@225 44 ConstantQConfig.max = m_FMax;
c@225 45 ConstantQConfig.BPO = m_BPO;
c@225 46 ConstantQConfig.CQThresh = Config.CQThresh;
c@225 47
c@225 48 // Initialise ConstantQ operator
c@225 49 m_ConstantQ = new ConstantQ( ConstantQConfig );
c@225 50
c@225 51 // Initialise working arrays
c@225 52 m_frameSize = m_ConstantQ->getfftlength();
c@225 53 m_hopSize = m_ConstantQ->gethop();
c@225 54
c@289 55 // Initialise FFT object
c@289 56 m_FFT = new FFTReal(m_frameSize);
c@289 57
c@225 58 m_FFTRe = new double[ m_frameSize ];
c@225 59 m_FFTIm = new double[ m_frameSize ];
c@225 60 m_CQRe = new double[ m_uK ];
c@225 61 m_CQIm = new double[ m_uK ];
c@225 62
c@257 63 m_window = 0;
c@257 64 m_windowbuf = 0;
c@257 65
c@225 66 return 1;
c@225 67 }
c@225 68
c@225 69 Chromagram::~Chromagram()
c@225 70 {
c@225 71 deInitialise();
c@225 72 }
c@225 73
c@225 74 int Chromagram::deInitialise()
c@225 75 {
c@257 76 delete[] m_windowbuf;
c@257 77 delete m_window;
c@257 78
c@225 79 delete [] m_chromadata;
c@225 80
c@225 81 delete m_FFT;
c@225 82
c@225 83 delete m_ConstantQ;
c@225 84
c@225 85 delete [] m_FFTRe;
c@225 86 delete [] m_FFTIm;
c@225 87 delete [] m_CQRe;
c@225 88 delete [] m_CQIm;
c@225 89 return 1;
c@225 90 }
c@225 91
c@225 92 //----------------------------------------------------------------------------------
c@225 93 // returns the absolute value of complex number xx + i*yy
c@225 94 double Chromagram::kabs(double xx, double yy)
c@225 95 {
c@225 96 double ab = sqrt(xx*xx + yy*yy);
c@225 97 return(ab);
c@225 98 }
c@225 99 //-----------------------------------------------------------------------------------
c@225 100
c@225 101
c@225 102 void Chromagram::unityNormalise(double *src)
c@225 103 {
c@225 104 double min, max;
c@225 105
c@225 106 double val = 0;
c@225 107
c@225 108 MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
c@225 109
c@225 110 for( unsigned int i = 0; i < m_BPO; i++ )
c@225 111 {
c@225 112 val = src[ i ] / max;
c@225 113
c@225 114 src[ i ] = val;
c@225 115 }
c@225 116 }
c@225 117
c@225 118
c@257 119 double* Chromagram::process( const double *data )
c@225 120 {
c@276 121 if (!m_skGenerated) {
c@276 122 // Generate CQ Kernel
c@276 123 m_ConstantQ->sparsekernel();
c@276 124 m_skGenerated = true;
c@276 125 }
c@276 126
c@257 127 if (!m_window) {
c@257 128 m_window = new Window<double>(HammingWindow, m_frameSize);
c@257 129 m_windowbuf = new double[m_frameSize];
c@257 130 }
c@257 131
c@257 132 for (int i = 0; i < m_frameSize; ++i) {
c@257 133 m_windowbuf[i] = data[i];
c@257 134 }
c@257 135 m_window->cut(m_windowbuf);
c@257 136
c@228 137 // FFT of current frame
c@298 138 m_FFT->process(false, m_windowbuf, m_FFTRe, m_FFTIm);
c@228 139
c@228 140 return process(m_FFTRe, m_FFTIm);
c@228 141 }
c@228 142
c@257 143 double* Chromagram::process( const double *real, const double *imag )
c@228 144 {
c@276 145 if (!m_skGenerated) {
c@276 146 // Generate CQ Kernel
c@276 147 m_ConstantQ->sparsekernel();
c@276 148 m_skGenerated = true;
c@276 149 }
c@276 150
c@228 151 // initialise chromadata to 0
c@228 152 for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
c@225 153
c@225 154 double cmax = 0.0;
c@225 155 double cval = 0;
c@225 156
c@225 157 // Calculate ConstantQ frame
c@228 158 m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
c@225 159
c@225 160 // add each octave of cq data into Chromagram
c@225 161 const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1;
c@228 162 for (unsigned octave = 0; octave <= octaves; octave++)
c@225 163 {
c@225 164 unsigned firstBin = octave*m_BPO;
c@228 165 for (unsigned i = 0; i < m_BPO; i++)
c@225 166 {
c@225 167 m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
c@225 168 }
c@225 169 }
c@225 170
c@259 171 MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
c@225 172
c@225 173 return m_chromadata;
c@225 174 }
c@225 175
c@225 176