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