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