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