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