annotate dsp/onsets/DetectionFunction.cpp @ 14:68801ecbab6a

* add adaptive whitening and simple power metric
author cannam
date Thu, 09 Aug 2007 16:30:26 +0000
parents f2b5c4251bf3
children 2e3f5d2d62c1
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 "DetectionFunction.h"
cannam@0 12
cannam@0 13 //////////////////////////////////////////////////////////////////////
cannam@0 14 // Construction/Destruction
cannam@0 15 //////////////////////////////////////////////////////////////////////
cannam@0 16
cannam@0 17 DetectionFunction::DetectionFunction( DFConfig Config ) :
cannam@0 18 m_window(0)
cannam@0 19 {
cannam@2 20 m_magHistory = NULL;
cannam@2 21 m_phaseHistory = NULL;
cannam@2 22 m_phaseHistoryOld = NULL;
cannam@14 23 m_magPeaks = NULL;
cannam@0 24
cannam@0 25 initialise( Config );
cannam@0 26 }
cannam@0 27
cannam@0 28 DetectionFunction::~DetectionFunction()
cannam@0 29 {
cannam@0 30 deInitialise();
cannam@0 31 }
cannam@0 32
cannam@0 33
cannam@0 34 void DetectionFunction::initialise( DFConfig Config )
cannam@0 35 {
cannam@0 36 m_dataLength = Config.frameLength;
cannam@0 37 m_halfLength = m_dataLength/2;
cannam@14 38
cannam@0 39 m_DFType = Config.DFType;
cannam@13 40 m_stepSecs = Config.stepSecs;
cannam@13 41 m_stepSize = Config.stepSize;
cannam@0 42
cannam@14 43 m_whiten = Config.adaptiveWhitening;
cannam@14 44 m_whitenRelaxCoeff = Config.whiteningRelaxCoeff;
cannam@14 45 m_whitenFloor = Config.whiteningFloor;
cannam@14 46 if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
cannam@14 47 if (m_whitenFloor < 0) m_whitenFloor = 0.01;
cannam@14 48
cannam@2 49 m_magHistory = new double[ m_halfLength ];
cannam@2 50 memset(m_magHistory,0, m_halfLength*sizeof(double));
cannam@0 51
cannam@2 52 m_phaseHistory = new double[ m_halfLength ];
cannam@2 53 memset(m_phaseHistory,0, m_halfLength*sizeof(double));
cannam@0 54
cannam@2 55 m_phaseHistoryOld = new double[ m_halfLength ];
cannam@2 56 memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
cannam@0 57
cannam@14 58 m_magPeaks = new double[ m_halfLength ];
cannam@14 59 memset(m_magPeaks,0, m_halfLength*sizeof(double));
cannam@14 60
cannam@0 61 m_phaseVoc = new PhaseVocoder;
cannam@0 62
cannam@0 63 m_DFWindowedFrame = new double[ m_dataLength ];
cannam@0 64 m_magnitude = new double[ m_halfLength ];
cannam@0 65 m_thetaAngle = new double[ m_halfLength ];
cannam@0 66
cannam@0 67 m_window = new Window<double>(HanningWindow, m_dataLength);
cannam@0 68 }
cannam@0 69
cannam@0 70 void DetectionFunction::deInitialise()
cannam@0 71 {
cannam@2 72 delete [] m_magHistory ;
cannam@2 73 delete [] m_phaseHistory ;
cannam@2 74 delete [] m_phaseHistoryOld ;
cannam@14 75 delete [] m_magPeaks ;
cannam@0 76
cannam@0 77 delete m_phaseVoc;
cannam@0 78
cannam@0 79 delete [] m_DFWindowedFrame;
cannam@0 80 delete [] m_magnitude;
cannam@0 81 delete [] m_thetaAngle;
cannam@0 82
cannam@0 83 delete m_window;
cannam@0 84 }
cannam@0 85
cannam@0 86 double DetectionFunction::process( double *TDomain )
cannam@0 87 {
cannam@0 88 m_window->cut( TDomain, m_DFWindowedFrame );
cannam@0 89
cannam@0 90 m_phaseVoc->process( m_dataLength, m_DFWindowedFrame, m_magnitude, m_thetaAngle );
cannam@0 91
cannam@14 92 if (m_whiten) whiten();
cannam@14 93
cannam@2 94 return runDF();
cannam@2 95 }
cannam@2 96
cannam@2 97 double DetectionFunction::process( double *magnitudes, double *phases )
cannam@2 98 {
cannam@2 99 for (size_t i = 0; i < m_halfLength; ++i) {
cannam@2 100 m_magnitude[i] = magnitudes[i];
cannam@2 101 m_thetaAngle[i] = phases[i];
cannam@2 102 }
cannam@2 103
cannam@14 104 if (m_whiten) whiten();
cannam@14 105
cannam@2 106 return runDF();
cannam@2 107 }
cannam@2 108
cannam@14 109 void DetectionFunction::whiten()
cannam@14 110 {
cannam@14 111 for (unsigned int i = 0; i < m_halfLength; ++i) {
cannam@14 112 double m = m_magnitude[i];
cannam@14 113 if (m < m_magPeaks[i]) {
cannam@14 114 m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
cannam@14 115 }
cannam@14 116 if (m < m_whitenFloor) m = m_whitenFloor;
cannam@14 117 m_magPeaks[i] = m;
cannam@14 118 m_magnitude[i] /= m;
cannam@14 119 }
cannam@14 120 }
cannam@14 121
cannam@2 122 double DetectionFunction::runDF()
cannam@2 123 {
cannam@2 124 double retVal = 0;
cannam@2 125
cannam@0 126 switch( m_DFType )
cannam@0 127 {
cannam@0 128 case DF_HFC:
cannam@0 129 retVal = HFC( m_halfLength, m_magnitude);
cannam@0 130 break;
cannam@0 131
cannam@13 132 case DF_SPECDIFF:
cannam@0 133 retVal = specDiff( m_halfLength, m_magnitude);
cannam@0 134 break;
cannam@0 135
cannam@0 136 case DF_PHASEDEV:
cannam@14 137 retVal = phaseDev( m_halfLength, m_thetaAngle);
cannam@0 138 break;
cannam@0 139
cannam@0 140 case DF_COMPLEXSD:
cannam@0 141 retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
cannam@0 142 break;
cannam@12 143
cannam@12 144 case DF_BROADBAND:
cannam@14 145 retVal = broadband( m_halfLength, m_magnitude);
cannam@14 146 break;
cannam@14 147
cannam@14 148 case DF_POWER:
cannam@14 149 retVal = power( m_halfLength, m_magnitude );
cannam@14 150 break;
cannam@0 151 }
cannam@0 152
cannam@0 153 return retVal;
cannam@0 154 }
cannam@0 155
cannam@0 156 double DetectionFunction::HFC(unsigned int length, double *src)
cannam@0 157 {
cannam@0 158 unsigned int i;
cannam@0 159 double val = 0;
cannam@0 160
cannam@0 161 for( i = 0; i < length; i++)
cannam@0 162 {
cannam@0 163 val += src[ i ] * ( i + 1);
cannam@0 164 }
cannam@0 165 return val;
cannam@0 166 }
cannam@0 167
cannam@0 168 double DetectionFunction::specDiff(unsigned int length, double *src)
cannam@0 169 {
cannam@0 170 unsigned int i;
cannam@0 171 double val = 0.0;
cannam@0 172 double temp = 0.0;
cannam@0 173 double diff = 0.0;
cannam@0 174
cannam@0 175 for( i = 0; i < length; i++)
cannam@0 176 {
cannam@2 177 temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
cannam@0 178
cannam@0 179 diff= sqrt(temp);
cannam@0 180
cannam@13 181 // (See note in phaseDev below.)
cannam@13 182
cannam@13 183 val += diff;
cannam@0 184
cannam@2 185 m_magHistory[ i ] = src[ i ];
cannam@0 186 }
cannam@0 187
cannam@0 188 return val;
cannam@0 189 }
cannam@0 190
cannam@0 191
cannam@14 192 double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
cannam@0 193 {
cannam@0 194 unsigned int i;
cannam@0 195 double tmpPhase = 0;
cannam@0 196 double tmpVal = 0;
cannam@0 197 double val = 0;
cannam@0 198
cannam@0 199 double dev = 0;
cannam@0 200
cannam@0 201 for( i = 0; i < length; i++)
cannam@0 202 {
cannam@2 203 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 204 dev = MathUtilities::princarg( tmpPhase );
cannam@13 205
cannam@13 206 // A previous version of this code only counted the value here
cannam@13 207 // if the magnitude exceeded 0.1. My impression is that
cannam@13 208 // doesn't greatly improve the results for "loud" music (so
cannam@13 209 // long as the peak picker is reasonably sophisticated), but
cannam@13 210 // does significantly damage its ability to work with quieter
cannam@13 211 // music, so I'm removing it and counting the result always.
cannam@13 212 // Same goes for the spectral difference measure above.
cannam@0 213
cannam@13 214 tmpVal = fabs(dev);
cannam@13 215 val += tmpVal ;
cannam@0 216
cannam@2 217 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 218 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@0 219 }
cannam@0 220
cannam@0 221
cannam@0 222 return val;
cannam@0 223 }
cannam@0 224
cannam@0 225
cannam@0 226 double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
cannam@0 227 {
cannam@0 228 unsigned int i;
cannam@0 229 double val = 0;
cannam@0 230 double tmpPhase = 0;
cannam@0 231 double tmpReal = 0;
cannam@0 232 double tmpImag = 0;
cannam@0 233
cannam@0 234 double dev = 0;
cannam@0 235 ComplexData meas = ComplexData( 0, 0 );
cannam@2 236 ComplexData j = ComplexData( 0, 1 );
cannam@0 237
cannam@0 238 for( i = 0; i < length; i++)
cannam@0 239 {
cannam@2 240 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 241 dev= MathUtilities::princarg( tmpPhase );
cannam@0 242
cannam@2 243 meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
cannam@0 244
cannam@0 245 tmpReal = real( meas );
cannam@0 246 tmpImag = imag( meas );
cannam@0 247
cannam@0 248 val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
cannam@0 249
cannam@2 250 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 251 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@2 252 m_magHistory[ i ] = srcMagnitude[ i ];
cannam@0 253 }
cannam@0 254
cannam@0 255 return val;
cannam@0 256 }
cannam@0 257
cannam@14 258 double DetectionFunction::broadband(unsigned int length, double *src)
cannam@12 259 {
cannam@12 260 double val = 0;
cannam@12 261 for (unsigned int i = 0; i < length; ++i) {
cannam@14 262 double sqrmag = src[i] * src[i];
cannam@12 263 if (m_magHistory[i] > 0.0) {
cannam@12 264 double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
cannam@12 265 if (diff > m_dbRise) val = val + 1;
cannam@12 266 }
cannam@12 267 m_magHistory[i] = sqrmag;
cannam@12 268 }
cannam@12 269 return val;
cannam@12 270 }
cannam@12 271
cannam@14 272 double DetectionFunction::power(unsigned int length, double *src)
cannam@14 273 {
cannam@14 274 double val = 0;
cannam@14 275 for (unsigned int i = 0; i < length; ++i) {
cannam@14 276 val += src[i];
cannam@14 277 }
cannam@14 278 return val;
cannam@14 279 }
cannam@14 280
cannam@0 281 double* DetectionFunction::getSpectrumMagnitude()
cannam@0 282 {
cannam@0 283 return m_magnitude;
cannam@0 284 }
cannam@0 285