annotate dsp/onsets/DetectionFunction.cpp @ 115:f3c69325cca2 pvoc

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