annotate dsp/onsets/DetectionFunction.cpp @ 191:857ca50ca25f

Add DCT
author Chris Cannam
date Wed, 07 Oct 2015 09:55:35 +0100
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