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