| 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 |