annotate dsp/onsets/DetectionFunction.cpp @ 96:88f3cfcff55f

A threshold (delta) is added in the peak picking parameters structure (PPickParams). It is used as an offset when computing the smoothed detection function. A constructor for the structure PPickParams is also added to set the parameters to 0 when a structure instance is created. Hence programmes using the peak picking parameter structure and which do not set the delta parameter (e.g. QM Vamp note onset detector) won't be affected by the modifications. Functions modified: - dsp/onsets/PeakPicking.cpp - dsp/onsets/PeakPicking.h - dsp/signalconditioning/DFProcess.cpp - dsp/signalconditioning/DFProcess.h
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Mon, 20 Jun 2011 19:01:48 +0100
parents e5907ae6de17
children 37449f085a4c
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.
Chris@84 7 This file 2005-2006 Christian Landone.
Chris@84 8
Chris@84 9 This program is free software; you can redistribute it and/or
Chris@84 10 modify it under the terms of the GNU General Public License as
Chris@84 11 published by the Free Software Foundation; either version 2 of the
Chris@84 12 License, or (at your option) any later version. See the file
Chris@84 13 COPYING included with this distribution for more information.
cannam@0 14 */
cannam@0 15
cannam@0 16 #include "DetectionFunction.h"
cannam@47 17 #include <cstring>
cannam@0 18
cannam@0 19 //////////////////////////////////////////////////////////////////////
cannam@0 20 // Construction/Destruction
cannam@0 21 //////////////////////////////////////////////////////////////////////
cannam@0 22
cannam@0 23 DetectionFunction::DetectionFunction( DFConfig Config ) :
cannam@0 24 m_window(0)
cannam@0 25 {
cannam@2 26 m_magHistory = NULL;
cannam@2 27 m_phaseHistory = NULL;
cannam@2 28 m_phaseHistoryOld = NULL;
cannam@14 29 m_magPeaks = NULL;
cannam@0 30
cannam@0 31 initialise( Config );
cannam@0 32 }
cannam@0 33
cannam@0 34 DetectionFunction::~DetectionFunction()
cannam@0 35 {
cannam@0 36 deInitialise();
cannam@0 37 }
cannam@0 38
cannam@0 39
cannam@0 40 void DetectionFunction::initialise( DFConfig Config )
cannam@0 41 {
cannam@0 42 m_dataLength = Config.frameLength;
cannam@0 43 m_halfLength = m_dataLength/2;
cannam@14 44
cannam@0 45 m_DFType = Config.DFType;
cannam@13 46 m_stepSize = Config.stepSize;
cannam@0 47
cannam@14 48 m_whiten = Config.adaptiveWhitening;
cannam@14 49 m_whitenRelaxCoeff = Config.whiteningRelaxCoeff;
cannam@14 50 m_whitenFloor = Config.whiteningFloor;
cannam@14 51 if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
cannam@14 52 if (m_whitenFloor < 0) m_whitenFloor = 0.01;
cannam@14 53
cannam@2 54 m_magHistory = new double[ m_halfLength ];
cannam@2 55 memset(m_magHistory,0, m_halfLength*sizeof(double));
cannam@0 56
cannam@2 57 m_phaseHistory = new double[ m_halfLength ];
cannam@2 58 memset(m_phaseHistory,0, m_halfLength*sizeof(double));
cannam@0 59
cannam@2 60 m_phaseHistoryOld = new double[ m_halfLength ];
cannam@2 61 memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
cannam@0 62
cannam@14 63 m_magPeaks = new double[ m_halfLength ];
cannam@14 64 memset(m_magPeaks,0, m_halfLength*sizeof(double));
cannam@14 65
cannam@64 66 // See note in process(const double *) below
cannam@64 67 int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
cannam@64 68 m_phaseVoc = new PhaseVocoder(actualLength);
cannam@0 69
cannam@0 70 m_DFWindowedFrame = new double[ m_dataLength ];
cannam@0 71 m_magnitude = new double[ m_halfLength ];
cannam@0 72 m_thetaAngle = new double[ m_halfLength ];
cannam@0 73
cannam@0 74 m_window = new Window<double>(HanningWindow, m_dataLength);
cannam@0 75 }
cannam@0 76
cannam@0 77 void DetectionFunction::deInitialise()
cannam@0 78 {
cannam@2 79 delete [] m_magHistory ;
cannam@2 80 delete [] m_phaseHistory ;
cannam@2 81 delete [] m_phaseHistoryOld ;
cannam@14 82 delete [] m_magPeaks ;
cannam@0 83
cannam@0 84 delete m_phaseVoc;
cannam@0 85
cannam@0 86 delete [] m_DFWindowedFrame;
cannam@0 87 delete [] m_magnitude;
cannam@0 88 delete [] m_thetaAngle;
cannam@0 89
cannam@0 90 delete m_window;
cannam@0 91 }
cannam@0 92
cannam@55 93 double DetectionFunction::process( const double *TDomain )
cannam@0 94 {
cannam@0 95 m_window->cut( TDomain, m_DFWindowedFrame );
cannam@55 96
cannam@55 97 // Our own FFT implementation supports power-of-two sizes only.
cannam@55 98 // If we have to use this implementation (as opposed to the
cannam@55 99 // version of process() below that operates on frequency domain
cannam@55 100 // data directly), we will have to use the next smallest power of
cannam@55 101 // two from the block size. Results may vary accordingly!
cannam@55 102
cannam@55 103 int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
cannam@55 104
cannam@55 105 if (actualLength != m_dataLength) {
cannam@55 106 // Pre-fill mag and phase vectors with zero, as the FFT output
cannam@55 107 // will not fill the arrays
cannam@55 108 for (int i = actualLength/2; i < m_dataLength/2; ++i) {
cannam@55 109 m_magnitude[i] = 0;
cannam@55 110 m_thetaAngle[0] = 0;
cannam@55 111 }
cannam@55 112 }
cannam@55 113
cannam@64 114 m_phaseVoc->process(m_DFWindowedFrame, m_magnitude, m_thetaAngle);
cannam@0 115
cannam@14 116 if (m_whiten) whiten();
cannam@14 117
cannam@2 118 return runDF();
cannam@2 119 }
cannam@2 120
cannam@55 121 double DetectionFunction::process( const double *magnitudes, const double *phases )
cannam@2 122 {
cannam@2 123 for (size_t i = 0; i < m_halfLength; ++i) {
cannam@2 124 m_magnitude[i] = magnitudes[i];
cannam@2 125 m_thetaAngle[i] = phases[i];
cannam@2 126 }
cannam@2 127
cannam@14 128 if (m_whiten) whiten();
cannam@14 129
cannam@2 130 return runDF();
cannam@2 131 }
cannam@2 132
cannam@14 133 void DetectionFunction::whiten()
cannam@14 134 {
cannam@14 135 for (unsigned int i = 0; i < m_halfLength; ++i) {
cannam@14 136 double m = m_magnitude[i];
cannam@14 137 if (m < m_magPeaks[i]) {
cannam@14 138 m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
cannam@14 139 }
cannam@14 140 if (m < m_whitenFloor) m = m_whitenFloor;
cannam@14 141 m_magPeaks[i] = m;
cannam@14 142 m_magnitude[i] /= m;
cannam@14 143 }
cannam@14 144 }
cannam@14 145
cannam@2 146 double DetectionFunction::runDF()
cannam@2 147 {
cannam@2 148 double retVal = 0;
cannam@2 149
cannam@0 150 switch( m_DFType )
cannam@0 151 {
cannam@0 152 case DF_HFC:
cannam@0 153 retVal = HFC( m_halfLength, m_magnitude);
cannam@0 154 break;
cannam@0 155
cannam@13 156 case DF_SPECDIFF:
cannam@0 157 retVal = specDiff( m_halfLength, m_magnitude);
cannam@0 158 break;
cannam@0 159
cannam@0 160 case DF_PHASEDEV:
cannam@14 161 retVal = phaseDev( m_halfLength, m_thetaAngle);
cannam@0 162 break;
cannam@0 163
cannam@0 164 case DF_COMPLEXSD:
cannam@0 165 retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
cannam@0 166 break;
cannam@12 167
cannam@12 168 case DF_BROADBAND:
cannam@14 169 retVal = broadband( m_halfLength, m_magnitude);
cannam@14 170 break;
cannam@0 171 }
cannam@0 172
cannam@0 173 return retVal;
cannam@0 174 }
cannam@0 175
cannam@0 176 double DetectionFunction::HFC(unsigned int length, double *src)
cannam@0 177 {
cannam@0 178 unsigned int i;
cannam@0 179 double val = 0;
cannam@0 180
cannam@0 181 for( i = 0; i < length; i++)
cannam@0 182 {
cannam@0 183 val += src[ i ] * ( i + 1);
cannam@0 184 }
cannam@0 185 return val;
cannam@0 186 }
cannam@0 187
cannam@0 188 double DetectionFunction::specDiff(unsigned int length, double *src)
cannam@0 189 {
cannam@0 190 unsigned int i;
cannam@0 191 double val = 0.0;
cannam@0 192 double temp = 0.0;
cannam@0 193 double diff = 0.0;
cannam@0 194
cannam@0 195 for( i = 0; i < length; i++)
cannam@0 196 {
cannam@2 197 temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
cannam@0 198
cannam@0 199 diff= sqrt(temp);
cannam@0 200
cannam@13 201 // (See note in phaseDev below.)
cannam@13 202
cannam@13 203 val += diff;
cannam@0 204
cannam@2 205 m_magHistory[ i ] = src[ i ];
cannam@0 206 }
cannam@0 207
cannam@0 208 return val;
cannam@0 209 }
cannam@0 210
cannam@0 211
cannam@14 212 double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
cannam@0 213 {
cannam@0 214 unsigned int i;
cannam@0 215 double tmpPhase = 0;
cannam@0 216 double tmpVal = 0;
cannam@0 217 double val = 0;
cannam@0 218
cannam@0 219 double dev = 0;
cannam@0 220
cannam@0 221 for( i = 0; i < length; i++)
cannam@0 222 {
cannam@2 223 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 224 dev = MathUtilities::princarg( tmpPhase );
cannam@13 225
cannam@13 226 // A previous version of this code only counted the value here
cannam@13 227 // if the magnitude exceeded 0.1. My impression is that
cannam@13 228 // doesn't greatly improve the results for "loud" music (so
cannam@13 229 // long as the peak picker is reasonably sophisticated), but
cannam@13 230 // does significantly damage its ability to work with quieter
cannam@13 231 // music, so I'm removing it and counting the result always.
cannam@13 232 // Same goes for the spectral difference measure above.
cannam@0 233
cannam@13 234 tmpVal = fabs(dev);
cannam@13 235 val += tmpVal ;
cannam@0 236
cannam@2 237 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 238 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@0 239 }
cannam@0 240
cannam@0 241
cannam@0 242 return val;
cannam@0 243 }
cannam@0 244
cannam@0 245
cannam@0 246 double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
cannam@0 247 {
cannam@0 248 unsigned int i;
cannam@0 249 double val = 0;
cannam@0 250 double tmpPhase = 0;
cannam@0 251 double tmpReal = 0;
cannam@0 252 double tmpImag = 0;
cannam@0 253
cannam@0 254 double dev = 0;
cannam@0 255 ComplexData meas = ComplexData( 0, 0 );
cannam@2 256 ComplexData j = ComplexData( 0, 1 );
cannam@0 257
cannam@0 258 for( i = 0; i < length; i++)
cannam@0 259 {
cannam@2 260 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 261 dev= MathUtilities::princarg( tmpPhase );
cannam@0 262
cannam@2 263 meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
cannam@0 264
cannam@0 265 tmpReal = real( meas );
cannam@0 266 tmpImag = imag( meas );
cannam@0 267
cannam@0 268 val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
cannam@0 269
cannam@2 270 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 271 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@2 272 m_magHistory[ i ] = srcMagnitude[ i ];
cannam@0 273 }
cannam@0 274
cannam@0 275 return val;
cannam@0 276 }
cannam@0 277
cannam@14 278 double DetectionFunction::broadband(unsigned int length, double *src)
cannam@12 279 {
cannam@12 280 double val = 0;
cannam@12 281 for (unsigned int i = 0; i < length; ++i) {
cannam@14 282 double sqrmag = src[i] * src[i];
cannam@12 283 if (m_magHistory[i] > 0.0) {
cannam@12 284 double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
cannam@12 285 if (diff > m_dbRise) val = val + 1;
cannam@12 286 }
cannam@12 287 m_magHistory[i] = sqrmag;
cannam@12 288 }
cannam@12 289 return val;
cannam@12 290 }
cannam@12 291
cannam@0 292 double* DetectionFunction::getSpectrumMagnitude()
cannam@0 293 {
cannam@0 294 return m_magnitude;
cannam@0 295 }
cannam@0 296