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