annotate dsp/onsets/DetectionFunction.cpp @ 209:ccd2019190bf msvc

Some MSVC fixes, including (temporarily, probably) renaming the FFT source file to avoid getting it mixed up with the Vamp SDK one in our object dir
author Chris Cannam
date Thu, 01 Feb 2018 16:34:08 +0000
parents 2ae4ceb76ac3
children fdaa63607c15
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;
Chris@115 43 m_halfLength = m_dataLength/2 + 1;
cannam@14 44
cannam@0 45 m_DFType = Config.DFType;
cannam@13 46 m_stepSize = Config.stepSize;
Chris@185 47 m_dbRise = Config.dbRise;
cannam@0 48
cannam@14 49 m_whiten = Config.adaptiveWhitening;
cannam@14 50 m_whitenRelaxCoeff = Config.whiteningRelaxCoeff;
cannam@14 51 m_whitenFloor = Config.whiteningFloor;
cannam@14 52 if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
cannam@14 53 if (m_whitenFloor < 0) m_whitenFloor = 0.01;
cannam@14 54
cannam@2 55 m_magHistory = new double[ m_halfLength ];
cannam@2 56 memset(m_magHistory,0, m_halfLength*sizeof(double));
cannam@0 57
cannam@2 58 m_phaseHistory = new double[ m_halfLength ];
cannam@2 59 memset(m_phaseHistory,0, m_halfLength*sizeof(double));
cannam@0 60
cannam@2 61 m_phaseHistoryOld = new double[ m_halfLength ];
cannam@2 62 memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
cannam@0 63
cannam@14 64 m_magPeaks = new double[ m_halfLength ];
cannam@14 65 memset(m_magPeaks,0, m_halfLength*sizeof(double));
cannam@14 66
Chris@130 67 m_phaseVoc = new PhaseVocoder(m_dataLength, m_stepSize);
cannam@0 68
cannam@0 69 m_magnitude = new double[ m_halfLength ];
cannam@0 70 m_thetaAngle = new double[ m_halfLength ];
Chris@115 71 m_unwrapped = new double[ m_halfLength ];
cannam@0 72
cannam@0 73 m_window = new Window<double>(HanningWindow, m_dataLength);
Chris@119 74 m_windowed = new double[ 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_magnitude;
cannam@0 87 delete [] m_thetaAngle;
Chris@119 88 delete [] m_windowed;
Chris@119 89 delete [] m_unwrapped;
cannam@0 90
cannam@0 91 delete m_window;
cannam@0 92 }
cannam@0 93
Chris@119 94 double DetectionFunction::processTimeDomain(const double *samples)
cannam@0 95 {
Chris@119 96 m_window->cut(samples, m_windowed);
cannam@55 97
Chris@119 98 m_phaseVoc->processTimeDomain(m_windowed,
Chris@119 99 m_magnitude, m_thetaAngle, m_unwrapped);
cannam@0 100
cannam@14 101 if (m_whiten) whiten();
cannam@14 102
cannam@2 103 return runDF();
cannam@2 104 }
cannam@2 105
Chris@119 106 double DetectionFunction::processFrequencyDomain(const double *reals,
Chris@119 107 const double *imags)
cannam@2 108 {
Chris@119 109 m_phaseVoc->processFrequencyDomain(reals, imags,
Chris@119 110 m_magnitude, m_thetaAngle, m_unwrapped);
cannam@2 111
cannam@14 112 if (m_whiten) whiten();
cannam@14 113
cannam@2 114 return runDF();
cannam@2 115 }
cannam@2 116
cannam@14 117 void DetectionFunction::whiten()
cannam@14 118 {
cannam@14 119 for (unsigned int i = 0; i < m_halfLength; ++i) {
cannam@14 120 double m = m_magnitude[i];
cannam@14 121 if (m < m_magPeaks[i]) {
cannam@14 122 m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
cannam@14 123 }
cannam@14 124 if (m < m_whitenFloor) m = m_whitenFloor;
cannam@14 125 m_magPeaks[i] = m;
cannam@14 126 m_magnitude[i] /= m;
cannam@14 127 }
cannam@14 128 }
cannam@14 129
cannam@2 130 double DetectionFunction::runDF()
cannam@2 131 {
cannam@2 132 double retVal = 0;
cannam@2 133
cannam@0 134 switch( m_DFType )
cannam@0 135 {
cannam@0 136 case DF_HFC:
cannam@0 137 retVal = HFC( m_halfLength, m_magnitude);
cannam@0 138 break;
cannam@0 139
cannam@13 140 case DF_SPECDIFF:
cannam@0 141 retVal = specDiff( m_halfLength, m_magnitude);
cannam@0 142 break;
cannam@0 143
cannam@0 144 case DF_PHASEDEV:
Chris@120 145 // Using the instantaneous phases here actually provides the
Chris@120 146 // same results (for these calculations) as if we had used
Chris@120 147 // unwrapped phases, but without the possible accumulation of
Chris@120 148 // phase error over time
cannam@14 149 retVal = phaseDev( m_halfLength, m_thetaAngle);
cannam@0 150 break;
cannam@0 151
cannam@0 152 case DF_COMPLEXSD:
cannam@0 153 retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
cannam@0 154 break;
cannam@12 155
cannam@12 156 case DF_BROADBAND:
cannam@14 157 retVal = broadband( m_halfLength, m_magnitude);
cannam@14 158 break;
cannam@0 159 }
cannam@0 160
cannam@0 161 return retVal;
cannam@0 162 }
cannam@0 163
cannam@0 164 double DetectionFunction::HFC(unsigned int length, double *src)
cannam@0 165 {
cannam@0 166 unsigned int i;
cannam@0 167 double val = 0;
cannam@0 168
cannam@0 169 for( i = 0; i < length; i++)
cannam@0 170 {
cannam@0 171 val += src[ i ] * ( i + 1);
cannam@0 172 }
cannam@0 173 return val;
cannam@0 174 }
cannam@0 175
cannam@0 176 double DetectionFunction::specDiff(unsigned int length, double *src)
cannam@0 177 {
cannam@0 178 unsigned int i;
cannam@0 179 double val = 0.0;
cannam@0 180 double temp = 0.0;
cannam@0 181 double diff = 0.0;
cannam@0 182
cannam@0 183 for( i = 0; i < length; i++)
cannam@0 184 {
cannam@2 185 temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
cannam@0 186
cannam@0 187 diff= sqrt(temp);
cannam@0 188
cannam@13 189 // (See note in phaseDev below.)
cannam@13 190
cannam@13 191 val += diff;
cannam@0 192
cannam@2 193 m_magHistory[ i ] = src[ i ];
cannam@0 194 }
cannam@0 195
cannam@0 196 return val;
cannam@0 197 }
cannam@0 198
cannam@0 199
cannam@14 200 double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
cannam@0 201 {
cannam@0 202 unsigned int i;
cannam@0 203 double tmpPhase = 0;
cannam@0 204 double tmpVal = 0;
cannam@0 205 double val = 0;
cannam@0 206
cannam@0 207 double dev = 0;
cannam@0 208
cannam@0 209 for( i = 0; i < length; i++)
cannam@0 210 {
cannam@2 211 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 212 dev = MathUtilities::princarg( tmpPhase );
cannam@13 213
cannam@13 214 // A previous version of this code only counted the value here
cannam@13 215 // if the magnitude exceeded 0.1. My impression is that
cannam@13 216 // doesn't greatly improve the results for "loud" music (so
cannam@13 217 // long as the peak picker is reasonably sophisticated), but
cannam@13 218 // does significantly damage its ability to work with quieter
cannam@13 219 // music, so I'm removing it and counting the result always.
cannam@13 220 // Same goes for the spectral difference measure above.
cannam@0 221
cannam@13 222 tmpVal = fabs(dev);
cannam@13 223 val += tmpVal ;
cannam@0 224
cannam@2 225 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 226 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@0 227 }
cannam@0 228
cannam@0 229 return val;
cannam@0 230 }
cannam@0 231
cannam@0 232
cannam@0 233 double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
cannam@0 234 {
cannam@0 235 unsigned int i;
cannam@0 236 double val = 0;
cannam@0 237 double tmpPhase = 0;
cannam@0 238 double tmpReal = 0;
cannam@0 239 double tmpImag = 0;
cannam@0 240
cannam@0 241 double dev = 0;
cannam@0 242 ComplexData meas = ComplexData( 0, 0 );
cannam@2 243 ComplexData j = ComplexData( 0, 1 );
cannam@0 244
cannam@0 245 for( i = 0; i < length; i++)
cannam@0 246 {
cannam@2 247 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
cannam@0 248 dev= MathUtilities::princarg( tmpPhase );
cannam@0 249
cannam@2 250 meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
cannam@0 251
cannam@0 252 tmpReal = real( meas );
cannam@0 253 tmpImag = imag( meas );
cannam@0 254
cannam@0 255 val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
cannam@0 256
cannam@2 257 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
cannam@2 258 m_phaseHistory[ i ] = srcPhase[ i ];
cannam@2 259 m_magHistory[ i ] = srcMagnitude[ i ];
cannam@0 260 }
cannam@0 261
cannam@0 262 return val;
cannam@0 263 }
cannam@0 264
cannam@14 265 double DetectionFunction::broadband(unsigned int length, double *src)
cannam@12 266 {
cannam@12 267 double val = 0;
cannam@12 268 for (unsigned int i = 0; i < length; ++i) {
cannam@14 269 double sqrmag = src[i] * src[i];
cannam@12 270 if (m_magHistory[i] > 0.0) {
cannam@12 271 double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
cannam@12 272 if (diff > m_dbRise) val = val + 1;
cannam@12 273 }
cannam@12 274 m_magHistory[i] = sqrmag;
cannam@12 275 }
cannam@12 276 return val;
cannam@12 277 }
cannam@12 278
cannam@0 279 double* DetectionFunction::getSpectrumMagnitude()
cannam@0 280 {
cannam@0 281 return m_magnitude;
cannam@0 282 }
cannam@0 283