annotate src/OnsetDetectionFunction.cpp @ 115:54c657d621dd

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