annotate dsp/chromagram/Chromagram.cpp @ 73:dcb555b90924

* 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 cannam
date Fri, 05 Jun 2009 15:12:39 +0000
parents 6cb2b3cd5356
children e5907ae6de17
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 /*
cannam@0 4 QM DSP Library
cannam@0 5
cannam@0 6 Centre for Digital Music, Queen Mary, University of London.
cannam@0 7 This file copyright 2005-2006 Christian Landone.
cannam@0 8 All rights reserved.
cannam@0 9 */
cannam@0 10
cannam@0 11 #include <iostream>
cannam@0 12 #include <cmath>
cannam@16 13 #include "maths/MathUtilities.h"
cannam@0 14 #include "Chromagram.h"
cannam@0 15
cannam@0 16 //----------------------------------------------------------------------------
cannam@0 17
cannam@51 18 Chromagram::Chromagram( ChromaConfig Config ) :
cannam@51 19 m_skGenerated(false)
cannam@0 20 {
cannam@0 21 initialise( Config );
cannam@0 22 }
cannam@0 23
cannam@0 24 int Chromagram::initialise( ChromaConfig Config )
cannam@0 25 {
cannam@0 26 m_FMin = Config.min; // min freq
cannam@0 27 m_FMax = Config.max; // max freq
cannam@0 28 m_BPO = Config.BPO; // bins per octave
cannam@34 29 m_normalise = Config.normalise; // if frame normalisation is required
cannam@0 30
cannam@0 31 // No. of constant Q bins
cannam@0 32 m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0));
cannam@0 33
cannam@0 34 // Create array for chroma result
cannam@0 35 m_chromadata = new double[ m_BPO ];
cannam@0 36
cannam@0 37 // Create Config Structure for ConstantQ operator
cannam@0 38 CQConfig ConstantQConfig;
cannam@0 39
cannam@0 40 // Populate CQ config structure with parameters
cannam@0 41 // inherited from the Chroma config
cannam@0 42 ConstantQConfig.FS = Config.FS;
cannam@0 43 ConstantQConfig.min = m_FMin;
cannam@0 44 ConstantQConfig.max = m_FMax;
cannam@0 45 ConstantQConfig.BPO = m_BPO;
cannam@0 46 ConstantQConfig.CQThresh = Config.CQThresh;
cannam@0 47
cannam@0 48 // Initialise ConstantQ operator
cannam@0 49 m_ConstantQ = new ConstantQ( ConstantQConfig );
cannam@0 50
cannam@0 51 // Initialise working arrays
cannam@0 52 m_frameSize = m_ConstantQ->getfftlength();
cannam@0 53 m_hopSize = m_ConstantQ->gethop();
cannam@0 54
cannam@64 55 // Initialise FFT object
cannam@64 56 m_FFT = new FFTReal(m_frameSize);
cannam@64 57
cannam@0 58 m_FFTRe = new double[ m_frameSize ];
cannam@0 59 m_FFTIm = new double[ m_frameSize ];
cannam@0 60 m_CQRe = new double[ m_uK ];
cannam@0 61 m_CQIm = new double[ m_uK ];
cannam@0 62
cannam@32 63 m_window = 0;
cannam@32 64 m_windowbuf = 0;
cannam@32 65
cannam@0 66 return 1;
cannam@0 67 }
cannam@0 68
cannam@0 69 Chromagram::~Chromagram()
cannam@0 70 {
cannam@0 71 deInitialise();
cannam@0 72 }
cannam@0 73
cannam@0 74 int Chromagram::deInitialise()
cannam@0 75 {
cannam@32 76 delete[] m_windowbuf;
cannam@32 77 delete m_window;
cannam@32 78
cannam@0 79 delete [] m_chromadata;
cannam@0 80
cannam@0 81 delete m_FFT;
cannam@0 82
cannam@0 83 delete m_ConstantQ;
cannam@0 84
cannam@0 85 delete [] m_FFTRe;
cannam@0 86 delete [] m_FFTIm;
cannam@0 87 delete [] m_CQRe;
cannam@0 88 delete [] m_CQIm;
cannam@0 89 return 1;
cannam@0 90 }
cannam@0 91
cannam@0 92 //----------------------------------------------------------------------------------
cannam@0 93 // returns the absolute value of complex number xx + i*yy
cannam@0 94 double Chromagram::kabs(double xx, double yy)
cannam@0 95 {
cannam@0 96 double ab = sqrt(xx*xx + yy*yy);
cannam@0 97 return(ab);
cannam@0 98 }
cannam@0 99 //-----------------------------------------------------------------------------------
cannam@0 100
cannam@0 101
cannam@0 102 void Chromagram::unityNormalise(double *src)
cannam@0 103 {
cannam@0 104 double min, max;
cannam@0 105
cannam@0 106 double val = 0;
cannam@0 107
cannam@0 108 MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
cannam@0 109
cannam@0 110 for( unsigned int i = 0; i < m_BPO; i++ )
cannam@0 111 {
cannam@0 112 val = src[ i ] / max;
cannam@0 113
cannam@0 114 src[ i ] = val;
cannam@0 115 }
cannam@0 116 }
cannam@0 117
cannam@0 118
cannam@32 119 double* Chromagram::process( const double *data )
cannam@0 120 {
cannam@51 121 if (!m_skGenerated) {
cannam@51 122 // Generate CQ Kernel
cannam@51 123 m_ConstantQ->sparsekernel();
cannam@51 124 m_skGenerated = true;
cannam@51 125 }
cannam@51 126
cannam@32 127 if (!m_window) {
cannam@32 128 m_window = new Window<double>(HammingWindow, m_frameSize);
cannam@32 129 m_windowbuf = new double[m_frameSize];
cannam@32 130 }
cannam@32 131
cannam@32 132 for (int i = 0; i < m_frameSize; ++i) {
cannam@32 133 m_windowbuf[i] = data[i];
cannam@32 134 }
cannam@32 135 m_window->cut(m_windowbuf);
cannam@32 136
cannam@3 137 // FFT of current frame
cannam@73 138 m_FFT->process(false, m_windowbuf, m_FFTRe, m_FFTIm);
cannam@3 139
cannam@3 140 return process(m_FFTRe, m_FFTIm);
cannam@3 141 }
cannam@3 142
cannam@32 143 double* Chromagram::process( const double *real, const double *imag )
cannam@3 144 {
cannam@51 145 if (!m_skGenerated) {
cannam@51 146 // Generate CQ Kernel
cannam@51 147 m_ConstantQ->sparsekernel();
cannam@51 148 m_skGenerated = true;
cannam@51 149 }
cannam@51 150
cannam@3 151 // initialise chromadata to 0
cannam@3 152 for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
cannam@0 153
cannam@0 154 double cmax = 0.0;
cannam@0 155 double cval = 0;
cannam@0 156
cannam@0 157 // Calculate ConstantQ frame
cannam@3 158 m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
cannam@0 159
cannam@0 160 // add each octave of cq data into Chromagram
cannam@0 161 const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1;
cannam@3 162 for (unsigned octave = 0; octave <= octaves; octave++)
cannam@0 163 {
cannam@0 164 unsigned firstBin = octave*m_BPO;
cannam@3 165 for (unsigned i = 0; i < m_BPO; i++)
cannam@0 166 {
cannam@0 167 m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
cannam@0 168 }
cannam@0 169 }
cannam@0 170
cannam@34 171 MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
cannam@0 172
cannam@0 173 return m_chromadata;
cannam@0 174 }
cannam@0 175
cannam@0 176