DetectionFunction.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  QM DSP Library
5 
6  Centre for Digital Music, Queen Mary, University of London.
7  This file 2005-2006 Christian Landone.
8 
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.
14 */
15 
16 #include "DetectionFunction.h"
17 #include <cstring>
18 
20 // Construction/Destruction
22 
24  m_window(0)
25 {
26  m_magHistory = NULL;
27  m_phaseHistory = NULL;
28  m_phaseHistoryOld = NULL;
29  m_magPeaks = NULL;
30 
31  initialise( config );
32 }
33 
35 {
36  deInitialise();
37 }
38 
39 
41 {
42  m_dataLength = Config.frameLength;
43  m_halfLength = m_dataLength/2 + 1;
44 
45  m_DFType = Config.DFType;
46  m_stepSize = Config.stepSize;
47  m_dbRise = Config.dbRise;
48 
49  m_whiten = Config.adaptiveWhitening;
52  if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
53  if (m_whitenFloor < 0) m_whitenFloor = 0.01;
54 
55  m_magHistory = new double[ m_halfLength ];
56  memset(m_magHistory,0, m_halfLength*sizeof(double));
57 
58  m_phaseHistory = new double[ m_halfLength ];
59  memset(m_phaseHistory,0, m_halfLength*sizeof(double));
60 
61  m_phaseHistoryOld = new double[ m_halfLength ];
62  memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
63 
64  m_magPeaks = new double[ m_halfLength ];
65  memset(m_magPeaks,0, m_halfLength*sizeof(double));
66 
68 
69  m_magnitude = new double[ m_halfLength ];
70  m_thetaAngle = new double[ m_halfLength ];
71  m_unwrapped = new double[ m_halfLength ];
72 
74  m_windowed = new double[ m_dataLength ];
75 }
76 
78 {
79  delete [] m_magHistory ;
80  delete [] m_phaseHistory ;
81  delete [] m_phaseHistoryOld ;
82  delete [] m_magPeaks ;
83 
84  delete m_phaseVoc;
85 
86  delete [] m_magnitude;
87  delete [] m_thetaAngle;
88  delete [] m_windowed;
89  delete [] m_unwrapped;
90 
91  delete m_window;
92 }
93 
94 double DetectionFunction::processTimeDomain(const double *samples)
95 {
96  m_window->cut(samples, m_windowed);
97 
100 
101  if (m_whiten) whiten();
102 
103  return runDF();
104 }
105 
106 double DetectionFunction::processFrequencyDomain(const double *reals,
107  const double *imags)
108 {
109  m_phaseVoc->processFrequencyDomain(reals, imags,
111 
112  if (m_whiten) whiten();
113 
114  return runDF();
115 }
116 
118 {
119  for (int i = 0; i < m_halfLength; ++i) {
120  double m = m_magnitude[i];
121  if (m < m_magPeaks[i]) {
122  m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
123  }
124  if (m < m_whitenFloor) m = m_whitenFloor;
125  m_magPeaks[i] = m;
126  m_magnitude[i] /= m;
127  }
128 }
129 
131 {
132  double retVal = 0;
133 
134  switch( m_DFType )
135  {
136  case DF_HFC:
137  retVal = HFC( m_halfLength, m_magnitude);
138  break;
139 
140  case DF_SPECDIFF:
141  retVal = specDiff( m_halfLength, m_magnitude);
142  break;
143 
144  case DF_PHASEDEV:
145  // Using the instantaneous phases here actually provides the
146  // same results (for these calculations) as if we had used
147  // unwrapped phases, but without the possible accumulation of
148  // phase error over time
149  retVal = phaseDev( m_halfLength, m_thetaAngle);
150  break;
151 
152  case DF_COMPLEXSD:
154  break;
155 
156  case DF_BROADBAND:
157  retVal = broadband( m_halfLength, m_magnitude);
158  break;
159  }
160 
161  return retVal;
162 }
163 
164 double DetectionFunction::HFC(int length, double *src)
165 {
166  double val = 0;
167  for (int i = 0; i < length; i++) {
168  val += src[ i ] * ( i + 1);
169  }
170  return val;
171 }
172 
173 double DetectionFunction::specDiff(int length, double *src)
174 {
175  double val = 0.0;
176  double temp = 0.0;
177  double diff = 0.0;
178 
179  for (int i = 0; i < length; i++) {
180 
181  temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
182 
183  diff= sqrt(temp);
184 
185  // (See note in phaseDev below.)
186 
187  val += diff;
188 
189  m_magHistory[ i ] = src[ i ];
190  }
191 
192  return val;
193 }
194 
195 
196 double DetectionFunction::phaseDev(int length, double *srcPhase)
197 {
198  double tmpPhase = 0;
199  double tmpVal = 0;
200  double val = 0;
201 
202  double dev = 0;
203 
204  for (int i = 0; i < length; i++) {
205  tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
206  dev = MathUtilities::princarg( tmpPhase );
207 
208  // A previous version of this code only counted the value here
209  // if the magnitude exceeded 0.1. My impression is that
210  // doesn't greatly improve the results for "loud" music (so
211  // long as the peak picker is reasonably sophisticated), but
212  // does significantly damage its ability to work with quieter
213  // music, so I'm removing it and counting the result always.
214  // Same goes for the spectral difference measure above.
215 
216  tmpVal = fabs(dev);
217  val += tmpVal ;
218 
219  m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
220  m_phaseHistory[ i ] = srcPhase[ i ];
221  }
222 
223  return val;
224 }
225 
226 
227 double DetectionFunction::complexSD(int length, double *srcMagnitude, double *srcPhase)
228 {
229  double val = 0;
230  double tmpPhase = 0;
231  double tmpReal = 0;
232  double tmpImag = 0;
233 
234  double dev = 0;
235  ComplexData meas = ComplexData( 0, 0 );
236  ComplexData j = ComplexData( 0, 1 );
237 
238  for (int i = 0; i < length; i++) {
239 
240  tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
241  dev= MathUtilities::princarg( tmpPhase );
242 
243  meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
244 
245  tmpReal = real( meas );
246  tmpImag = imag( meas );
247 
248  val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
249 
250  m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
251  m_phaseHistory[ i ] = srcPhase[ i ];
252  m_magHistory[ i ] = srcMagnitude[ i ];
253  }
254 
255  return val;
256 }
257 
258 double DetectionFunction::broadband(int length, double *src)
259 {
260  double val = 0;
261  for (int i = 0; i < length; ++i) {
262  double sqrmag = src[i] * src[i];
263  if (m_magHistory[i] > 0.0) {
264  double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
265  if (diff > m_dbRise) val = val + 1;
266  }
267  m_magHistory[i] = sqrmag;
268  }
269  return val;
270 }
271 
273 {
274  return m_magnitude;
275 }
276 
double processFrequencyDomain(const double *reals, const double *imags)
Process a single frequency-domain frame, provided as frameLength/2+1 real and imaginary component val...
double phaseDev(int length, double *srcPhase)
double broadband(int length, double *srcMagnitude)
double whiteningFloor
Window< double > * m_window
double HFC(int length, double *src)
double processTimeDomain(const double *samples)
Process a single time-domain frame of audio, provided as frameLength samples.
bool adaptiveWhitening
void processTimeDomain(const double *src, double *mag, double *phase, double *unwrapped)
Given one frame of time-domain samples, FFT and return the magnitudes, instantaneous phases...
void initialise(DFConfig Config)
#define DF_HFC
PhaseVocoder * m_phaseVoc
DetectionFunction(DFConfig config)
static double princarg(double ang)
The principle argument function.
double complexSD(int length, double *srcMagnitude, double *srcPhase)
double whiteningRelaxCoeff
#define DF_PHASEDEV
std::complex< double > ComplexData
Definition: MathAliases.h:37
void cut(T *src) const
Definition: Window.h:61
#define DF_COMPLEXSD
#define DF_BROADBAND
double specDiff(int length, double *src)
void processFrequencyDomain(const double *reals, const double *imags, double *mag, double *phase, double *unwrapped)
Given one frame of frequency-domain samples, return the magnitudes, instantaneous phases...
double * getSpectrumMagnitude()
#define DF_SPECDIFF