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