adamstark@38
|
1 //=======================================================================
|
adamstark@38
|
2 /** @file OnsetDetectionFunction.cpp
|
adamstark@38
|
3 * @brief A class for calculating onset detection functions
|
adamstark@38
|
4 * @author Adam Stark
|
adamstark@38
|
5 * @copyright Copyright (C) 2008-2014 Queen Mary University of London
|
adamstark@38
|
6 *
|
adamstark@38
|
7 * This program is free software: you can redistribute it and/or modify
|
adamstark@38
|
8 * it under the terms of the GNU General Public License as published by
|
adamstark@38
|
9 * the Free Software Foundation, either version 3 of the License, or
|
adamstark@38
|
10 * (at your option) any later version.
|
adamstark@38
|
11 *
|
adamstark@38
|
12 * This program is distributed in the hope that it will be useful,
|
adamstark@38
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
adamstark@38
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
adamstark@38
|
15 * GNU General Public License for more details.
|
adamstark@38
|
16 *
|
adamstark@38
|
17 * You should have received a copy of the GNU General Public License
|
adamstark@38
|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
adamstark@38
|
19 */
|
adamstark@38
|
20 //=======================================================================
|
adamstark@38
|
21
|
adamstark@38
|
22 #include <math.h>
|
adamstark@38
|
23 #include "OnsetDetectionFunction.h"
|
adamstark@38
|
24
|
adamstark@52
|
25 //=======================================================================
|
adamstark@92
|
26 OnsetDetectionFunction::OnsetDetectionFunction (int hopSize_,int frameSize_)
|
adamstark@92
|
27 : onsetDetectionFunctionType (ComplexSpectralDifferenceHWR), windowType (HanningWindow)
|
adamstark@66
|
28 {
|
adamstark@66
|
29 // indicate that we have not initialised yet
|
adamstark@66
|
30 initialised = false;
|
adamstark@66
|
31
|
adamstark@66
|
32 // set pi
|
adamstark@66
|
33 pi = 3.14159265358979;
|
adamstark@66
|
34
|
adamstark@66
|
35 // initialise with arguments to constructor
|
adamstark@92
|
36 initialise (hopSize_, frameSize_, ComplexSpectralDifferenceHWR, HanningWindow);
|
adamstark@66
|
37 }
|
adamstark@66
|
38
|
adamstark@66
|
39 //=======================================================================
|
adamstark@92
|
40 OnsetDetectionFunction::OnsetDetectionFunction(int hopSize_,int frameSize_,int onsetDetectionFunctionType_,int windowType_)
|
adamstark@92
|
41 : onsetDetectionFunctionType (ComplexSpectralDifferenceHWR), windowType (HanningWindow)
|
adamstark@38
|
42 {
|
adamstark@38
|
43 // indicate that we have not initialised yet
|
adamstark@64
|
44 initialised = false;
|
adamstark@38
|
45
|
adamstark@38
|
46 // set pi
|
adamstark@38
|
47 pi = 3.14159265358979;
|
adamstark@38
|
48
|
adamstark@38
|
49 // initialise with arguments to constructor
|
adamstark@92
|
50 initialise (hopSize_, frameSize_, onsetDetectionFunctionType_, windowType_);
|
adamstark@38
|
51 }
|
adamstark@38
|
52
|
adamstark@38
|
53
|
adamstark@52
|
54 //=======================================================================
|
adamstark@59
|
55 OnsetDetectionFunction::~OnsetDetectionFunction()
|
adamstark@38
|
56 {
|
adamstark@64
|
57 if (initialised)
|
adamstark@64
|
58 {
|
adamstark@93
|
59 freeFFT();
|
adamstark@64
|
60 }
|
adamstark@38
|
61 }
|
adamstark@38
|
62
|
adamstark@52
|
63 //=======================================================================
|
adamstark@92
|
64 void OnsetDetectionFunction::initialise (int hopSize_, int frameSize_)
|
adamstark@66
|
65 {
|
adamstark@66
|
66 // use the already initialised onset detection function and window type and
|
adamstark@66
|
67 // pass the new frame and hop size to the main initialisation function
|
adamstark@92
|
68 initialise (hopSize_, frameSize_, onsetDetectionFunctionType, windowType);
|
adamstark@66
|
69 }
|
adamstark@66
|
70
|
adamstark@66
|
71 //=======================================================================
|
adamstark@66
|
72 void OnsetDetectionFunction::initialise(int hopSize_,int frameSize_,int onsetDetectionFunctionType_,int windowType_)
|
adamstark@38
|
73 {
|
adamstark@59
|
74 hopSize = hopSize_; // set hopsize
|
adamstark@59
|
75 frameSize = frameSize_; // set framesize
|
adamstark@38
|
76
|
adamstark@59
|
77 onsetDetectionFunctionType = onsetDetectionFunctionType_; // set detection function type
|
adamstark@66
|
78 windowType = windowType_; // set window type
|
adamstark@38
|
79
|
adamstark@38
|
80 // initialise buffers
|
adamstark@92
|
81 frame.resize (frameSize);
|
adamstark@92
|
82 window.resize (frameSize);
|
adamstark@92
|
83 magSpec.resize (frameSize);
|
adamstark@92
|
84 prevMagSpec.resize (frameSize);
|
adamstark@92
|
85 phase.resize (frameSize);
|
adamstark@92
|
86 prevPhase.resize (frameSize);
|
adamstark@92
|
87 prevPhase2.resize (frameSize);
|
adamstark@38
|
88
|
adamstark@38
|
89
|
adamstark@38
|
90 // set the window to the specified type
|
adamstark@92
|
91 switch (windowType)
|
adamstark@92
|
92 {
|
adamstark@57
|
93 case RectangularWindow:
|
adamstark@59
|
94 calculateRectangularWindow(); // Rectangular window
|
adamstark@38
|
95 break;
|
adamstark@57
|
96 case HanningWindow:
|
adamstark@59
|
97 calculateHanningWindow(); // Hanning Window
|
adamstark@38
|
98 break;
|
adamstark@57
|
99 case HammingWindow:
|
adamstark@59
|
100 calclulateHammingWindow(); // Hamming Window
|
adamstark@38
|
101 break;
|
adamstark@57
|
102 case BlackmanWindow:
|
adamstark@59
|
103 calculateBlackmanWindow(); // Blackman Window
|
adamstark@38
|
104 break;
|
adamstark@57
|
105 case TukeyWindow:
|
adamstark@59
|
106 calculateTukeyWindow(); // Tukey Window
|
adamstark@38
|
107 break;
|
adamstark@38
|
108 default:
|
adamstark@59
|
109 calculateHanningWindow(); // DEFAULT: Hanning Window
|
adamstark@38
|
110 }
|
adamstark@38
|
111
|
adamstark@38
|
112 // initialise previous magnitude spectrum to zero
|
adamstark@92
|
113 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
114 {
|
adamstark@59
|
115 prevMagSpec[i] = 0.0;
|
adamstark@59
|
116 prevPhase[i] = 0.0;
|
adamstark@59
|
117 prevPhase2[i] = 0.0;
|
adamstark@38
|
118 frame[i] = 0.0;
|
adamstark@38
|
119 }
|
adamstark@38
|
120
|
adamstark@59
|
121 prevEnergySum = 0.0; // initialise previous energy sum value to zero
|
adamstark@38
|
122
|
adamstark@93
|
123 initialiseFFT();
|
adamstark@93
|
124 }
|
adamstark@93
|
125
|
adamstark@93
|
126 //=======================================================================
|
adamstark@93
|
127 void OnsetDetectionFunction::initialiseFFT()
|
adamstark@93
|
128 {
|
adamstark@93
|
129 if (initialised) // if we have already initialised FFT plan
|
adamstark@93
|
130 {
|
adamstark@93
|
131 freeFFT();
|
adamstark@93
|
132 }
|
adamstark@93
|
133
|
adamstark@93
|
134 #ifdef USE_FFTW
|
adamstark@93
|
135 complexIn = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * frameSize); // complex array to hold fft data
|
adamstark@93
|
136 complexOut = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * frameSize); // complex array to hold fft data
|
adamstark@93
|
137 p = fftw_plan_dft_1d (frameSize, complexIn, complexOut, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation
|
adamstark@93
|
138 #endif
|
adamstark@93
|
139
|
adamstark@93
|
140 #ifdef USE_KISS_FFT
|
adamstark@93
|
141 complexOut.resize (frameSize);
|
adamstark@93
|
142
|
adamstark@93
|
143 for (int i = 0; i < frameSize;i++)
|
adamstark@93
|
144 {
|
adamstark@93
|
145 complexOut[i].resize(2);
|
adamstark@93
|
146 }
|
adamstark@93
|
147
|
adamstark@93
|
148 fftIn = new kiss_fft_cpx[frameSize];
|
adamstark@93
|
149 fftOut = new kiss_fft_cpx[frameSize];
|
adamstark@93
|
150 cfg = kiss_fft_alloc (frameSize, 0, 0, 0);
|
adamstark@93
|
151 #endif
|
adamstark@93
|
152
|
adamstark@93
|
153 initialised = true;
|
adamstark@93
|
154 }
|
adamstark@93
|
155
|
adamstark@93
|
156 //=======================================================================
|
adamstark@93
|
157 void OnsetDetectionFunction::freeFFT()
|
adamstark@93
|
158 {
|
adamstark@93
|
159 #ifdef USE_FFTW
|
adamstark@93
|
160 fftw_destroy_plan (p);
|
adamstark@93
|
161 fftw_free (complexIn);
|
adamstark@93
|
162 fftw_free (complexOut);
|
adamstark@93
|
163 #endif
|
adamstark@93
|
164
|
adamstark@93
|
165 #ifdef USE_KISS_FFT
|
adamstark@93
|
166 free (cfg);
|
adamstark@93
|
167 delete [] fftIn;
|
adamstark@93
|
168 delete [] fftOut;
|
adamstark@93
|
169 #endif
|
adamstark@38
|
170 }
|
adamstark@38
|
171
|
adamstark@52
|
172 //=======================================================================
|
adamstark@92
|
173 void OnsetDetectionFunction::setOnsetDetectionFunctionType (int onsetDetectionFunctionType_)
|
adamstark@38
|
174 {
|
adamstark@59
|
175 onsetDetectionFunctionType = onsetDetectionFunctionType_; // set detection function type
|
adamstark@38
|
176 }
|
adamstark@38
|
177
|
adamstark@52
|
178 //=======================================================================
|
adamstark@92
|
179 double OnsetDetectionFunction::calculateOnsetDetectionFunctionSample (double* buffer)
|
adamstark@38
|
180 {
|
adamstark@59
|
181 double odfSample;
|
adamstark@38
|
182
|
adamstark@38
|
183 // shift audio samples back in frame by hop size
|
adamstark@59
|
184 for (int i = 0; i < (frameSize-hopSize);i++)
|
adamstark@38
|
185 {
|
adamstark@59
|
186 frame[i] = frame[i+hopSize];
|
adamstark@38
|
187 }
|
adamstark@38
|
188
|
adamstark@38
|
189 // add new samples to frame from input buffer
|
adamstark@38
|
190 int j = 0;
|
adamstark@59
|
191 for (int i = (frameSize-hopSize);i < frameSize;i++)
|
adamstark@38
|
192 {
|
adamstark@59
|
193 frame[i] = buffer[j];
|
adamstark@38
|
194 j++;
|
adamstark@38
|
195 }
|
adamstark@38
|
196
|
adamstark@92
|
197 switch (onsetDetectionFunctionType)
|
adamstark@92
|
198 {
|
adamstark@57
|
199 case EnergyEnvelope:
|
adamstark@57
|
200 {
|
adamstark@57
|
201 // calculate energy envelope detection function sample
|
adamstark@59
|
202 odfSample = energyEnvelope();
|
adamstark@38
|
203 break;
|
adamstark@57
|
204 }
|
adamstark@57
|
205 case EnergyDifference:
|
adamstark@57
|
206 {
|
adamstark@57
|
207 // calculate half-wave rectified energy difference detection function sample
|
adamstark@59
|
208 odfSample = energyDifference();
|
adamstark@38
|
209 break;
|
adamstark@57
|
210 }
|
adamstark@57
|
211 case SpectralDifference:
|
adamstark@57
|
212 {
|
adamstark@57
|
213 // calculate spectral difference detection function sample
|
adamstark@59
|
214 odfSample = spectralDifference();
|
adamstark@38
|
215 break;
|
adamstark@57
|
216 }
|
adamstark@57
|
217 case SpectralDifferenceHWR:
|
adamstark@57
|
218 {
|
adamstark@57
|
219 // calculate spectral difference detection function sample (half wave rectified)
|
adamstark@59
|
220 odfSample = spectralDifferenceHWR();
|
adamstark@38
|
221 break;
|
adamstark@57
|
222 }
|
adamstark@57
|
223 case PhaseDeviation:
|
adamstark@57
|
224 {
|
adamstark@57
|
225 // calculate phase deviation detection function sample (half wave rectified)
|
adamstark@59
|
226 odfSample = phaseDeviation();
|
adamstark@38
|
227 break;
|
adamstark@57
|
228 }
|
adamstark@57
|
229 case ComplexSpectralDifference:
|
adamstark@57
|
230 {
|
adamstark@57
|
231 // calcualte complex spectral difference detection function sample
|
adamstark@59
|
232 odfSample = complexSpectralDifference();
|
adamstark@38
|
233 break;
|
adamstark@57
|
234 }
|
adamstark@57
|
235 case ComplexSpectralDifferenceHWR:
|
adamstark@57
|
236 {
|
adamstark@57
|
237 // calcualte complex spectral difference detection function sample (half-wave rectified)
|
adamstark@59
|
238 odfSample = complexSpectralDifferenceHWR();
|
adamstark@38
|
239 break;
|
adamstark@57
|
240 }
|
adamstark@57
|
241 case HighFrequencyContent:
|
adamstark@57
|
242 {
|
adamstark@57
|
243 // calculate high frequency content detection function sample
|
adamstark@59
|
244 odfSample = highFrequencyContent();
|
adamstark@38
|
245 break;
|
adamstark@57
|
246 }
|
adamstark@57
|
247 case HighFrequencySpectralDifference:
|
adamstark@57
|
248 {
|
adamstark@57
|
249 // calculate high frequency spectral difference detection function sample
|
adamstark@59
|
250 odfSample = highFrequencySpectralDifference();
|
adamstark@38
|
251 break;
|
adamstark@57
|
252 }
|
adamstark@57
|
253 case HighFrequencySpectralDifferenceHWR:
|
adamstark@57
|
254 {
|
adamstark@57
|
255 // calculate high frequency spectral difference detection function (half-wave rectified)
|
adamstark@59
|
256 odfSample = highFrequencySpectralDifferenceHWR();
|
adamstark@57
|
257 break;
|
adamstark@57
|
258 }
|
adamstark@38
|
259 default:
|
adamstark@57
|
260 {
|
adamstark@59
|
261 odfSample = 1.0;
|
adamstark@57
|
262 }
|
adamstark@38
|
263 }
|
adamstark@38
|
264
|
adamstark@59
|
265 return odfSample;
|
adamstark@38
|
266 }
|
adamstark@38
|
267
|
adamstark@38
|
268
|
adamstark@52
|
269 //=======================================================================
|
adamstark@92
|
270 void OnsetDetectionFunction::performFFT()
|
adamstark@38
|
271 {
|
adamstark@93
|
272 int fsize2 = (frameSize/2);
|
adamstark@93
|
273
|
adamstark@93
|
274 #ifdef USE_FFTW
|
adamstark@38
|
275 // window frame and copy to complex array, swapping the first and second half of the signal
|
adamstark@38
|
276 for (int i = 0;i < fsize2;i++)
|
adamstark@38
|
277 {
|
adamstark@93
|
278 complexIn[i][0] = frame[i + fsize2] * window[i + fsize2];
|
adamstark@59
|
279 complexIn[i][1] = 0.0;
|
adamstark@59
|
280 complexIn[i+fsize2][0] = frame[i] * window[i];
|
adamstark@59
|
281 complexIn[i+fsize2][1] = 0.0;
|
adamstark@38
|
282 }
|
adamstark@38
|
283
|
adamstark@38
|
284 // perform the fft
|
adamstark@92
|
285 fftw_execute (p);
|
adamstark@93
|
286 #endif
|
adamstark@93
|
287
|
adamstark@93
|
288 #ifdef USE_KISS_FFT
|
adamstark@93
|
289 for (int i = 0; i < fsize2; i++)
|
adamstark@93
|
290 {
|
adamstark@93
|
291 fftIn[i].r = frame[i + fsize2] * window[i + fsize2];
|
adamstark@93
|
292 fftIn[i].i = 0.0;
|
adamstark@93
|
293 fftIn[i + fsize2].r = frame[i] * window[i];
|
adamstark@93
|
294 fftIn[i + fsize2].i = 0.0;
|
adamstark@93
|
295 }
|
adamstark@93
|
296
|
adamstark@93
|
297 // execute kiss fft
|
adamstark@93
|
298 kiss_fft (cfg, fftIn, fftOut);
|
adamstark@93
|
299
|
adamstark@93
|
300 // store real and imaginary parts of FFT
|
adamstark@93
|
301 for (int i = 0; i < frameSize; i++)
|
adamstark@93
|
302 {
|
adamstark@93
|
303 complexOut[i][0] = fftOut[i].r;
|
adamstark@93
|
304 complexOut[i][1] = fftOut[i].i;
|
adamstark@93
|
305 }
|
adamstark@93
|
306 #endif
|
adamstark@38
|
307 }
|
adamstark@38
|
308
|
adamstark@38
|
309 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
310 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
311 ////////////////////////////// Methods for Detection Functions /////////////////////////////////
|
adamstark@38
|
312
|
adamstark@52
|
313 //=======================================================================
|
adamstark@92
|
314 double OnsetDetectionFunction::energyEnvelope()
|
adamstark@38
|
315 {
|
adamstark@38
|
316 double sum;
|
adamstark@38
|
317
|
adamstark@38
|
318 sum = 0; // initialise sum
|
adamstark@38
|
319
|
adamstark@38
|
320 // sum the squares of the samples
|
adamstark@59
|
321 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
322 {
|
adamstark@92
|
323 sum = sum + (frame[i] * frame[i]);
|
adamstark@38
|
324 }
|
adamstark@38
|
325
|
adamstark@38
|
326 return sum; // return sum
|
adamstark@38
|
327 }
|
adamstark@38
|
328
|
adamstark@52
|
329 //=======================================================================
|
adamstark@92
|
330 double OnsetDetectionFunction::energyDifference()
|
adamstark@38
|
331 {
|
adamstark@38
|
332 double sum;
|
adamstark@38
|
333 double sample;
|
adamstark@38
|
334
|
adamstark@38
|
335 sum = 0; // initialise sum
|
adamstark@38
|
336
|
adamstark@38
|
337 // sum the squares of the samples
|
adamstark@92
|
338 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
339 {
|
adamstark@92
|
340 sum = sum + (frame[i] * frame[i]);
|
adamstark@38
|
341 }
|
adamstark@38
|
342
|
adamstark@59
|
343 sample = sum - prevEnergySum; // sample is first order difference in energy
|
adamstark@38
|
344
|
adamstark@59
|
345 prevEnergySum = sum; // store energy value for next calculation
|
adamstark@38
|
346
|
adamstark@38
|
347 if (sample > 0)
|
adamstark@38
|
348 {
|
adamstark@38
|
349 return sample; // return difference
|
adamstark@38
|
350 }
|
adamstark@38
|
351 else
|
adamstark@38
|
352 {
|
adamstark@38
|
353 return 0;
|
adamstark@38
|
354 }
|
adamstark@38
|
355 }
|
adamstark@38
|
356
|
adamstark@52
|
357 //=======================================================================
|
adamstark@92
|
358 double OnsetDetectionFunction::spectralDifference()
|
adamstark@38
|
359 {
|
adamstark@38
|
360 double diff;
|
adamstark@38
|
361 double sum;
|
adamstark@38
|
362
|
adamstark@38
|
363 // perform the FFT
|
adamstark@59
|
364 performFFT();
|
adamstark@38
|
365
|
adamstark@38
|
366 // compute first (N/2)+1 mag values
|
adamstark@59
|
367 for (int i = 0;i < (frameSize/2)+1;i++)
|
adamstark@38
|
368 {
|
adamstark@93
|
369 magSpec[i] = sqrt (pow (complexOut[i][0], 2) + pow (complexOut[i][1], 2));
|
adamstark@38
|
370 }
|
adamstark@38
|
371 // mag spec symmetric above (N/2)+1 so copy previous values
|
adamstark@92
|
372 for (int i = (frameSize/2)+1; i < frameSize; i++)
|
adamstark@38
|
373 {
|
adamstark@59
|
374 magSpec[i] = magSpec[frameSize-i];
|
adamstark@38
|
375 }
|
adamstark@38
|
376
|
adamstark@38
|
377 sum = 0; // initialise sum to zero
|
adamstark@38
|
378
|
adamstark@92
|
379 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
380 {
|
adamstark@38
|
381 // calculate difference
|
adamstark@59
|
382 diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
383
|
adamstark@38
|
384 // ensure all difference values are positive
|
adamstark@38
|
385 if (diff < 0)
|
adamstark@38
|
386 {
|
adamstark@38
|
387 diff = diff*-1;
|
adamstark@38
|
388 }
|
adamstark@38
|
389
|
adamstark@38
|
390 // add difference to sum
|
adamstark@92
|
391 sum = sum + diff;
|
adamstark@38
|
392
|
adamstark@38
|
393 // store magnitude spectrum bin for next detection function sample calculation
|
adamstark@59
|
394 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
395 }
|
adamstark@38
|
396
|
adamstark@38
|
397 return sum;
|
adamstark@38
|
398 }
|
adamstark@38
|
399
|
adamstark@52
|
400 //=======================================================================
|
adamstark@92
|
401 double OnsetDetectionFunction::spectralDifferenceHWR()
|
adamstark@38
|
402 {
|
adamstark@38
|
403 double diff;
|
adamstark@38
|
404 double sum;
|
adamstark@38
|
405
|
adamstark@38
|
406 // perform the FFT
|
adamstark@59
|
407 performFFT();
|
adamstark@38
|
408
|
adamstark@38
|
409 // compute first (N/2)+1 mag values
|
adamstark@92
|
410 for (int i = 0;i < (frameSize/2) + 1; i++)
|
adamstark@38
|
411 {
|
adamstark@92
|
412 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
413 }
|
adamstark@38
|
414 // mag spec symmetric above (N/2)+1 so copy previous values
|
adamstark@59
|
415 for (int i = (frameSize/2)+1;i < frameSize;i++)
|
adamstark@38
|
416 {
|
adamstark@59
|
417 magSpec[i] = magSpec[frameSize-i];
|
adamstark@38
|
418 }
|
adamstark@38
|
419
|
adamstark@38
|
420 sum = 0; // initialise sum to zero
|
adamstark@38
|
421
|
adamstark@59
|
422 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
423 {
|
adamstark@38
|
424 // calculate difference
|
adamstark@59
|
425 diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
426
|
adamstark@38
|
427 // only add up positive differences
|
adamstark@38
|
428 if (diff > 0)
|
adamstark@38
|
429 {
|
adamstark@38
|
430 // add difference to sum
|
adamstark@38
|
431 sum = sum+diff;
|
adamstark@38
|
432 }
|
adamstark@38
|
433
|
adamstark@38
|
434 // store magnitude spectrum bin for next detection function sample calculation
|
adamstark@59
|
435 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
436 }
|
adamstark@38
|
437
|
adamstark@38
|
438 return sum;
|
adamstark@38
|
439 }
|
adamstark@38
|
440
|
adamstark@38
|
441
|
adamstark@52
|
442 //=======================================================================
|
adamstark@92
|
443 double OnsetDetectionFunction::phaseDeviation()
|
adamstark@38
|
444 {
|
adamstark@38
|
445 double dev,pdev;
|
adamstark@38
|
446 double sum;
|
adamstark@38
|
447
|
adamstark@38
|
448 // perform the FFT
|
adamstark@59
|
449 performFFT();
|
adamstark@38
|
450
|
adamstark@38
|
451 sum = 0; // initialise sum to zero
|
adamstark@38
|
452
|
adamstark@38
|
453 // compute phase values from fft output and sum deviations
|
adamstark@59
|
454 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
455 {
|
adamstark@38
|
456 // calculate phase value
|
adamstark@93
|
457 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
458
|
adamstark@38
|
459 // calculate magnitude value
|
adamstark@92
|
460 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
461
|
adamstark@38
|
462
|
adamstark@38
|
463 // if bin is not just a low energy bin then examine phase deviation
|
adamstark@59
|
464 if (magSpec[i] > 0.1)
|
adamstark@38
|
465 {
|
adamstark@59
|
466 dev = phase[i] - (2*prevPhase[i]) + prevPhase2[i]; // phase deviation
|
adamstark@92
|
467 pdev = princarg (dev); // wrap into [-pi,pi] range
|
adamstark@38
|
468
|
adamstark@38
|
469 // make all values positive
|
adamstark@38
|
470 if (pdev < 0)
|
adamstark@38
|
471 {
|
adamstark@38
|
472 pdev = pdev*-1;
|
adamstark@38
|
473 }
|
adamstark@38
|
474
|
adamstark@38
|
475 // add to sum
|
adamstark@38
|
476 sum = sum + pdev;
|
adamstark@38
|
477 }
|
adamstark@38
|
478
|
adamstark@38
|
479 // store values for next calculation
|
adamstark@59
|
480 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
481 prevPhase[i] = phase[i];
|
adamstark@38
|
482 }
|
adamstark@38
|
483
|
adamstark@38
|
484 return sum;
|
adamstark@38
|
485 }
|
adamstark@38
|
486
|
adamstark@52
|
487 //=======================================================================
|
adamstark@92
|
488 double OnsetDetectionFunction::complexSpectralDifference()
|
adamstark@38
|
489 {
|
adamstark@86
|
490 double phaseDeviation;
|
adamstark@38
|
491 double sum;
|
adamstark@86
|
492 double csd;
|
adamstark@38
|
493
|
adamstark@38
|
494 // perform the FFT
|
adamstark@59
|
495 performFFT();
|
adamstark@38
|
496
|
adamstark@38
|
497 sum = 0; // initialise sum to zero
|
adamstark@38
|
498
|
adamstark@38
|
499 // compute phase values from fft output and sum deviations
|
adamstark@59
|
500 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
501 {
|
adamstark@38
|
502 // calculate phase value
|
adamstark@93
|
503 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
504
|
adamstark@38
|
505 // calculate magnitude value
|
adamstark@92
|
506 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2));
|
adamstark@38
|
507
|
adamstark@86
|
508 // phase deviation
|
adamstark@92
|
509 phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i];
|
adamstark@38
|
510
|
adamstark@86
|
511 // calculate complex spectral difference for the current spectral bin
|
adamstark@92
|
512 csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation));
|
adamstark@38
|
513
|
adamstark@38
|
514 // add to sum
|
adamstark@86
|
515 sum = sum + csd;
|
adamstark@38
|
516
|
adamstark@38
|
517 // store values for next calculation
|
adamstark@59
|
518 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
519 prevPhase[i] = phase[i];
|
adamstark@59
|
520 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
521 }
|
adamstark@38
|
522
|
adamstark@38
|
523 return sum;
|
adamstark@38
|
524 }
|
adamstark@38
|
525
|
adamstark@52
|
526 //=======================================================================
|
adamstark@92
|
527 double OnsetDetectionFunction::complexSpectralDifferenceHWR()
|
adamstark@38
|
528 {
|
adamstark@86
|
529 double phaseDeviation;
|
adamstark@38
|
530 double sum;
|
adamstark@86
|
531 double magnitudeDifference;
|
adamstark@86
|
532 double csd;
|
adamstark@38
|
533
|
adamstark@38
|
534 // perform the FFT
|
adamstark@59
|
535 performFFT();
|
adamstark@38
|
536
|
adamstark@38
|
537 sum = 0; // initialise sum to zero
|
adamstark@38
|
538
|
adamstark@38
|
539 // compute phase values from fft output and sum deviations
|
adamstark@59
|
540 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
541 {
|
adamstark@38
|
542 // calculate phase value
|
adamstark@93
|
543 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
544
|
adamstark@38
|
545 // calculate magnitude value
|
adamstark@92
|
546 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2));
|
adamstark@38
|
547
|
adamstark@86
|
548 // phase deviation
|
adamstark@92
|
549 phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i];
|
adamstark@86
|
550
|
adamstark@86
|
551 // calculate magnitude difference (real part of Euclidean distance between complex frames)
|
adamstark@86
|
552 magnitudeDifference = magSpec[i] - prevMagSpec[i];
|
adamstark@86
|
553
|
adamstark@86
|
554 // if we have a positive change in magnitude, then include in sum, otherwise ignore (half-wave rectification)
|
adamstark@86
|
555 if (magnitudeDifference > 0)
|
adamstark@86
|
556 {
|
adamstark@86
|
557 // calculate complex spectral difference for the current spectral bin
|
adamstark@92
|
558 csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation));
|
adamstark@86
|
559
|
adamstark@86
|
560 // add to sum
|
adamstark@86
|
561 sum = sum + csd;
|
adamstark@86
|
562 }
|
adamstark@86
|
563
|
adamstark@38
|
564 // store values for next calculation
|
adamstark@59
|
565 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
566 prevPhase[i] = phase[i];
|
adamstark@59
|
567 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
568 }
|
adamstark@38
|
569
|
adamstark@38
|
570 return sum;
|
adamstark@38
|
571 }
|
adamstark@38
|
572
|
adamstark@38
|
573
|
adamstark@52
|
574 //=======================================================================
|
adamstark@92
|
575 double OnsetDetectionFunction::highFrequencyContent()
|
adamstark@38
|
576 {
|
adamstark@38
|
577 double sum;
|
adamstark@38
|
578
|
adamstark@38
|
579 // perform the FFT
|
adamstark@59
|
580 performFFT();
|
adamstark@38
|
581
|
adamstark@38
|
582 sum = 0; // initialise sum to zero
|
adamstark@38
|
583
|
adamstark@38
|
584 // compute phase values from fft output and sum deviations
|
adamstark@92
|
585 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
586 {
|
adamstark@38
|
587 // calculate magnitude value
|
adamstark@92
|
588 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
589
|
adamstark@38
|
590
|
adamstark@92
|
591 sum = sum + (magSpec[i] * ((double) (i+1)));
|
adamstark@38
|
592
|
adamstark@38
|
593 // store values for next calculation
|
adamstark@59
|
594 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
595 }
|
adamstark@38
|
596
|
adamstark@38
|
597 return sum;
|
adamstark@38
|
598 }
|
adamstark@38
|
599
|
adamstark@52
|
600 //=======================================================================
|
adamstark@92
|
601 double OnsetDetectionFunction::highFrequencySpectralDifference()
|
adamstark@38
|
602 {
|
adamstark@38
|
603 double sum;
|
adamstark@38
|
604 double mag_diff;
|
adamstark@38
|
605
|
adamstark@38
|
606 // perform the FFT
|
adamstark@59
|
607 performFFT();
|
adamstark@38
|
608
|
adamstark@38
|
609 sum = 0; // initialise sum to zero
|
adamstark@38
|
610
|
adamstark@38
|
611 // compute phase values from fft output and sum deviations
|
adamstark@59
|
612 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
613 {
|
adamstark@38
|
614 // calculate magnitude value
|
adamstark@92
|
615 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
616
|
adamstark@38
|
617 // calculate difference
|
adamstark@59
|
618 mag_diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
619
|
adamstark@38
|
620 if (mag_diff < 0)
|
adamstark@38
|
621 {
|
adamstark@38
|
622 mag_diff = -mag_diff;
|
adamstark@38
|
623 }
|
adamstark@38
|
624
|
adamstark@92
|
625 sum = sum + (mag_diff * ((double) (i+1)));
|
adamstark@38
|
626
|
adamstark@38
|
627 // store values for next calculation
|
adamstark@59
|
628 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
629 }
|
adamstark@38
|
630
|
adamstark@38
|
631 return sum;
|
adamstark@38
|
632 }
|
adamstark@38
|
633
|
adamstark@52
|
634 //=======================================================================
|
adamstark@92
|
635 double OnsetDetectionFunction::highFrequencySpectralDifferenceHWR()
|
adamstark@38
|
636 {
|
adamstark@38
|
637 double sum;
|
adamstark@38
|
638 double mag_diff;
|
adamstark@38
|
639
|
adamstark@38
|
640 // perform the FFT
|
adamstark@59
|
641 performFFT();
|
adamstark@38
|
642
|
adamstark@38
|
643 sum = 0; // initialise sum to zero
|
adamstark@38
|
644
|
adamstark@38
|
645 // compute phase values from fft output and sum deviations
|
adamstark@59
|
646 for (int i = 0;i < frameSize;i++)
|
adamstark@38
|
647 {
|
adamstark@38
|
648 // calculate magnitude value
|
adamstark@92
|
649 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
650
|
adamstark@38
|
651 // calculate difference
|
adamstark@59
|
652 mag_diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
653
|
adamstark@38
|
654 if (mag_diff > 0)
|
adamstark@38
|
655 {
|
adamstark@92
|
656 sum = sum + (mag_diff * ((double) (i+1)));
|
adamstark@38
|
657 }
|
adamstark@38
|
658
|
adamstark@38
|
659 // store values for next calculation
|
adamstark@59
|
660 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
661 }
|
adamstark@38
|
662
|
adamstark@38
|
663 return sum;
|
adamstark@38
|
664 }
|
adamstark@38
|
665
|
adamstark@38
|
666
|
adamstark@38
|
667 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
668 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
669 ////////////////////////////// Methods to Calculate Windows ////////////////////////////////////
|
adamstark@38
|
670
|
adamstark@52
|
671 //=======================================================================
|
adamstark@92
|
672 void OnsetDetectionFunction::calculateHanningWindow()
|
adamstark@38
|
673 {
|
adamstark@38
|
674 double N; // variable to store framesize minus 1
|
adamstark@38
|
675
|
adamstark@59
|
676 N = (double) (frameSize-1); // framesize minus 1
|
adamstark@38
|
677
|
adamstark@38
|
678 // Hanning window calculation
|
adamstark@92
|
679 for (int n = 0; n < frameSize; n++)
|
adamstark@38
|
680 {
|
adamstark@92
|
681 window[n] = 0.5 * (1 - cos (2 * pi * (n / N)));
|
adamstark@38
|
682 }
|
adamstark@38
|
683 }
|
adamstark@38
|
684
|
adamstark@52
|
685 //=======================================================================
|
adamstark@92
|
686 void OnsetDetectionFunction::calclulateHammingWindow()
|
adamstark@38
|
687 {
|
adamstark@38
|
688 double N; // variable to store framesize minus 1
|
adamstark@38
|
689 double n_val; // double version of index 'n'
|
adamstark@38
|
690
|
adamstark@59
|
691 N = (double) (frameSize-1); // framesize minus 1
|
adamstark@38
|
692 n_val = 0;
|
adamstark@38
|
693
|
adamstark@38
|
694 // Hamming window calculation
|
adamstark@59
|
695 for (int n = 0;n < frameSize;n++)
|
adamstark@38
|
696 {
|
adamstark@92
|
697 window[n] = 0.54 - (0.46 * cos (2 * pi * (n_val/N)));
|
adamstark@38
|
698 n_val = n_val+1;
|
adamstark@38
|
699 }
|
adamstark@38
|
700 }
|
adamstark@38
|
701
|
adamstark@52
|
702 //=======================================================================
|
adamstark@92
|
703 void OnsetDetectionFunction::calculateBlackmanWindow()
|
adamstark@38
|
704 {
|
adamstark@38
|
705 double N; // variable to store framesize minus 1
|
adamstark@38
|
706 double n_val; // double version of index 'n'
|
adamstark@38
|
707
|
adamstark@59
|
708 N = (double) (frameSize-1); // framesize minus 1
|
adamstark@38
|
709 n_val = 0;
|
adamstark@38
|
710
|
adamstark@38
|
711 // Blackman window calculation
|
adamstark@59
|
712 for (int n = 0;n < frameSize;n++)
|
adamstark@38
|
713 {
|
adamstark@38
|
714 window[n] = 0.42 - (0.5*cos(2*pi*(n_val/N))) + (0.08*cos(4*pi*(n_val/N)));
|
adamstark@38
|
715 n_val = n_val+1;
|
adamstark@38
|
716 }
|
adamstark@38
|
717 }
|
adamstark@38
|
718
|
adamstark@52
|
719 //=======================================================================
|
adamstark@92
|
720 void OnsetDetectionFunction::calculateTukeyWindow()
|
adamstark@38
|
721 {
|
adamstark@38
|
722 double N; // variable to store framesize minus 1
|
adamstark@38
|
723 double n_val; // double version of index 'n'
|
adamstark@38
|
724 double alpha; // alpha [default value = 0.5];
|
adamstark@38
|
725
|
adamstark@38
|
726 alpha = 0.5;
|
adamstark@38
|
727
|
adamstark@59
|
728 N = (double) (frameSize-1); // framesize minus 1
|
adamstark@38
|
729
|
adamstark@38
|
730 // Tukey window calculation
|
adamstark@38
|
731
|
adamstark@59
|
732 n_val = (double) (-1*((frameSize/2)))+1;
|
adamstark@38
|
733
|
adamstark@59
|
734 for (int n = 0;n < frameSize;n++) // left taper
|
adamstark@38
|
735 {
|
adamstark@38
|
736 if ((n_val >= 0) && (n_val <= (alpha*(N/2))))
|
adamstark@38
|
737 {
|
adamstark@38
|
738 window[n] = 1.0;
|
adamstark@38
|
739 }
|
adamstark@38
|
740 else if ((n_val <= 0) && (n_val >= (-1*alpha*(N/2))))
|
adamstark@38
|
741 {
|
adamstark@38
|
742 window[n] = 1.0;
|
adamstark@38
|
743 }
|
adamstark@38
|
744 else
|
adamstark@38
|
745 {
|
adamstark@38
|
746 window[n] = 0.5*(1+cos(pi*(((2*n_val)/(alpha*N))-1)));
|
adamstark@38
|
747 }
|
adamstark@38
|
748
|
adamstark@38
|
749 n_val = n_val+1;
|
adamstark@38
|
750 }
|
adamstark@38
|
751
|
adamstark@38
|
752 }
|
adamstark@38
|
753
|
adamstark@52
|
754 //=======================================================================
|
adamstark@92
|
755 void OnsetDetectionFunction::calculateRectangularWindow()
|
adamstark@38
|
756 {
|
adamstark@38
|
757 // Rectangular window calculation
|
adamstark@59
|
758 for (int n = 0;n < frameSize;n++)
|
adamstark@38
|
759 {
|
adamstark@38
|
760 window[n] = 1.0;
|
adamstark@38
|
761 }
|
adamstark@38
|
762 }
|
adamstark@38
|
763
|
adamstark@38
|
764 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
765 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
766 ///////////////////////////////// Other Handy Methods //////////////////////////////////////////
|
adamstark@38
|
767
|
adamstark@52
|
768 //=======================================================================
|
adamstark@92
|
769 double OnsetDetectionFunction::princarg(double phaseVal)
|
adamstark@38
|
770 {
|
adamstark@38
|
771 // if phase value is less than or equal to -pi then add 2*pi
|
adamstark@59
|
772 while (phaseVal <= (-pi))
|
adamstark@38
|
773 {
|
adamstark@92
|
774 phaseVal = phaseVal + (2 * pi);
|
adamstark@38
|
775 }
|
adamstark@38
|
776
|
adamstark@38
|
777 // if phase value is larger than pi, then subtract 2*pi
|
adamstark@59
|
778 while (phaseVal > pi)
|
adamstark@38
|
779 {
|
adamstark@92
|
780 phaseVal = phaseVal - (2 * pi);
|
adamstark@38
|
781 }
|
adamstark@38
|
782
|
adamstark@59
|
783 return phaseVal;
|
adamstark@38
|
784 }
|