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