annotate dsp/onsets/DetectionFunction.cpp @ 321:f1e6be2de9a5

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