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@115
|
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@115
|
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@115
|
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@115
|
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@100
|
184 std::rotate (frame.begin(), frame.begin() + hopSize, frame.end());
|
adamstark@38
|
185
|
adamstark@38
|
186 // add new samples to frame from input buffer
|
adamstark@38
|
187 int j = 0;
|
adamstark@100
|
188 for (int i = (frameSize - hopSize); i < frameSize; i++)
|
adamstark@38
|
189 {
|
adamstark@59
|
190 frame[i] = buffer[j];
|
adamstark@38
|
191 j++;
|
adamstark@38
|
192 }
|
adamstark@38
|
193
|
adamstark@92
|
194 switch (onsetDetectionFunctionType)
|
adamstark@92
|
195 {
|
adamstark@57
|
196 case EnergyEnvelope:
|
adamstark@57
|
197 {
|
adamstark@57
|
198 // calculate energy envelope detection function sample
|
adamstark@59
|
199 odfSample = energyEnvelope();
|
adamstark@38
|
200 break;
|
adamstark@57
|
201 }
|
adamstark@57
|
202 case EnergyDifference:
|
adamstark@57
|
203 {
|
adamstark@57
|
204 // calculate half-wave rectified energy difference detection function sample
|
adamstark@59
|
205 odfSample = energyDifference();
|
adamstark@38
|
206 break;
|
adamstark@57
|
207 }
|
adamstark@57
|
208 case SpectralDifference:
|
adamstark@57
|
209 {
|
adamstark@57
|
210 // calculate spectral difference detection function sample
|
adamstark@59
|
211 odfSample = spectralDifference();
|
adamstark@38
|
212 break;
|
adamstark@57
|
213 }
|
adamstark@57
|
214 case SpectralDifferenceHWR:
|
adamstark@57
|
215 {
|
adamstark@57
|
216 // calculate spectral difference detection function sample (half wave rectified)
|
adamstark@59
|
217 odfSample = spectralDifferenceHWR();
|
adamstark@38
|
218 break;
|
adamstark@57
|
219 }
|
adamstark@57
|
220 case PhaseDeviation:
|
adamstark@57
|
221 {
|
adamstark@57
|
222 // calculate phase deviation detection function sample (half wave rectified)
|
adamstark@59
|
223 odfSample = phaseDeviation();
|
adamstark@38
|
224 break;
|
adamstark@57
|
225 }
|
adamstark@57
|
226 case ComplexSpectralDifference:
|
adamstark@57
|
227 {
|
adamstark@57
|
228 // calcualte complex spectral difference detection function sample
|
adamstark@59
|
229 odfSample = complexSpectralDifference();
|
adamstark@38
|
230 break;
|
adamstark@57
|
231 }
|
adamstark@57
|
232 case ComplexSpectralDifferenceHWR:
|
adamstark@57
|
233 {
|
adamstark@57
|
234 // calcualte complex spectral difference detection function sample (half-wave rectified)
|
adamstark@59
|
235 odfSample = complexSpectralDifferenceHWR();
|
adamstark@38
|
236 break;
|
adamstark@57
|
237 }
|
adamstark@57
|
238 case HighFrequencyContent:
|
adamstark@57
|
239 {
|
adamstark@57
|
240 // calculate high frequency content detection function sample
|
adamstark@59
|
241 odfSample = highFrequencyContent();
|
adamstark@38
|
242 break;
|
adamstark@57
|
243 }
|
adamstark@57
|
244 case HighFrequencySpectralDifference:
|
adamstark@57
|
245 {
|
adamstark@57
|
246 // calculate high frequency spectral difference detection function sample
|
adamstark@59
|
247 odfSample = highFrequencySpectralDifference();
|
adamstark@38
|
248 break;
|
adamstark@57
|
249 }
|
adamstark@57
|
250 case HighFrequencySpectralDifferenceHWR:
|
adamstark@57
|
251 {
|
adamstark@57
|
252 // calculate high frequency spectral difference detection function (half-wave rectified)
|
adamstark@59
|
253 odfSample = highFrequencySpectralDifferenceHWR();
|
adamstark@57
|
254 break;
|
adamstark@57
|
255 }
|
adamstark@38
|
256 default:
|
adamstark@57
|
257 {
|
adamstark@59
|
258 odfSample = 1.0;
|
adamstark@57
|
259 }
|
adamstark@38
|
260 }
|
adamstark@38
|
261
|
adamstark@59
|
262 return odfSample;
|
adamstark@38
|
263 }
|
adamstark@38
|
264
|
adamstark@38
|
265
|
adamstark@52
|
266 //=======================================================================
|
adamstark@92
|
267 void OnsetDetectionFunction::performFFT()
|
adamstark@38
|
268 {
|
adamstark@115
|
269 int fsize2 = (frameSize / 2);
|
adamstark@93
|
270
|
adamstark@93
|
271 #ifdef USE_FFTW
|
adamstark@38
|
272 // window frame and copy to complex array, swapping the first and second half of the signal
|
adamstark@115
|
273 for (int i = 0; i < fsize2; i++)
|
adamstark@38
|
274 {
|
adamstark@93
|
275 complexIn[i][0] = frame[i + fsize2] * window[i + fsize2];
|
adamstark@59
|
276 complexIn[i][1] = 0.0;
|
adamstark@59
|
277 complexIn[i+fsize2][0] = frame[i] * window[i];
|
adamstark@59
|
278 complexIn[i+fsize2][1] = 0.0;
|
adamstark@38
|
279 }
|
adamstark@38
|
280
|
adamstark@38
|
281 // perform the fft
|
adamstark@92
|
282 fftw_execute (p);
|
adamstark@93
|
283 #endif
|
adamstark@93
|
284
|
adamstark@93
|
285 #ifdef USE_KISS_FFT
|
adamstark@93
|
286 for (int i = 0; i < fsize2; i++)
|
adamstark@93
|
287 {
|
adamstark@93
|
288 fftIn[i].r = frame[i + fsize2] * window[i + fsize2];
|
adamstark@93
|
289 fftIn[i].i = 0.0;
|
adamstark@93
|
290 fftIn[i + fsize2].r = frame[i] * window[i];
|
adamstark@93
|
291 fftIn[i + fsize2].i = 0.0;
|
adamstark@93
|
292 }
|
adamstark@93
|
293
|
adamstark@93
|
294 // execute kiss fft
|
adamstark@93
|
295 kiss_fft (cfg, fftIn, fftOut);
|
adamstark@93
|
296
|
adamstark@93
|
297 // store real and imaginary parts of FFT
|
adamstark@93
|
298 for (int i = 0; i < frameSize; i++)
|
adamstark@93
|
299 {
|
adamstark@93
|
300 complexOut[i][0] = fftOut[i].r;
|
adamstark@93
|
301 complexOut[i][1] = fftOut[i].i;
|
adamstark@93
|
302 }
|
adamstark@93
|
303 #endif
|
adamstark@38
|
304 }
|
adamstark@38
|
305
|
adamstark@38
|
306 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
307 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
308 ////////////////////////////// Methods for Detection Functions /////////////////////////////////
|
adamstark@38
|
309
|
adamstark@52
|
310 //=======================================================================
|
adamstark@92
|
311 double OnsetDetectionFunction::energyEnvelope()
|
adamstark@38
|
312 {
|
adamstark@38
|
313 double sum;
|
adamstark@38
|
314
|
adamstark@38
|
315 sum = 0; // initialise sum
|
adamstark@38
|
316
|
adamstark@38
|
317 // sum the squares of the samples
|
adamstark@115
|
318 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
319 {
|
adamstark@92
|
320 sum = sum + (frame[i] * frame[i]);
|
adamstark@38
|
321 }
|
adamstark@38
|
322
|
adamstark@38
|
323 return sum; // return sum
|
adamstark@38
|
324 }
|
adamstark@38
|
325
|
adamstark@52
|
326 //=======================================================================
|
adamstark@92
|
327 double OnsetDetectionFunction::energyDifference()
|
adamstark@38
|
328 {
|
adamstark@38
|
329 double sum;
|
adamstark@38
|
330 double sample;
|
adamstark@38
|
331
|
adamstark@38
|
332 sum = 0; // initialise sum
|
adamstark@38
|
333
|
adamstark@38
|
334 // sum the squares of the samples
|
adamstark@92
|
335 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
336 {
|
adamstark@92
|
337 sum = sum + (frame[i] * frame[i]);
|
adamstark@38
|
338 }
|
adamstark@38
|
339
|
adamstark@59
|
340 sample = sum - prevEnergySum; // sample is first order difference in energy
|
adamstark@38
|
341
|
adamstark@59
|
342 prevEnergySum = sum; // store energy value for next calculation
|
adamstark@38
|
343
|
adamstark@38
|
344 if (sample > 0)
|
adamstark@38
|
345 {
|
adamstark@38
|
346 return sample; // return difference
|
adamstark@38
|
347 }
|
adamstark@38
|
348 else
|
adamstark@38
|
349 {
|
adamstark@38
|
350 return 0;
|
adamstark@38
|
351 }
|
adamstark@38
|
352 }
|
adamstark@38
|
353
|
adamstark@52
|
354 //=======================================================================
|
adamstark@92
|
355 double OnsetDetectionFunction::spectralDifference()
|
adamstark@38
|
356 {
|
adamstark@38
|
357 double diff;
|
adamstark@38
|
358 double sum;
|
adamstark@38
|
359
|
adamstark@38
|
360 // perform the FFT
|
adamstark@59
|
361 performFFT();
|
adamstark@38
|
362
|
adamstark@115
|
363 // compute first (N / 2) + 1 mag values
|
adamstark@115
|
364 for (int i = 0; i < (frameSize / 2) + 1; i++)
|
adamstark@38
|
365 {
|
adamstark@93
|
366 magSpec[i] = sqrt (pow (complexOut[i][0], 2) + pow (complexOut[i][1], 2));
|
adamstark@38
|
367 }
|
adamstark@115
|
368 // mag spec symmetric above (N / 2) + 1 so copy previous values
|
adamstark@115
|
369 for (int i = (frameSize / 2) + 1; i < frameSize; i++)
|
adamstark@38
|
370 {
|
adamstark@115
|
371 magSpec[i] = magSpec[frameSize - i];
|
adamstark@38
|
372 }
|
adamstark@38
|
373
|
adamstark@38
|
374 sum = 0; // initialise sum to zero
|
adamstark@38
|
375
|
adamstark@92
|
376 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
377 {
|
adamstark@38
|
378 // calculate difference
|
adamstark@59
|
379 diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
380
|
adamstark@38
|
381 // ensure all difference values are positive
|
adamstark@38
|
382 if (diff < 0)
|
adamstark@38
|
383 {
|
adamstark@115
|
384 diff = diff * -1;
|
adamstark@38
|
385 }
|
adamstark@38
|
386
|
adamstark@38
|
387 // add difference to sum
|
adamstark@92
|
388 sum = sum + diff;
|
adamstark@38
|
389
|
adamstark@38
|
390 // store magnitude spectrum bin for next detection function sample calculation
|
adamstark@59
|
391 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
392 }
|
adamstark@38
|
393
|
adamstark@38
|
394 return sum;
|
adamstark@38
|
395 }
|
adamstark@38
|
396
|
adamstark@52
|
397 //=======================================================================
|
adamstark@92
|
398 double OnsetDetectionFunction::spectralDifferenceHWR()
|
adamstark@38
|
399 {
|
adamstark@38
|
400 double diff;
|
adamstark@38
|
401 double sum;
|
adamstark@38
|
402
|
adamstark@38
|
403 // perform the FFT
|
adamstark@59
|
404 performFFT();
|
adamstark@38
|
405
|
adamstark@115
|
406 // compute first (N / 2) + 1 mag values
|
adamstark@115
|
407 for (int i = 0; i < (frameSize / 2) + 1; i++)
|
adamstark@38
|
408 {
|
adamstark@92
|
409 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
410 }
|
adamstark@115
|
411 // mag spec symmetric above (N / 2) + 1 so copy previous values
|
adamstark@115
|
412 for (int i = (frameSize / 2) + 1; i < frameSize; i++)
|
adamstark@38
|
413 {
|
adamstark@115
|
414 magSpec[i] = magSpec[frameSize - i];
|
adamstark@38
|
415 }
|
adamstark@38
|
416
|
adamstark@38
|
417 sum = 0; // initialise sum to zero
|
adamstark@38
|
418
|
adamstark@115
|
419 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
420 {
|
adamstark@38
|
421 // calculate difference
|
adamstark@59
|
422 diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
423
|
adamstark@38
|
424 // only add up positive differences
|
adamstark@38
|
425 if (diff > 0)
|
adamstark@38
|
426 {
|
adamstark@38
|
427 // add difference to sum
|
adamstark@38
|
428 sum = sum+diff;
|
adamstark@38
|
429 }
|
adamstark@38
|
430
|
adamstark@38
|
431 // store magnitude spectrum bin for next detection function sample calculation
|
adamstark@59
|
432 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
433 }
|
adamstark@38
|
434
|
adamstark@38
|
435 return sum;
|
adamstark@38
|
436 }
|
adamstark@38
|
437
|
adamstark@38
|
438
|
adamstark@52
|
439 //=======================================================================
|
adamstark@92
|
440 double OnsetDetectionFunction::phaseDeviation()
|
adamstark@38
|
441 {
|
adamstark@38
|
442 double dev,pdev;
|
adamstark@38
|
443 double sum;
|
adamstark@38
|
444
|
adamstark@38
|
445 // perform the FFT
|
adamstark@59
|
446 performFFT();
|
adamstark@38
|
447
|
adamstark@38
|
448 sum = 0; // initialise sum to zero
|
adamstark@38
|
449
|
adamstark@38
|
450 // compute phase values from fft output and sum deviations
|
adamstark@115
|
451 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
452 {
|
adamstark@38
|
453 // calculate phase value
|
adamstark@93
|
454 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
455
|
adamstark@38
|
456 // calculate magnitude value
|
adamstark@92
|
457 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
458
|
adamstark@38
|
459
|
adamstark@38
|
460 // if bin is not just a low energy bin then examine phase deviation
|
adamstark@59
|
461 if (magSpec[i] > 0.1)
|
adamstark@38
|
462 {
|
adamstark@115
|
463 dev = phase[i] - (2 * prevPhase[i]) + prevPhase2[i]; // phase deviation
|
adamstark@92
|
464 pdev = princarg (dev); // wrap into [-pi,pi] range
|
adamstark@38
|
465
|
adamstark@38
|
466 // make all values positive
|
adamstark@38
|
467 if (pdev < 0)
|
adamstark@38
|
468 {
|
adamstark@115
|
469 pdev = pdev * -1;
|
adamstark@38
|
470 }
|
adamstark@38
|
471
|
adamstark@38
|
472 // add to sum
|
adamstark@38
|
473 sum = sum + pdev;
|
adamstark@38
|
474 }
|
adamstark@38
|
475
|
adamstark@38
|
476 // store values for next calculation
|
adamstark@59
|
477 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
478 prevPhase[i] = phase[i];
|
adamstark@38
|
479 }
|
adamstark@38
|
480
|
adamstark@38
|
481 return sum;
|
adamstark@38
|
482 }
|
adamstark@38
|
483
|
adamstark@52
|
484 //=======================================================================
|
adamstark@92
|
485 double OnsetDetectionFunction::complexSpectralDifference()
|
adamstark@38
|
486 {
|
adamstark@86
|
487 double phaseDeviation;
|
adamstark@38
|
488 double sum;
|
adamstark@86
|
489 double csd;
|
adamstark@38
|
490
|
adamstark@38
|
491 // perform the FFT
|
adamstark@59
|
492 performFFT();
|
adamstark@38
|
493
|
adamstark@38
|
494 sum = 0; // initialise sum to zero
|
adamstark@38
|
495
|
adamstark@38
|
496 // compute phase values from fft output and sum deviations
|
adamstark@115
|
497 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
498 {
|
adamstark@38
|
499 // calculate phase value
|
adamstark@93
|
500 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
501
|
adamstark@38
|
502 // calculate magnitude value
|
adamstark@92
|
503 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2));
|
adamstark@38
|
504
|
adamstark@86
|
505 // phase deviation
|
adamstark@92
|
506 phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i];
|
adamstark@38
|
507
|
adamstark@86
|
508 // calculate complex spectral difference for the current spectral bin
|
adamstark@92
|
509 csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation));
|
adamstark@38
|
510
|
adamstark@38
|
511 // add to sum
|
adamstark@86
|
512 sum = sum + csd;
|
adamstark@38
|
513
|
adamstark@38
|
514 // store values for next calculation
|
adamstark@59
|
515 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
516 prevPhase[i] = phase[i];
|
adamstark@59
|
517 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
518 }
|
adamstark@38
|
519
|
adamstark@38
|
520 return sum;
|
adamstark@38
|
521 }
|
adamstark@38
|
522
|
adamstark@52
|
523 //=======================================================================
|
adamstark@92
|
524 double OnsetDetectionFunction::complexSpectralDifferenceHWR()
|
adamstark@38
|
525 {
|
adamstark@86
|
526 double phaseDeviation;
|
adamstark@38
|
527 double sum;
|
adamstark@86
|
528 double magnitudeDifference;
|
adamstark@86
|
529 double csd;
|
adamstark@38
|
530
|
adamstark@38
|
531 // perform the FFT
|
adamstark@59
|
532 performFFT();
|
adamstark@38
|
533
|
adamstark@38
|
534 sum = 0; // initialise sum to zero
|
adamstark@38
|
535
|
adamstark@38
|
536 // compute phase values from fft output and sum deviations
|
adamstark@115
|
537 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
538 {
|
adamstark@38
|
539 // calculate phase value
|
adamstark@93
|
540 phase[i] = atan2 (complexOut[i][1], complexOut[i][0]);
|
adamstark@38
|
541
|
adamstark@38
|
542 // calculate magnitude value
|
adamstark@92
|
543 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2));
|
adamstark@38
|
544
|
adamstark@86
|
545 // phase deviation
|
adamstark@92
|
546 phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i];
|
adamstark@86
|
547
|
adamstark@86
|
548 // calculate magnitude difference (real part of Euclidean distance between complex frames)
|
adamstark@86
|
549 magnitudeDifference = magSpec[i] - prevMagSpec[i];
|
adamstark@86
|
550
|
adamstark@86
|
551 // if we have a positive change in magnitude, then include in sum, otherwise ignore (half-wave rectification)
|
adamstark@86
|
552 if (magnitudeDifference > 0)
|
adamstark@86
|
553 {
|
adamstark@86
|
554 // calculate complex spectral difference for the current spectral bin
|
adamstark@92
|
555 csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation));
|
adamstark@86
|
556
|
adamstark@86
|
557 // add to sum
|
adamstark@86
|
558 sum = sum + csd;
|
adamstark@86
|
559 }
|
adamstark@86
|
560
|
adamstark@38
|
561 // store values for next calculation
|
adamstark@59
|
562 prevPhase2[i] = prevPhase[i];
|
adamstark@59
|
563 prevPhase[i] = phase[i];
|
adamstark@59
|
564 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
565 }
|
adamstark@38
|
566
|
adamstark@38
|
567 return sum;
|
adamstark@38
|
568 }
|
adamstark@38
|
569
|
adamstark@38
|
570
|
adamstark@52
|
571 //=======================================================================
|
adamstark@92
|
572 double OnsetDetectionFunction::highFrequencyContent()
|
adamstark@38
|
573 {
|
adamstark@38
|
574 double sum;
|
adamstark@38
|
575
|
adamstark@38
|
576 // perform the FFT
|
adamstark@59
|
577 performFFT();
|
adamstark@38
|
578
|
adamstark@38
|
579 sum = 0; // initialise sum to zero
|
adamstark@38
|
580
|
adamstark@38
|
581 // compute phase values from fft output and sum deviations
|
adamstark@92
|
582 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
583 {
|
adamstark@38
|
584 // calculate magnitude value
|
adamstark@92
|
585 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
586
|
adamstark@38
|
587
|
adamstark@115
|
588 sum = sum + (magSpec[i] * ((double) (i + 1)));
|
adamstark@38
|
589
|
adamstark@38
|
590 // store values for next calculation
|
adamstark@59
|
591 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
592 }
|
adamstark@38
|
593
|
adamstark@38
|
594 return sum;
|
adamstark@38
|
595 }
|
adamstark@38
|
596
|
adamstark@52
|
597 //=======================================================================
|
adamstark@92
|
598 double OnsetDetectionFunction::highFrequencySpectralDifference()
|
adamstark@38
|
599 {
|
adamstark@38
|
600 double sum;
|
adamstark@38
|
601 double mag_diff;
|
adamstark@38
|
602
|
adamstark@38
|
603 // perform the FFT
|
adamstark@59
|
604 performFFT();
|
adamstark@38
|
605
|
adamstark@38
|
606 sum = 0; // initialise sum to zero
|
adamstark@38
|
607
|
adamstark@38
|
608 // compute phase values from fft output and sum deviations
|
adamstark@115
|
609 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
610 {
|
adamstark@38
|
611 // calculate magnitude value
|
adamstark@92
|
612 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
613
|
adamstark@38
|
614 // calculate difference
|
adamstark@59
|
615 mag_diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
616
|
adamstark@38
|
617 if (mag_diff < 0)
|
adamstark@38
|
618 {
|
adamstark@38
|
619 mag_diff = -mag_diff;
|
adamstark@38
|
620 }
|
adamstark@38
|
621
|
adamstark@115
|
622 sum = sum + (mag_diff * ((double) (i + 1)));
|
adamstark@38
|
623
|
adamstark@38
|
624 // store values for next calculation
|
adamstark@59
|
625 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
626 }
|
adamstark@38
|
627
|
adamstark@38
|
628 return sum;
|
adamstark@38
|
629 }
|
adamstark@38
|
630
|
adamstark@52
|
631 //=======================================================================
|
adamstark@92
|
632 double OnsetDetectionFunction::highFrequencySpectralDifferenceHWR()
|
adamstark@38
|
633 {
|
adamstark@38
|
634 double sum;
|
adamstark@38
|
635 double mag_diff;
|
adamstark@38
|
636
|
adamstark@38
|
637 // perform the FFT
|
adamstark@59
|
638 performFFT();
|
adamstark@38
|
639
|
adamstark@38
|
640 sum = 0; // initialise sum to zero
|
adamstark@38
|
641
|
adamstark@38
|
642 // compute phase values from fft output and sum deviations
|
adamstark@115
|
643 for (int i = 0; i < frameSize; i++)
|
adamstark@38
|
644 {
|
adamstark@38
|
645 // calculate magnitude value
|
adamstark@92
|
646 magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2));
|
adamstark@38
|
647
|
adamstark@38
|
648 // calculate difference
|
adamstark@59
|
649 mag_diff = magSpec[i] - prevMagSpec[i];
|
adamstark@38
|
650
|
adamstark@38
|
651 if (mag_diff > 0)
|
adamstark@38
|
652 {
|
adamstark@115
|
653 sum = sum + (mag_diff * ((double) (i + 1)));
|
adamstark@38
|
654 }
|
adamstark@38
|
655
|
adamstark@38
|
656 // store values for next calculation
|
adamstark@59
|
657 prevMagSpec[i] = magSpec[i];
|
adamstark@38
|
658 }
|
adamstark@38
|
659
|
adamstark@38
|
660 return sum;
|
adamstark@38
|
661 }
|
adamstark@38
|
662
|
adamstark@38
|
663
|
adamstark@38
|
664 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
665 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
666 ////////////////////////////// Methods to Calculate Windows ////////////////////////////////////
|
adamstark@38
|
667
|
adamstark@52
|
668 //=======================================================================
|
adamstark@92
|
669 void OnsetDetectionFunction::calculateHanningWindow()
|
adamstark@38
|
670 {
|
adamstark@38
|
671 double N; // variable to store framesize minus 1
|
adamstark@38
|
672
|
adamstark@115
|
673 N = (double) (frameSize - 1); // framesize minus 1
|
adamstark@38
|
674
|
adamstark@38
|
675 // Hanning window calculation
|
adamstark@92
|
676 for (int n = 0; n < frameSize; n++)
|
adamstark@38
|
677 {
|
adamstark@92
|
678 window[n] = 0.5 * (1 - cos (2 * pi * (n / N)));
|
adamstark@38
|
679 }
|
adamstark@38
|
680 }
|
adamstark@38
|
681
|
adamstark@52
|
682 //=======================================================================
|
adamstark@92
|
683 void OnsetDetectionFunction::calclulateHammingWindow()
|
adamstark@38
|
684 {
|
adamstark@38
|
685 double N; // variable to store framesize minus 1
|
adamstark@38
|
686 double n_val; // double version of index 'n'
|
adamstark@38
|
687
|
adamstark@115
|
688 N = (double) (frameSize - 1); // framesize minus 1
|
adamstark@38
|
689 n_val = 0;
|
adamstark@38
|
690
|
adamstark@38
|
691 // Hamming window calculation
|
adamstark@115
|
692 for (int n = 0; n < frameSize; n++)
|
adamstark@38
|
693 {
|
adamstark@115
|
694 window[n] = 0.54 - (0.46 * cos (2 * pi * (n_val / N)));
|
adamstark@38
|
695 n_val = n_val+1;
|
adamstark@38
|
696 }
|
adamstark@38
|
697 }
|
adamstark@38
|
698
|
adamstark@52
|
699 //=======================================================================
|
adamstark@92
|
700 void OnsetDetectionFunction::calculateBlackmanWindow()
|
adamstark@38
|
701 {
|
adamstark@38
|
702 double N; // variable to store framesize minus 1
|
adamstark@38
|
703 double n_val; // double version of index 'n'
|
adamstark@38
|
704
|
adamstark@115
|
705 N = (double) (frameSize - 1); // framesize minus 1
|
adamstark@38
|
706 n_val = 0;
|
adamstark@38
|
707
|
adamstark@38
|
708 // Blackman window calculation
|
adamstark@115
|
709 for (int n = 0; n < frameSize; n++)
|
adamstark@38
|
710 {
|
adamstark@115
|
711 window[n] = 0.42 - (0.5 * cos (2 * pi * (n_val / N))) + (0.08 * cos (4 * pi * (n_val / N)));
|
adamstark@115
|
712 n_val = n_val + 1;
|
adamstark@38
|
713 }
|
adamstark@38
|
714 }
|
adamstark@38
|
715
|
adamstark@52
|
716 //=======================================================================
|
adamstark@92
|
717 void OnsetDetectionFunction::calculateTukeyWindow()
|
adamstark@38
|
718 {
|
adamstark@38
|
719 double N; // variable to store framesize minus 1
|
adamstark@38
|
720 double n_val; // double version of index 'n'
|
adamstark@38
|
721 double alpha; // alpha [default value = 0.5];
|
adamstark@38
|
722
|
adamstark@38
|
723 alpha = 0.5;
|
adamstark@38
|
724
|
adamstark@115
|
725 N = (double) (frameSize - 1); // framesize minus 1
|
adamstark@38
|
726
|
adamstark@38
|
727 // Tukey window calculation
|
adamstark@38
|
728
|
adamstark@115
|
729 n_val = (double) (-1 * ((frameSize / 2))) + 1;
|
adamstark@38
|
730
|
adamstark@115
|
731 for (int n = 0; n < frameSize; n++) // left taper
|
adamstark@38
|
732 {
|
adamstark@115
|
733 if ((n_val >= 0) && (n_val <= (alpha * (N / 2))))
|
adamstark@38
|
734 {
|
adamstark@38
|
735 window[n] = 1.0;
|
adamstark@38
|
736 }
|
adamstark@115
|
737 else if ((n_val <= 0) && (n_val >= (-1 * alpha * (N / 2))))
|
adamstark@38
|
738 {
|
adamstark@38
|
739 window[n] = 1.0;
|
adamstark@38
|
740 }
|
adamstark@38
|
741 else
|
adamstark@38
|
742 {
|
adamstark@115
|
743 window[n] = 0.5 * (1 + cos (pi * (((2 * n_val) / (alpha * N)) - 1)));
|
adamstark@38
|
744 }
|
adamstark@38
|
745
|
adamstark@115
|
746 n_val = n_val + 1;
|
adamstark@38
|
747 }
|
adamstark@38
|
748
|
adamstark@38
|
749 }
|
adamstark@38
|
750
|
adamstark@52
|
751 //=======================================================================
|
adamstark@92
|
752 void OnsetDetectionFunction::calculateRectangularWindow()
|
adamstark@38
|
753 {
|
adamstark@38
|
754 // Rectangular window calculation
|
adamstark@115
|
755 for (int n = 0; n < frameSize; n++)
|
adamstark@38
|
756 {
|
adamstark@38
|
757 window[n] = 1.0;
|
adamstark@38
|
758 }
|
adamstark@38
|
759 }
|
adamstark@38
|
760
|
adamstark@38
|
761 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
762 ////////////////////////////////////////////////////////////////////////////////////////////////
|
adamstark@38
|
763 ///////////////////////////////// Other Handy Methods //////////////////////////////////////////
|
adamstark@38
|
764
|
adamstark@52
|
765 //=======================================================================
|
adamstark@92
|
766 double OnsetDetectionFunction::princarg(double phaseVal)
|
adamstark@38
|
767 {
|
adamstark@38
|
768 // if phase value is less than or equal to -pi then add 2*pi
|
adamstark@59
|
769 while (phaseVal <= (-pi))
|
adamstark@38
|
770 {
|
adamstark@92
|
771 phaseVal = phaseVal + (2 * pi);
|
adamstark@38
|
772 }
|
adamstark@38
|
773
|
adamstark@38
|
774 // if phase value is larger than pi, then subtract 2*pi
|
adamstark@59
|
775 while (phaseVal > pi)
|
adamstark@38
|
776 {
|
adamstark@92
|
777 phaseVal = phaseVal - (2 * pi);
|
adamstark@38
|
778 }
|
adamstark@38
|
779
|
adamstark@59
|
780 return phaseVal;
|
adamstark@38
|
781 }
|