annotate dsp/onsets/DetectionFunction.cpp @ 345:04d134031a15

Comments
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 03 Oct 2013 13:03:31 +0100
parents 5eb9c2387108
children 2053a308bb4d
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@340 43 m_halfLength = m_dataLength/2 + 1;
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@344 66 // See note in processTimeDomain below
c@289 67 int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
c@340 68 m_phaseVoc = new PhaseVocoder(actualLength, m_stepSize);
c@225 69
c@225 70 m_magnitude = new double[ m_halfLength ];
c@225 71 m_thetaAngle = new double[ m_halfLength ];
c@340 72 m_unwrapped = new double[ m_halfLength ];
c@225 73
c@225 74 m_window = new Window<double>(HanningWindow, m_dataLength);
c@344 75 m_windowed = new double[ m_dataLength ];
c@225 76 }
c@225 77
c@225 78 void DetectionFunction::deInitialise()
c@225 79 {
c@227 80 delete [] m_magHistory ;
c@227 81 delete [] m_phaseHistory ;
c@227 82 delete [] m_phaseHistoryOld ;
c@239 83 delete [] m_magPeaks ;
c@225 84
c@225 85 delete m_phaseVoc;
c@225 86
c@225 87 delete [] m_magnitude;
c@225 88 delete [] m_thetaAngle;
c@344 89 delete [] m_windowed;
c@344 90 delete [] m_unwrapped;
c@225 91
c@225 92 delete m_window;
c@225 93 }
c@225 94
c@344 95 double DetectionFunction::processTimeDomain(const double *samples)
c@225 96 {
c@344 97 m_window->cut(samples, m_windowed);
c@280 98
c@280 99 // Our own FFT implementation supports power-of-two sizes only.
c@280 100 // If we have to use this implementation (as opposed to the
c@280 101 // version of process() below that operates on frequency domain
c@280 102 // data directly), we will have to use the next smallest power of
c@280 103 // two from the block size. Results may vary accordingly!
c@280 104
c@331 105 int actualLength = MathUtilities::previousPowerOfTwo((int)m_dataLength);
c@280 106
c@325 107 if (actualLength != (int)m_dataLength) {
c@280 108 // Pre-fill mag and phase vectors with zero, as the FFT output
c@280 109 // will not fill the arrays
c@325 110 for (int i = actualLength/2; i < (int)m_dataLength/2; ++i) {
c@280 111 m_magnitude[i] = 0;
c@280 112 m_thetaAngle[0] = 0;
c@280 113 }
c@280 114 }
c@280 115
c@344 116 m_phaseVoc->processTimeDomain(m_windowed,
c@344 117 m_magnitude, m_thetaAngle, m_unwrapped);
c@225 118
c@239 119 if (m_whiten) whiten();
c@239 120
c@227 121 return runDF();
c@227 122 }
c@227 123
c@344 124 double DetectionFunction::processFrequencyDomain(const double *reals,
c@344 125 const double *imags)
c@227 126 {
c@344 127 m_phaseVoc->processFrequencyDomain(reals, imags,
c@344 128 m_magnitude, m_thetaAngle, m_unwrapped);
c@227 129
c@239 130 if (m_whiten) whiten();
c@239 131
c@227 132 return runDF();
c@227 133 }
c@227 134
c@239 135 void DetectionFunction::whiten()
c@239 136 {
c@239 137 for (unsigned int i = 0; i < m_halfLength; ++i) {
c@239 138 double m = m_magnitude[i];
c@239 139 if (m < m_magPeaks[i]) {
c@239 140 m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
c@239 141 }
c@239 142 if (m < m_whitenFloor) m = m_whitenFloor;
c@239 143 m_magPeaks[i] = m;
c@239 144 m_magnitude[i] /= m;
c@239 145 }
c@239 146 }
c@239 147
c@227 148 double DetectionFunction::runDF()
c@227 149 {
c@227 150 double retVal = 0;
c@227 151
c@225 152 switch( m_DFType )
c@225 153 {
c@225 154 case DF_HFC:
c@225 155 retVal = HFC( m_halfLength, m_magnitude);
c@225 156 break;
c@225 157
c@238 158 case DF_SPECDIFF:
c@225 159 retVal = specDiff( m_halfLength, m_magnitude);
c@225 160 break;
c@225 161
c@225 162 case DF_PHASEDEV:
c@345 163 // Using the instantaneous phases here actually provides the
c@345 164 // same results (for these calculations) as if we had used
c@345 165 // unwrapped phases, but without the possible accumulation of
c@345 166 // phase error over time
c@239 167 retVal = phaseDev( m_halfLength, m_thetaAngle);
c@225 168 break;
c@225 169
c@225 170 case DF_COMPLEXSD:
c@225 171 retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
c@225 172 break;
c@237 173
c@237 174 case DF_BROADBAND:
c@239 175 retVal = broadband( m_halfLength, m_magnitude);
c@239 176 break;
c@225 177 }
c@225 178
c@225 179 return retVal;
c@225 180 }
c@225 181
c@225 182 double DetectionFunction::HFC(unsigned int length, double *src)
c@225 183 {
c@225 184 unsigned int i;
c@225 185 double val = 0;
c@225 186
c@225 187 for( i = 0; i < length; i++)
c@225 188 {
c@225 189 val += src[ i ] * ( i + 1);
c@225 190 }
c@225 191 return val;
c@225 192 }
c@225 193
c@225 194 double DetectionFunction::specDiff(unsigned int length, double *src)
c@225 195 {
c@225 196 unsigned int i;
c@225 197 double val = 0.0;
c@225 198 double temp = 0.0;
c@225 199 double diff = 0.0;
c@225 200
c@225 201 for( i = 0; i < length; i++)
c@225 202 {
c@227 203 temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
c@225 204
c@225 205 diff= sqrt(temp);
c@225 206
c@238 207 // (See note in phaseDev below.)
c@238 208
c@238 209 val += diff;
c@225 210
c@227 211 m_magHistory[ i ] = src[ i ];
c@225 212 }
c@225 213
c@225 214 return val;
c@225 215 }
c@225 216
c@225 217
c@239 218 double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
c@225 219 {
c@225 220 unsigned int i;
c@225 221 double tmpPhase = 0;
c@225 222 double tmpVal = 0;
c@225 223 double val = 0;
c@225 224
c@225 225 double dev = 0;
c@225 226
c@225 227 for( i = 0; i < length; i++)
c@225 228 {
c@227 229 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
c@225 230 dev = MathUtilities::princarg( tmpPhase );
c@238 231
c@238 232 // A previous version of this code only counted the value here
c@238 233 // if the magnitude exceeded 0.1. My impression is that
c@238 234 // doesn't greatly improve the results for "loud" music (so
c@238 235 // long as the peak picker is reasonably sophisticated), but
c@238 236 // does significantly damage its ability to work with quieter
c@238 237 // music, so I'm removing it and counting the result always.
c@238 238 // Same goes for the spectral difference measure above.
c@225 239
c@238 240 tmpVal = fabs(dev);
c@238 241 val += tmpVal ;
c@225 242
c@227 243 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
c@227 244 m_phaseHistory[ i ] = srcPhase[ i ];
c@225 245 }
c@225 246
c@225 247 return val;
c@225 248 }
c@225 249
c@225 250
c@225 251 double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
c@225 252 {
c@225 253 unsigned int i;
c@225 254 double val = 0;
c@225 255 double tmpPhase = 0;
c@225 256 double tmpReal = 0;
c@225 257 double tmpImag = 0;
c@225 258
c@225 259 double dev = 0;
c@225 260 ComplexData meas = ComplexData( 0, 0 );
c@227 261 ComplexData j = ComplexData( 0, 1 );
c@225 262
c@225 263 for( i = 0; i < length; i++)
c@225 264 {
c@227 265 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
c@225 266 dev= MathUtilities::princarg( tmpPhase );
c@225 267
c@227 268 meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
c@225 269
c@225 270 tmpReal = real( meas );
c@225 271 tmpImag = imag( meas );
c@225 272
c@225 273 val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
c@225 274
c@227 275 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
c@227 276 m_phaseHistory[ i ] = srcPhase[ i ];
c@227 277 m_magHistory[ i ] = srcMagnitude[ i ];
c@225 278 }
c@225 279
c@225 280 return val;
c@225 281 }
c@225 282
c@239 283 double DetectionFunction::broadband(unsigned int length, double *src)
c@237 284 {
c@237 285 double val = 0;
c@237 286 for (unsigned int i = 0; i < length; ++i) {
c@239 287 double sqrmag = src[i] * src[i];
c@237 288 if (m_magHistory[i] > 0.0) {
c@237 289 double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
c@237 290 if (diff > m_dbRise) val = val + 1;
c@237 291 }
c@237 292 m_magHistory[i] = sqrmag;
c@237 293 }
c@237 294 return val;
c@237 295 }
c@237 296
c@225 297 double* DetectionFunction::getSpectrumMagnitude()
c@225 298 {
c@225 299 return m_magnitude;
c@225 300 }
c@225 301