adamstark@38: //======================================================================= adamstark@38: /** @file OnsetDetectionFunction.cpp adamstark@38: * @brief A class for calculating onset detection functions adamstark@38: * @author Adam Stark adamstark@38: * @copyright Copyright (C) 2008-2014 Queen Mary University of London adamstark@38: * adamstark@38: * This program is free software: you can redistribute it and/or modify adamstark@38: * it under the terms of the GNU General Public License as published by adamstark@38: * the Free Software Foundation, either version 3 of the License, or adamstark@38: * (at your option) any later version. adamstark@38: * adamstark@38: * This program is distributed in the hope that it will be useful, adamstark@38: * but WITHOUT ANY WARRANTY; without even the implied warranty of adamstark@38: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the adamstark@38: * GNU General Public License for more details. adamstark@38: * adamstark@38: * You should have received a copy of the GNU General Public License adamstark@38: * along with this program. If not, see . adamstark@38: */ adamstark@38: //======================================================================= adamstark@38: adamstark@38: #include adamstark@38: #include "OnsetDetectionFunction.h" adamstark@38: adamstark@52: //======================================================================= adamstark@115: OnsetDetectionFunction::OnsetDetectionFunction (int hopSize_, int frameSize_) adamstark@92: : onsetDetectionFunctionType (ComplexSpectralDifferenceHWR), windowType (HanningWindow) adamstark@66: { adamstark@66: // indicate that we have not initialised yet adamstark@66: initialised = false; adamstark@66: adamstark@66: // set pi adamstark@66: pi = 3.14159265358979; adamstark@66: adamstark@66: // initialise with arguments to constructor adamstark@92: initialise (hopSize_, frameSize_, ComplexSpectralDifferenceHWR, HanningWindow); adamstark@66: } adamstark@66: adamstark@66: //======================================================================= adamstark@115: OnsetDetectionFunction::OnsetDetectionFunction (int hopSize_, int frameSize_, int onsetDetectionFunctionType_, int windowType_) adamstark@92: : onsetDetectionFunctionType (ComplexSpectralDifferenceHWR), windowType (HanningWindow) adamstark@38: { adamstark@38: // indicate that we have not initialised yet adamstark@64: initialised = false; adamstark@38: adamstark@38: // set pi adamstark@38: pi = 3.14159265358979; adamstark@38: adamstark@38: // initialise with arguments to constructor adamstark@92: initialise (hopSize_, frameSize_, onsetDetectionFunctionType_, windowType_); adamstark@38: } adamstark@38: adamstark@38: adamstark@52: //======================================================================= adamstark@59: OnsetDetectionFunction::~OnsetDetectionFunction() adamstark@38: { adamstark@64: if (initialised) adamstark@64: { adamstark@93: freeFFT(); adamstark@64: } adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::initialise (int hopSize_, int frameSize_) adamstark@66: { adamstark@66: // use the already initialised onset detection function and window type and adamstark@66: // pass the new frame and hop size to the main initialisation function adamstark@92: initialise (hopSize_, frameSize_, onsetDetectionFunctionType, windowType); adamstark@66: } adamstark@66: adamstark@66: //======================================================================= adamstark@115: void OnsetDetectionFunction::initialise (int hopSize_, int frameSize_, int onsetDetectionFunctionType_, int windowType_) adamstark@38: { adamstark@59: hopSize = hopSize_; // set hopsize adamstark@59: frameSize = frameSize_; // set framesize adamstark@38: adamstark@59: onsetDetectionFunctionType = onsetDetectionFunctionType_; // set detection function type adamstark@66: windowType = windowType_; // set window type adamstark@38: adamstark@38: // initialise buffers adamstark@92: frame.resize (frameSize); adamstark@92: window.resize (frameSize); adamstark@92: magSpec.resize (frameSize); adamstark@92: prevMagSpec.resize (frameSize); adamstark@92: phase.resize (frameSize); adamstark@92: prevPhase.resize (frameSize); adamstark@92: prevPhase2.resize (frameSize); adamstark@38: adamstark@38: adamstark@38: // set the window to the specified type adamstark@92: switch (windowType) adamstark@92: { adamstark@57: case RectangularWindow: adamstark@59: calculateRectangularWindow(); // Rectangular window adamstark@38: break; adamstark@57: case HanningWindow: adamstark@59: calculateHanningWindow(); // Hanning Window adamstark@38: break; adamstark@57: case HammingWindow: adamstark@59: calclulateHammingWindow(); // Hamming Window adamstark@38: break; adamstark@57: case BlackmanWindow: adamstark@59: calculateBlackmanWindow(); // Blackman Window adamstark@38: break; adamstark@57: case TukeyWindow: adamstark@59: calculateTukeyWindow(); // Tukey Window adamstark@38: break; adamstark@38: default: adamstark@59: calculateHanningWindow(); // DEFAULT: Hanning Window adamstark@38: } adamstark@38: adamstark@38: // initialise previous magnitude spectrum to zero adamstark@92: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@59: prevMagSpec[i] = 0.0; adamstark@59: prevPhase[i] = 0.0; adamstark@59: prevPhase2[i] = 0.0; adamstark@38: frame[i] = 0.0; adamstark@38: } adamstark@38: adamstark@59: prevEnergySum = 0.0; // initialise previous energy sum value to zero adamstark@38: adamstark@93: initialiseFFT(); adamstark@93: } adamstark@93: adamstark@93: //======================================================================= adamstark@93: void OnsetDetectionFunction::initialiseFFT() adamstark@93: { adamstark@93: if (initialised) // if we have already initialised FFT plan adamstark@93: { adamstark@93: freeFFT(); adamstark@93: } adamstark@93: adamstark@93: #ifdef USE_FFTW adamstark@93: complexIn = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * frameSize); // complex array to hold fft data adamstark@93: complexOut = (fftw_complex*) fftw_malloc (sizeof(fftw_complex) * frameSize); // complex array to hold fft data adamstark@93: p = fftw_plan_dft_1d (frameSize, complexIn, complexOut, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation adamstark@93: #endif adamstark@93: adamstark@93: #ifdef USE_KISS_FFT adamstark@93: complexOut.resize (frameSize); adamstark@93: adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@93: { adamstark@93: complexOut[i].resize(2); adamstark@93: } adamstark@93: adamstark@93: fftIn = new kiss_fft_cpx[frameSize]; adamstark@93: fftOut = new kiss_fft_cpx[frameSize]; adamstark@93: cfg = kiss_fft_alloc (frameSize, 0, 0, 0); adamstark@93: #endif adamstark@93: adamstark@93: initialised = true; adamstark@93: } adamstark@93: adamstark@93: //======================================================================= adamstark@93: void OnsetDetectionFunction::freeFFT() adamstark@93: { adamstark@93: #ifdef USE_FFTW adamstark@93: fftw_destroy_plan (p); adamstark@93: fftw_free (complexIn); adamstark@93: fftw_free (complexOut); adamstark@93: #endif adamstark@93: adamstark@93: #ifdef USE_KISS_FFT adamstark@93: free (cfg); adamstark@93: delete [] fftIn; adamstark@93: delete [] fftOut; adamstark@93: #endif adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::setOnsetDetectionFunctionType (int onsetDetectionFunctionType_) adamstark@38: { adamstark@59: onsetDetectionFunctionType = onsetDetectionFunctionType_; // set detection function type adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::calculateOnsetDetectionFunctionSample (double* buffer) adamstark@38: { adamstark@59: double odfSample; adamstark@38: adamstark@38: // shift audio samples back in frame by hop size adamstark@100: std::rotate (frame.begin(), frame.begin() + hopSize, frame.end()); adamstark@38: adamstark@38: // add new samples to frame from input buffer adamstark@38: int j = 0; adamstark@100: for (int i = (frameSize - hopSize); i < frameSize; i++) adamstark@38: { adamstark@59: frame[i] = buffer[j]; adamstark@38: j++; adamstark@38: } adamstark@38: adamstark@92: switch (onsetDetectionFunctionType) adamstark@92: { adamstark@57: case EnergyEnvelope: adamstark@57: { adamstark@57: // calculate energy envelope detection function sample adamstark@59: odfSample = energyEnvelope(); adamstark@38: break; adamstark@57: } adamstark@57: case EnergyDifference: adamstark@57: { adamstark@57: // calculate half-wave rectified energy difference detection function sample adamstark@59: odfSample = energyDifference(); adamstark@38: break; adamstark@57: } adamstark@57: case SpectralDifference: adamstark@57: { adamstark@57: // calculate spectral difference detection function sample adamstark@59: odfSample = spectralDifference(); adamstark@38: break; adamstark@57: } adamstark@57: case SpectralDifferenceHWR: adamstark@57: { adamstark@57: // calculate spectral difference detection function sample (half wave rectified) adamstark@59: odfSample = spectralDifferenceHWR(); adamstark@38: break; adamstark@57: } adamstark@57: case PhaseDeviation: adamstark@57: { adamstark@57: // calculate phase deviation detection function sample (half wave rectified) adamstark@59: odfSample = phaseDeviation(); adamstark@38: break; adamstark@57: } adamstark@57: case ComplexSpectralDifference: adamstark@57: { adamstark@57: // calcualte complex spectral difference detection function sample adamstark@59: odfSample = complexSpectralDifference(); adamstark@38: break; adamstark@57: } adamstark@57: case ComplexSpectralDifferenceHWR: adamstark@57: { adamstark@57: // calcualte complex spectral difference detection function sample (half-wave rectified) adamstark@59: odfSample = complexSpectralDifferenceHWR(); adamstark@38: break; adamstark@57: } adamstark@57: case HighFrequencyContent: adamstark@57: { adamstark@57: // calculate high frequency content detection function sample adamstark@59: odfSample = highFrequencyContent(); adamstark@38: break; adamstark@57: } adamstark@57: case HighFrequencySpectralDifference: adamstark@57: { adamstark@57: // calculate high frequency spectral difference detection function sample adamstark@59: odfSample = highFrequencySpectralDifference(); adamstark@38: break; adamstark@57: } adamstark@57: case HighFrequencySpectralDifferenceHWR: adamstark@57: { adamstark@57: // calculate high frequency spectral difference detection function (half-wave rectified) adamstark@59: odfSample = highFrequencySpectralDifferenceHWR(); adamstark@57: break; adamstark@57: } adamstark@38: default: adamstark@57: { adamstark@59: odfSample = 1.0; adamstark@57: } adamstark@38: } adamstark@38: adamstark@59: return odfSample; adamstark@38: } adamstark@38: adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::performFFT() adamstark@38: { adamstark@115: int fsize2 = (frameSize / 2); adamstark@93: adamstark@93: #ifdef USE_FFTW adamstark@38: // window frame and copy to complex array, swapping the first and second half of the signal adamstark@115: for (int i = 0; i < fsize2; i++) adamstark@38: { adamstark@93: complexIn[i][0] = frame[i + fsize2] * window[i + fsize2]; adamstark@59: complexIn[i][1] = 0.0; adamstark@59: complexIn[i+fsize2][0] = frame[i] * window[i]; adamstark@59: complexIn[i+fsize2][1] = 0.0; adamstark@38: } adamstark@38: adamstark@38: // perform the fft adamstark@92: fftw_execute (p); adamstark@93: #endif adamstark@93: adamstark@93: #ifdef USE_KISS_FFT adamstark@93: for (int i = 0; i < fsize2; i++) adamstark@93: { adamstark@93: fftIn[i].r = frame[i + fsize2] * window[i + fsize2]; adamstark@93: fftIn[i].i = 0.0; adamstark@93: fftIn[i + fsize2].r = frame[i] * window[i]; adamstark@93: fftIn[i + fsize2].i = 0.0; adamstark@93: } adamstark@93: adamstark@93: // execute kiss fft adamstark@93: kiss_fft (cfg, fftIn, fftOut); adamstark@93: adamstark@93: // store real and imaginary parts of FFT adamstark@93: for (int i = 0; i < frameSize; i++) adamstark@93: { adamstark@93: complexOut[i][0] = fftOut[i].r; adamstark@93: complexOut[i][1] = fftOut[i].i; adamstark@93: } adamstark@93: #endif adamstark@38: } adamstark@38: adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: ////////////////////////////// Methods for Detection Functions ///////////////////////////////// adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::energyEnvelope() adamstark@38: { adamstark@38: double sum; adamstark@38: adamstark@38: sum = 0; // initialise sum adamstark@38: adamstark@38: // sum the squares of the samples adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@92: sum = sum + (frame[i] * frame[i]); adamstark@38: } adamstark@38: adamstark@38: return sum; // return sum adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::energyDifference() adamstark@38: { adamstark@38: double sum; adamstark@38: double sample; adamstark@38: adamstark@38: sum = 0; // initialise sum adamstark@38: adamstark@38: // sum the squares of the samples adamstark@92: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@92: sum = sum + (frame[i] * frame[i]); adamstark@38: } adamstark@38: adamstark@59: sample = sum - prevEnergySum; // sample is first order difference in energy adamstark@38: adamstark@59: prevEnergySum = sum; // store energy value for next calculation adamstark@38: adamstark@38: if (sample > 0) adamstark@38: { adamstark@38: return sample; // return difference adamstark@38: } adamstark@38: else adamstark@38: { adamstark@38: return 0; adamstark@38: } adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::spectralDifference() adamstark@38: { adamstark@38: double diff; adamstark@38: double sum; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@115: // compute first (N / 2) + 1 mag values adamstark@115: for (int i = 0; i < (frameSize / 2) + 1; i++) adamstark@38: { adamstark@93: magSpec[i] = sqrt (pow (complexOut[i][0], 2) + pow (complexOut[i][1], 2)); adamstark@38: } adamstark@115: // mag spec symmetric above (N / 2) + 1 so copy previous values adamstark@115: for (int i = (frameSize / 2) + 1; i < frameSize; i++) adamstark@38: { adamstark@115: magSpec[i] = magSpec[frameSize - i]; adamstark@38: } adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@92: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate difference adamstark@59: diff = magSpec[i] - prevMagSpec[i]; adamstark@38: adamstark@38: // ensure all difference values are positive adamstark@38: if (diff < 0) adamstark@38: { adamstark@115: diff = diff * -1; adamstark@38: } adamstark@38: adamstark@38: // add difference to sum adamstark@92: sum = sum + diff; adamstark@38: adamstark@38: // store magnitude spectrum bin for next detection function sample calculation adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::spectralDifferenceHWR() adamstark@38: { adamstark@38: double diff; adamstark@38: double sum; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@115: // compute first (N / 2) + 1 mag values adamstark@115: for (int i = 0; i < (frameSize / 2) + 1; i++) adamstark@38: { adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2)); adamstark@38: } adamstark@115: // mag spec symmetric above (N / 2) + 1 so copy previous values adamstark@115: for (int i = (frameSize / 2) + 1; i < frameSize; i++) adamstark@38: { adamstark@115: magSpec[i] = magSpec[frameSize - i]; adamstark@38: } adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate difference adamstark@59: diff = magSpec[i] - prevMagSpec[i]; adamstark@38: adamstark@38: // only add up positive differences adamstark@38: if (diff > 0) adamstark@38: { adamstark@38: // add difference to sum adamstark@38: sum = sum+diff; adamstark@38: } adamstark@38: adamstark@38: // store magnitude spectrum bin for next detection function sample calculation adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::phaseDeviation() adamstark@38: { adamstark@38: double dev,pdev; adamstark@38: double sum; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate phase value adamstark@93: phase[i] = atan2 (complexOut[i][1], complexOut[i][0]); adamstark@38: adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2)); adamstark@38: adamstark@38: adamstark@38: // if bin is not just a low energy bin then examine phase deviation adamstark@59: if (magSpec[i] > 0.1) adamstark@38: { adamstark@115: dev = phase[i] - (2 * prevPhase[i]) + prevPhase2[i]; // phase deviation adamstark@92: pdev = princarg (dev); // wrap into [-pi,pi] range adamstark@38: adamstark@38: // make all values positive adamstark@38: if (pdev < 0) adamstark@38: { adamstark@115: pdev = pdev * -1; adamstark@38: } adamstark@38: adamstark@38: // add to sum adamstark@38: sum = sum + pdev; adamstark@38: } adamstark@38: adamstark@38: // store values for next calculation adamstark@59: prevPhase2[i] = prevPhase[i]; adamstark@59: prevPhase[i] = phase[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::complexSpectralDifference() adamstark@38: { adamstark@86: double phaseDeviation; adamstark@38: double sum; adamstark@86: double csd; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate phase value adamstark@93: phase[i] = atan2 (complexOut[i][1], complexOut[i][0]); adamstark@38: adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2)); adamstark@38: adamstark@86: // phase deviation adamstark@92: phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i]; adamstark@38: adamstark@86: // calculate complex spectral difference for the current spectral bin adamstark@92: csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation)); adamstark@38: adamstark@38: // add to sum adamstark@86: sum = sum + csd; adamstark@38: adamstark@38: // store values for next calculation adamstark@59: prevPhase2[i] = prevPhase[i]; adamstark@59: prevPhase[i] = phase[i]; adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::complexSpectralDifferenceHWR() adamstark@38: { adamstark@86: double phaseDeviation; adamstark@38: double sum; adamstark@86: double magnitudeDifference; adamstark@86: double csd; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate phase value adamstark@93: phase[i] = atan2 (complexOut[i][1], complexOut[i][0]); adamstark@38: adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow(complexOut[i][1],2)); adamstark@38: adamstark@86: // phase deviation adamstark@92: phaseDeviation = phase[i] - (2 * prevPhase[i]) + prevPhase2[i]; adamstark@86: adamstark@86: // calculate magnitude difference (real part of Euclidean distance between complex frames) adamstark@86: magnitudeDifference = magSpec[i] - prevMagSpec[i]; adamstark@86: adamstark@86: // if we have a positive change in magnitude, then include in sum, otherwise ignore (half-wave rectification) adamstark@86: if (magnitudeDifference > 0) adamstark@86: { adamstark@86: // calculate complex spectral difference for the current spectral bin adamstark@92: csd = sqrt (pow (magSpec[i], 2) + pow (prevMagSpec[i], 2) - 2 * magSpec[i] * prevMagSpec[i] * cos (phaseDeviation)); adamstark@86: adamstark@86: // add to sum adamstark@86: sum = sum + csd; adamstark@86: } adamstark@86: adamstark@38: // store values for next calculation adamstark@59: prevPhase2[i] = prevPhase[i]; adamstark@59: prevPhase[i] = phase[i]; adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::highFrequencyContent() adamstark@38: { adamstark@38: double sum; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@92: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2)); adamstark@38: adamstark@38: adamstark@115: sum = sum + (magSpec[i] * ((double) (i + 1))); adamstark@38: adamstark@38: // store values for next calculation adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::highFrequencySpectralDifference() adamstark@38: { adamstark@38: double sum; adamstark@38: double mag_diff; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2)); adamstark@38: adamstark@38: // calculate difference adamstark@59: mag_diff = magSpec[i] - prevMagSpec[i]; adamstark@38: adamstark@38: if (mag_diff < 0) adamstark@38: { adamstark@38: mag_diff = -mag_diff; adamstark@38: } adamstark@38: adamstark@115: sum = sum + (mag_diff * ((double) (i + 1))); adamstark@38: adamstark@38: // store values for next calculation adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::highFrequencySpectralDifferenceHWR() adamstark@38: { adamstark@38: double sum; adamstark@38: double mag_diff; adamstark@38: adamstark@38: // perform the FFT adamstark@59: performFFT(); adamstark@38: adamstark@38: sum = 0; // initialise sum to zero adamstark@38: adamstark@38: // compute phase values from fft output and sum deviations adamstark@115: for (int i = 0; i < frameSize; i++) adamstark@38: { adamstark@38: // calculate magnitude value adamstark@92: magSpec[i] = sqrt (pow (complexOut[i][0],2) + pow (complexOut[i][1],2)); adamstark@38: adamstark@38: // calculate difference adamstark@59: mag_diff = magSpec[i] - prevMagSpec[i]; adamstark@38: adamstark@38: if (mag_diff > 0) adamstark@38: { adamstark@115: sum = sum + (mag_diff * ((double) (i + 1))); adamstark@38: } adamstark@38: adamstark@38: // store values for next calculation adamstark@59: prevMagSpec[i] = magSpec[i]; adamstark@38: } adamstark@38: adamstark@38: return sum; adamstark@38: } adamstark@38: adamstark@38: adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: ////////////////////////////// Methods to Calculate Windows //////////////////////////////////// adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::calculateHanningWindow() adamstark@38: { adamstark@38: double N; // variable to store framesize minus 1 adamstark@38: adamstark@115: N = (double) (frameSize - 1); // framesize minus 1 adamstark@38: adamstark@38: // Hanning window calculation adamstark@92: for (int n = 0; n < frameSize; n++) adamstark@38: { adamstark@92: window[n] = 0.5 * (1 - cos (2 * pi * (n / N))); adamstark@38: } adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::calclulateHammingWindow() adamstark@38: { adamstark@38: double N; // variable to store framesize minus 1 adamstark@38: double n_val; // double version of index 'n' adamstark@38: adamstark@115: N = (double) (frameSize - 1); // framesize minus 1 adamstark@38: n_val = 0; adamstark@38: adamstark@38: // Hamming window calculation adamstark@115: for (int n = 0; n < frameSize; n++) adamstark@38: { adamstark@115: window[n] = 0.54 - (0.46 * cos (2 * pi * (n_val / N))); adamstark@38: n_val = n_val+1; adamstark@38: } adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::calculateBlackmanWindow() adamstark@38: { adamstark@38: double N; // variable to store framesize minus 1 adamstark@38: double n_val; // double version of index 'n' adamstark@38: adamstark@115: N = (double) (frameSize - 1); // framesize minus 1 adamstark@38: n_val = 0; adamstark@38: adamstark@38: // Blackman window calculation adamstark@115: for (int n = 0; n < frameSize; n++) adamstark@38: { adamstark@115: window[n] = 0.42 - (0.5 * cos (2 * pi * (n_val / N))) + (0.08 * cos (4 * pi * (n_val / N))); adamstark@115: n_val = n_val + 1; adamstark@38: } adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::calculateTukeyWindow() adamstark@38: { adamstark@38: double N; // variable to store framesize minus 1 adamstark@38: double n_val; // double version of index 'n' adamstark@38: double alpha; // alpha [default value = 0.5]; adamstark@38: adamstark@38: alpha = 0.5; adamstark@38: adamstark@115: N = (double) (frameSize - 1); // framesize minus 1 adamstark@38: adamstark@38: // Tukey window calculation adamstark@38: adamstark@115: n_val = (double) (-1 * ((frameSize / 2))) + 1; adamstark@38: adamstark@115: for (int n = 0; n < frameSize; n++) // left taper adamstark@38: { adamstark@115: if ((n_val >= 0) && (n_val <= (alpha * (N / 2)))) adamstark@38: { adamstark@38: window[n] = 1.0; adamstark@38: } adamstark@115: else if ((n_val <= 0) && (n_val >= (-1 * alpha * (N / 2)))) adamstark@38: { adamstark@38: window[n] = 1.0; adamstark@38: } adamstark@38: else adamstark@38: { adamstark@115: window[n] = 0.5 * (1 + cos (pi * (((2 * n_val) / (alpha * N)) - 1))); adamstark@38: } adamstark@38: adamstark@115: n_val = n_val + 1; adamstark@38: } adamstark@38: adamstark@38: } adamstark@38: adamstark@52: //======================================================================= adamstark@92: void OnsetDetectionFunction::calculateRectangularWindow() adamstark@38: { adamstark@38: // Rectangular window calculation adamstark@115: for (int n = 0; n < frameSize; n++) adamstark@38: { adamstark@38: window[n] = 1.0; adamstark@38: } adamstark@38: } adamstark@38: adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: //////////////////////////////////////////////////////////////////////////////////////////////// adamstark@38: ///////////////////////////////// Other Handy Methods ////////////////////////////////////////// adamstark@38: adamstark@52: //======================================================================= adamstark@92: double OnsetDetectionFunction::princarg(double phaseVal) adamstark@38: { adamstark@38: // if phase value is less than or equal to -pi then add 2*pi adamstark@59: while (phaseVal <= (-pi)) adamstark@38: { adamstark@92: phaseVal = phaseVal + (2 * pi); adamstark@38: } adamstark@38: adamstark@38: // if phase value is larger than pi, then subtract 2*pi adamstark@59: while (phaseVal > pi) adamstark@38: { adamstark@92: phaseVal = phaseVal - (2 * pi); adamstark@38: } adamstark@38: adamstark@59: return phaseVal; adamstark@38: }