1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
6 Centre for Digital Music, Queen Mary, University of London.
7 This file 2005-2006 Christian Landone.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
16 #include "DetectionFunction.h"
19 //////////////////////////////////////////////////////////////////////
20 // Construction/Destruction
21 //////////////////////////////////////////////////////////////////////
23 DetectionFunction::DetectionFunction( DFConfig Config ) :
27 m_phaseHistory = NULL;
28 m_phaseHistoryOld = NULL;
34 DetectionFunction::~DetectionFunction()
40 void DetectionFunction::initialise( DFConfig Config )
42 m_dataLength = Config.frameLength;
43 m_halfLength = m_dataLength/2;
45 m_DFType = Config.DFType;
46 m_stepSize = Config.stepSize;
48 m_whiten = Config.adaptiveWhitening;
49 m_whitenRelaxCoeff = Config.whiteningRelaxCoeff;
50 m_whitenFloor = Config.whiteningFloor;
51 if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
52 if (m_whitenFloor < 0) m_whitenFloor = 0.01;
54 m_magHistory = new double[ m_halfLength ];
55 memset(m_magHistory,0, m_halfLength*sizeof(double));
57 m_phaseHistory = new double[ m_halfLength ];
58 memset(m_phaseHistory,0, m_halfLength*sizeof(double));
60 m_phaseHistoryOld = new double[ m_halfLength ];
61 memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
63 m_magPeaks = new double[ m_halfLength ];
64 memset(m_magPeaks,0, m_halfLength*sizeof(double));
66 // See note in process(const double *) below
67 int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
68 m_phaseVoc = new PhaseVocoder(actualLength);
70 m_DFWindowedFrame = new double[ m_dataLength ];
71 m_magnitude = new double[ m_halfLength ];
72 m_thetaAngle = new double[ m_halfLength ];
74 m_window = new Window<double>(HanningWindow, m_dataLength);
77 void DetectionFunction::deInitialise()
79 delete [] m_magHistory ;
80 delete [] m_phaseHistory ;
81 delete [] m_phaseHistoryOld ;
82 delete [] m_magPeaks ;
86 delete [] m_DFWindowedFrame;
87 delete [] m_magnitude;
88 delete [] m_thetaAngle;
93 double DetectionFunction::process( const double *TDomain )
95 m_window->cut( TDomain, m_DFWindowedFrame );
97 // Our own FFT implementation supports power-of-two sizes only.
98 // If we have to use this implementation (as opposed to the
99 // version of process() below that operates on frequency domain
100 // data directly), we will have to use the next smallest power of
101 // two from the block size. Results may vary accordingly!
103 unsigned int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
105 if (actualLength != m_dataLength) {
106 // Pre-fill mag and phase vectors with zero, as the FFT output
107 // will not fill the arrays
108 for (unsigned int i = actualLength/2; i < m_dataLength/2; ++i) {
114 m_phaseVoc->process(m_DFWindowedFrame, m_magnitude, m_thetaAngle);
116 if (m_whiten) whiten();
121 double DetectionFunction::process( const double *magnitudes, const double *phases )
123 for (size_t i = 0; i < m_halfLength; ++i) {
124 m_magnitude[i] = magnitudes[i];
125 m_thetaAngle[i] = phases[i];
128 if (m_whiten) whiten();
133 void DetectionFunction::whiten()
135 for (unsigned int i = 0; i < m_halfLength; ++i) {
136 double m = m_magnitude[i];
137 if (m < m_magPeaks[i]) {
138 m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
140 if (m < m_whitenFloor) m = m_whitenFloor;
146 double DetectionFunction::runDF()
153 retVal = HFC( m_halfLength, m_magnitude);
157 retVal = specDiff( m_halfLength, m_magnitude);
161 retVal = phaseDev( m_halfLength, m_thetaAngle);
165 retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
169 retVal = broadband( m_halfLength, m_magnitude);
176 double DetectionFunction::HFC(unsigned int length, double *src)
181 for( i = 0; i < length; i++)
183 val += src[ i ] * ( i + 1);
188 double DetectionFunction::specDiff(unsigned int length, double *src)
195 for( i = 0; i < length; i++)
197 temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
201 // (See note in phaseDev below.)
205 m_magHistory[ i ] = src[ i ];
212 double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
221 for( i = 0; i < length; i++)
223 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
224 dev = MathUtilities::princarg( tmpPhase );
226 // A previous version of this code only counted the value here
227 // if the magnitude exceeded 0.1. My impression is that
228 // doesn't greatly improve the results for "loud" music (so
229 // long as the peak picker is reasonably sophisticated), but
230 // does significantly damage its ability to work with quieter
231 // music, so I'm removing it and counting the result always.
232 // Same goes for the spectral difference measure above.
237 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
238 m_phaseHistory[ i ] = srcPhase[ i ];
246 double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
255 ComplexData meas = ComplexData( 0, 0 );
256 ComplexData j = ComplexData( 0, 1 );
258 for( i = 0; i < length; i++)
260 tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
261 dev= MathUtilities::princarg( tmpPhase );
263 meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
265 tmpReal = real( meas );
266 tmpImag = imag( meas );
268 val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
270 m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
271 m_phaseHistory[ i ] = srcPhase[ i ];
272 m_magHistory[ i ] = srcMagnitude[ i ];
278 double DetectionFunction::broadband(unsigned int length, double *src)
281 for (unsigned int i = 0; i < length; ++i) {
282 double sqrmag = src[i] * src[i];
283 if (m_magHistory[i] > 0.0) {
284 double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
285 if (diff > m_dbRise) val = val + 1;
287 m_magHistory[i] = sqrmag;
292 double* DetectionFunction::getSpectrumMagnitude()