Mercurial > hg > precise-onset-detection
changeset 0:3dcbd77efc94
added files for OF project
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Fri, 21 Sep 2012 16:35:17 +0100 |
parents | |
children | 5a94f002e5ef |
files | src/PeakProcessor.cpp src/PeakProcessor.h src/PreciseOnsetLocator.cpp src/PreciseOnsetLocator.h src/btrack_plus/.DS_Store src/btrack_plus/OnsetDetectionFunction.cpp src/btrack_plus/OnsetDetectionFunction.h src/btrack_plus/accFFT.cpp src/btrack_plus/accFFT.h src/main.cpp src/testApp.cpp src/testApp.h |
diffstat | 12 files changed, 2017 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PeakProcessor.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,134 @@ +/* + * PeakProcessor.cpp + * peakOnsetDetector + * + * Created by Andrew on 07/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "PeakProcessor.h" + +PeakProcessor::PeakProcessor(){ + + recentDFsamples.assign(vectorSize, 0.0); + recentDFonsetFound.assign(vectorSize, false); + recentDFslopeValues.assign(vectorSize, 0.0); + + numberOfDetectionValuesToTest = 10; + currentFrame = 0; + cutoffForRepeatOnsetsFrames = 4; + detectionTriggerRatio = 0.5f; + detectionTriggerThreshold = 0.1; + bestSlopeMedian = 1; + thresholdRelativeToMedian = 1.1; + slopeFallenBelowMedian = true; + lastSlopeOnsetFrame = 0; +} + +PeakProcessor::~PeakProcessor(){ + + recentDFsamples.clear(); + recentDFonsetFound.clear(); + recentDFslopeValues.clear(); +} + + +bool PeakProcessor::peakProcessing(const double& newDFval){ + recentDFsamples.erase (recentDFsamples.begin(), recentDFsamples.begin()+1);//erase first val + recentDFsamples.push_back(newDFval); + + double slopeVal = getBestSlopeValue(newDFval); + + newOnsetFound = checkForSlopeOnset(slopeVal); + + + printf("slope %f median %f det median %f\n", slopeVal, bestSlopeMedian, detectionTriggerThreshold); + if (newOnsetFound){ + printf("BANG!\n"); + + } + + recentDFslopeValues.erase (recentDFslopeValues.begin(), recentDFslopeValues.begin()+1);//erase first val + recentDFslopeValues.push_back(slopeVal); + + recentDFonsetFound.erase (recentDFonsetFound.begin(), recentDFonsetFound.begin()+1);//erase first val + recentDFonsetFound.push_back(newOnsetFound); + + + //printf("\n"); + // for (int i = 0;i < recentDFsamples.size();i++){ + // printf("rdf[%i] %f\n", i, recentDFsamples[i]); + // } + //printf("SLOPE %f\n", slopeVal); + + return newOnsetFound; +} + + +double PeakProcessor::getBestSlopeValue(const float& dfvalue){ + + //the idea is we want a high slope + double bestValue = 0; + + for (int i = 1;i < min(numberOfDetectionValuesToTest, (int)recentDFsamples.size() - 1);i++){ + double angle = 0; + int otherIndex = recentDFsamples.size() - i + 1; + double testValue = 0; + + if (otherIndex > 0 && recentDFsamples[otherIndex] > 0 + && recentDFsamples[otherIndex] < dfvalue + ){ + angle = atan((float)(i * dfvalue)/ (numberOfDetectionValuesToTest*(dfvalue-recentDFsamples[otherIndex])) ); + testValue = (dfvalue - recentDFsamples[otherIndex]) * cos(angle); + } + + if (testValue > bestValue) + bestValue = testValue; + } + + return bestValue; + +} + + + +bool PeakProcessor :: checkForSlopeOnset(const float& bestValue){ + bool onsetDetected = false; + //check for onset relative to our processed slope function + //a mix between increase in value and the gradient of that increase + + currentFrame++; + + if (bestValue > bestSlopeMedian * thresholdRelativeToMedian && //better than recent average + (currentFrame - lastSlopeOnsetFrame) > cutoffForRepeatOnsetsFrames //after cutoff time + && slopeFallenBelowMedian // has had onset and fall away again + && bestValue > detectionTriggerThreshold * detectionTriggerRatio //longer term ratio of winning onsets + ){ + // printf("frame diff between onsets %6.1f", (1000*framesToSeconds(currentFrame - lastMedianOnsetFrame)) ); + onsetDetected = true; + lastSlopeOnsetFrame = currentFrame; + slopeFallenBelowMedian = false; + + updateDetectionTriggerThreshold(bestValue); + } + + + if (bestValue > bestSlopeMedian){ + bestSlopeMedian += (bestValue - bestSlopeMedian)*0.04;//was 1.1 + } + else{ + bestSlopeMedian *= 0.99; + slopeFallenBelowMedian = true;; + } + + //bestSlopeMedian += 0.02* (bestValue - bestSlopeMedian); + + return onsetDetected; +} + +void PeakProcessor :: updateDetectionTriggerThreshold(const float& val){ + float detectionAdaptSpeed = 0.05;//moving average, roughly last twenty onsets + detectionTriggerThreshold *= 1- detectionAdaptSpeed; + detectionTriggerThreshold += (val * detectionAdaptSpeed); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PeakProcessor.h Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,39 @@ +/* + * PeakProcessor.h + * peakOnsetDetector + * + * Created by Andrew on 07/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#ifndef PEAK_PROCESSOR +#define PEAK_PROCESSOR + +#include <vector.h> + +class PeakProcessor{ + public: + + PeakProcessor(); + ~PeakProcessor(); + //peak processing requires + static const int vectorSize = 512/6; + vector<double> recentDFsamples; + vector<bool> recentDFonsetFound; + vector<double> recentDFslopeValues; + + int numberOfDetectionValuesToTest; + bool peakProcessing(const double& newDFval); + double getBestSlopeValue(const float& dfvalue); + bool checkForSlopeOnset(const float& bestValue); + int currentFrame, lastSlopeOnsetFrame, cutoffForRepeatOnsetsFrames; + void updateDetectionTriggerThreshold(const float& val); + float detectionTriggerThreshold, detectionTriggerRatio; + float bestSlopeMedian, thresholdRelativeToMedian; + bool newOnsetFound, slopeFallenBelowMedian; + + + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PreciseOnsetLocator.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,108 @@ +/* + * PreciseOnsetLocator.cpp + * peakOnsetDetector + * + * Created by Andrew on 21/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "PreciseOnsetLocator.h" + +PreciseOnsetLocator::PreciseOnsetLocator(){ + setup(512); +} + +PreciseOnsetLocator::~PreciseOnsetLocator(){ + onsetSamples.clear(); + recentBufferSamples.clear(); +} + + +void PreciseOnsetLocator::setup(const int& size){ + onsetSamples.clear(); + recentBufferSamples.clear(); + bufferSize = size; + onsetSamples.assign(bufferSize, 0.0); + recentBufferSamples.assign(bufferSize, 0.0); +} + +void PreciseOnsetLocator::storeSamples(double* newSamples){ + + for (int i = 0;i < bufferSize;i++) + recentBufferSamples[i] = newSamples[i]; + +} + +int PreciseOnsetLocator::findExactOnset(double* frame){ + //store the samples - mainly for viewing actually + onsetSamples.clear(); + for (int i = 0; i < bufferSize;i++) { + onsetSamples.push_back(frame[i]); + } + + double energySum = 0; + double lastEnergySum, hopsizeLastEnergySum; + double energyDifference; + int bestEnergyIndex = 0; + double bestEnergyDifference = 0; + int endIndex = bufferSize; + int hopSize; + + for (int resolution = bufferSize/2;resolution > 1;resolution/=2){ + printf("resolution %i\n", resolution); + + bestEnergyDifference = 0; + // printf("previous energy %f", lastEnergySum); + //initialise last energySum + hopSize = resolution/2; + + + lastEnergySum = getLastEnergySum(bestEnergyIndex, resolution); + hopsizeLastEnergySum = getLastEnergySum(bestEnergyIndex + hopSize, resolution); + + for (int startIndex = bestEnergyIndex;startIndex + resolution <= endIndex;startIndex += hopSize){ + printf("index %i last energy %f hop energy %f ", startIndex, lastEnergySum, hopsizeLastEnergySum); + + //sum the energy for this new frame + energySum = 0; + for (int i = 0;i < resolution;i++){ + energySum += onsetSamples[startIndex + i] * onsetSamples[startIndex + i]; + } + + printf("energysum %f\n", energySum); + //check if new max difference + energyDifference = energySum - lastEnergySum; + if (energyDifference > bestEnergyDifference){ + bestEnergyDifference = energyDifference; + bestEnergyIndex = startIndex; + } + + //store the values for checking in two loops time (because proceeding at resolution/2 each step) + //eg 0_to_128 compared to -128_to_0, 64_to_196 compared to -64_to_64, then 128_256 compared with 0_to_128, + lastEnergySum = hopsizeLastEnergySum;// energySum; + hopsizeLastEnergySum = energySum; + + } + printf("winning index is %i\n", bestEnergyIndex); + endIndex = bestEnergyIndex + resolution; + + } + printf("TOTAL WINNER %i\n", bestEnergyIndex); + return bestEnergyIndex; + +} + +double PreciseOnsetLocator::getLastEnergySum(const int& startIndex, const int& vectorSize){ + double lastEnergySum = 0; + + for (int i = startIndex - vectorSize;i < startIndex;i++){ + if (i > 0) + lastEnergySum += onsetSamples[i] * onsetSamples[i]; + else { + lastEnergySum += recentBufferSamples[bufferSize + i] * recentBufferSamples[bufferSize + i]; + } + } + return lastEnergySum; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PreciseOnsetLocator.h Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,36 @@ +/* + * PreciseOnsetLocator.h + * peakOnsetDetector + * + * Created by Andrew on 21/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + + +#ifndef PRECISE_ONSET_LOCATOR +#define PRECISE_ONSET_LOCATOR + +#include <vector.h> + +class PreciseOnsetLocator{ + public: + + PreciseOnsetLocator(); + ~PreciseOnsetLocator(); + + int bufferSize; + + vector <double> onsetSamples;//holds the audio samples when onset is found + vector <double> recentBufferSamples; + + double getLastEnergySum(const int& startIndex, const int& vectorSize); + int findExactOnset(double* frame); + + int exactOnsetIndex; + + void setup(const int& size); + void storeSamples(double* newSamples); + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/btrack_plus/OnsetDetectionFunction.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,826 @@ +/* + * OnsetDetectionFunction.cpp + * + * + * Created by Adam Stark on 22/03/2011. + * Copyright 2011 Queen Mary University of London. All rights reserved. + * + */ + +#include <math.h> +#include <iostream> +#include "OnsetDetectionFunction.h" +#include "accFFT.h" +using namespace std; + +//------------------------------------------------------------------------------- +// Constructor +OnsetDetectionFunction :: OnsetDetectionFunction() +{ + // indicate that we have not initialised yet + initialised = 0; + + // set pi + pi = 3.14159265358979; + + // initialise with hopsize = 512, framesize = 1024, complex spectral difference DF and hanning window + initialise(512,1024,6,1); +} + + +//------------------------------------------------------------------------------- +// Constructor (with arguments) +OnsetDetectionFunction :: OnsetDetectionFunction(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type) +{ + // indicate that we have not initialised yet + initialised = 0; + + // set pi + pi = 3.14159265358979; + + // initialise with arguments to constructor + initialise(arg_hsize,arg_fsize,arg_df_type,arg_win_type); +} + + +//-------------------------------------------------------------------------------------- +// Destructor +OnsetDetectionFunction :: ~OnsetDetectionFunction() +{ + // destroy fft plan + //fftw_destroy_plan(p); + //fftw_free(in); + //fftw_free(out); + + fft->~accFFT(); + delete [] in; + in = NULL; + delete [] out; + out = NULL; + + + + // deallocate memory + delete [] frame; + frame = NULL; + delete [] window; + window = NULL; + delete [] wframe; + wframe = NULL; + delete [] mag; + mag = NULL; + delete [] mag_old; + mag_old = NULL; + delete [] phase; + phase = NULL; + delete [] phase_old; + phase_old = NULL; + delete [] phase_old_2; + phase_old_2 = NULL; +} + +//------------------------------------------------------------------------------- +// Initialisation +void OnsetDetectionFunction :: initialise(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type) +{ + if (initialised == 1) // if we have already initialised some buffers and an FFT plan + { + ////////////////////////////////// + // TIDY UP FIRST - If initialise is called after the class has been initialised + // then we want to free up memory and cancel existing FFT plans + + // destroy fft plan + //fftw_destroy_plan(p); + //fftw_free(in); + //fftw_free(out); + + fft->~accFFT(); + delete [] in; + in = NULL; + delete [] out; + out = NULL; + + + // deallocate memory + delete [] frame; + frame = NULL; + delete [] window; + window = NULL; + delete [] wframe; + wframe = NULL; + delete [] mag; + mag = NULL; + delete [] mag_old; + mag_old = NULL; + delete [] phase; + phase = NULL; + delete [] phase_old; + phase_old = NULL; + delete [] phase_old_2; + phase_old_2 = NULL; + + ////// END TIDY UP /////////////// + ////////////////////////////////// + } + + hopsize = arg_hsize; // set hopsize + framesize = arg_fsize; // set framesize + + df_type = arg_df_type; // set detection function type + + // initialise buffers + frame = new double[framesize]; + window = new double[framesize]; + wframe = new double[framesize]; + + mag = new double[framesize]; + mag_old = new double[framesize]; + + phase = new double[framesize]; + phase_old = new double[framesize]; + phase_old_2 = new double[framesize]; + + + // set the window to the specified type + switch (arg_win_type){ + case 0: + set_win_rectangular(); // Rectangular window + break; + case 1: + set_win_hanning(); // Hanning Window + break; + case 2: + set_win_hamming(); // Hamming Window + break; + case 3: + set_win_blackman(); // Blackman Window + break; + case 4: + set_win_tukey(); // Tukey Window + break; + default: + set_win_hanning(); // DEFAULT: Hanning Window + } + + + + + // initialise previous magnitude spectrum to zero + for (int i = 0;i < framesize;i++) + { + mag_old[i] = 0.0; + phase_old[i] = 0.0; + phase_old_2[i] = 0.0; + frame[i] = 0.0; + } + + energy_sum_old = 0.0; // initialise previous energy sum value to zero + + /* Init fft */ + //in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * framesize); // complex array to hold fft data + //out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * framesize); // complex array to hold fft data + //p = fftw_plan_dft_1d(framesize, in, out, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation + + in = new double[framesize]; + out = new fft_complex[framesize]; + + //out = new double[2][framesize]; + fft = new accFFT(framesize,1); + + initialised = 1; +} + +//-------------------------------------------------------------------------------------- +// set the detection function type to that specified by the argument +void OnsetDetectionFunction :: set_df_type(int arg_df_type) +{ + df_type = arg_df_type; // set detection function type +} + + +//-------------------------------------------------------------------------------------- +// calculates a single detection function sample from a single audio frame. +double OnsetDetectionFunction :: getDFsample(double inputbuffer[]) +{ + double df_sample; + + // shift audio samples back in frame by hop size + for (int i = 0; i < (framesize-hopsize);i++) + { + frame[i] = frame[i+hopsize]; + } + + // add new samples to frame from input buffer + int j = 0; + for (int i = (framesize-hopsize);i < framesize;i++) + { + frame[i] = inputbuffer[j]; + j++; + } + + switch (df_type){ + case 0: + df_sample = energy_envelope(); // calculate energy envelope detection function sample + break; + case 1: + df_sample = energy_difference(); // calculate half-wave rectified energy difference detection function sample + break; + case 2: + df_sample = spectral_difference(); // calculate spectral difference detection function sample + break; + case 3: + df_sample = spectral_difference_hwr(); // calculate spectral difference detection function sample (half wave rectified) + break; + case 4: + df_sample = phase_deviation(); // calculate phase deviation detection function sample (half wave rectified) + break; + case 5: + df_sample = complex_spectral_difference(); // calcualte complex spectral difference detection function sample + break; + case 6: + df_sample = complex_spectral_difference_hwr(); // calcualte complex spectral difference detection function sample (half-wave rectified) + break; + case 7: + df_sample = high_frequency_content(); // calculate high frequency content detection function sample + break; + case 8: + df_sample = high_frequency_spectral_difference(); // calculate high frequency spectral difference detection function sample + break; + case 9: + df_sample = high_frequency_spectral_difference_hwr(); // calculate high frequency spectral difference detection function (half-wave rectified) + break; + default: + df_sample = 1.0; + } + + return df_sample; +} + + +//-------------------------------------------------------------------------------------- +// performs the fft, storing the complex result in 'out' +void OnsetDetectionFunction :: perform_FFT() +{ + int fsize2 = (framesize/2); + + + // window frame + //for (int i = 0;i < fsize2;i++) + for (int i = 0;i < framesize;i++) + { + in[i] = frame[i]*window[i]; + + //in[i] = frame[i+fsize2]*window[i+fsize2]; + //in[i+fsize2] = frame[i] * window[i]; + + /* + in[i][0] = frame[i+fsize2] * window[i+fsize2]; + in[i][1] = 0.0; + in[i+fsize2][0] = frame[i] * window[i]; + in[i+fsize2][1] = 0.0; + */ + } + + // perform the fft + //fftw_execute(p); + + // FIX + fft->forward_FFT_d(in,out); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////// Methods for Detection Functions ///////////////////////////////// + +//-------------------------------------------------------------------------------------- +// calculates an energy envelope detection function sample +double OnsetDetectionFunction :: energy_envelope() +{ + double sum; + + sum = 0; // initialise sum + + // sum the squares of the samples + for (int i = 0;i < framesize;i++) + { + sum = sum + (frame[i]*frame[i]); + } + + return sum; // return sum +} + +//-------------------------------------------------------------------------------------- +// calculates a half-wave rectified energy difference detection function sample +double OnsetDetectionFunction :: energy_difference() +{ + double sum; + double sample; + + sum = 0; // initialise sum + + // sum the squares of the samples + for (int i = 0;i < framesize;i++) + { + sum = sum + (frame[i]*frame[i]); + } + + sample = sum - energy_sum_old; // sample is first order difference in energy + + energy_sum_old = sum; // store energy value for next calculation + + if (sample > 0) + { + return sample; // return difference + } + else + { + return 0; + } +} + +//-------------------------------------------------------------------------------------- +// calculates a spectral difference detection function sample +double OnsetDetectionFunction :: spectral_difference() +{ + double diff; + double sum; + + // perform the FFT + perform_FFT(); + + // compute first (N/2)+1 mag values + for (int i = 0;i < (framesize/2)+1;i++) + { + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + } + // mag spec symmetric above (N/2)+1 so copy previous values + for (int i = (framesize/2)+1;i < framesize;i++) + { + mag[i] = mag[framesize-i]; + } + + sum = 0; // initialise sum to zero + + for (int i = 0;i < framesize;i++) + { + // calculate difference + diff = mag[i] - mag_old[i]; + + // ensure all difference values are positive + if (diff < 0) + { + diff = diff*-1; + } + + // add difference to sum + sum = sum+diff; + + // store magnitude spectrum bin for next detection function sample calculation + mag_old[i] = mag[i]; + } + + return sum; +} + +//-------------------------------------------------------------------------------------- +// calculates a spectral difference detection function sample +double OnsetDetectionFunction :: spectral_difference_hwr() +{ + double diff; + double sum; + + // perform the FFT + perform_FFT(); + + // compute first (N/2)+1 mag values + for (int i = 0;i < (framesize/2)+1;i++) + { + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + } + // mag spec symmetric above (N/2)+1 so copy previous values + for (int i = (framesize/2)+1;i < framesize;i++) + { + mag[i] = mag[framesize-i]; + } + + sum = 0; // initialise sum to zero + + for (int i = 0;i < framesize;i++) + { + // calculate difference + diff = mag[i] - mag_old[i]; + + // only add up positive differences + if (diff > 0) + { + // add difference to sum + sum = sum+diff; + } + + + + // store magnitude spectrum bin for next detection function sample calculation + mag_old[i] = mag[i]; + } + + return sum; +} + + +//-------------------------------------------------------------------------------------- +// calculates a phase deviation detection function sample +double OnsetDetectionFunction :: phase_deviation() +{ + double dev,pdev; + double sum; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate phase value + phase[i] = atan2(out[i][1],out[i][0]); + + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + + // if bin is not just a low energy bin then examine phase deviation + if (mag[i] > 0.1) + { + dev = phase[i] - (2*phase_old[i]) + phase_old_2[i]; // phase deviation + pdev = princarg(dev); // wrap into [-pi,pi] range + + // make all values positive + if (pdev < 0) + { + pdev = pdev*-1; + } + + // add to sum + sum = sum + pdev; + } + + // store values for next calculation + phase_old_2[i] = phase_old[i]; + phase_old[i] = phase[i]; + } + + return sum; +} + +//-------------------------------------------------------------------------------------- +// calculates a complex spectral difference detection function sample +double OnsetDetectionFunction :: complex_spectral_difference() +{ + double dev,pdev; + double sum; + double mag_diff,phase_diff; + double value; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate phase value + phase[i] = atan2(out[i][1],out[i][0]); + + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + + // phase deviation + dev = phase[i] - (2*phase_old[i]) + phase_old_2[i]; + + // wrap into [-pi,pi] range + pdev = princarg(dev); + + + // calculate magnitude difference (real part of Euclidean distance between complex frames) + mag_diff = mag[i] - mag_old[i]; + + // calculate phase difference (imaginary part of Euclidean distance between complex frames) + phase_diff = -mag[i]*sin(pdev); + + + + // square real and imaginary parts, sum and take square root + value = sqrt(pow(mag_diff,2) + pow(phase_diff,2)); + + + // add to sum + sum = sum + value; + + + // store values for next calculation + phase_old_2[i] = phase_old[i]; + phase_old[i] = phase[i]; + mag_old[i] = mag[i]; + } + + return sum; +} + +//-------------------------------------------------------------------------------------- +// calculates a complex spectral difference detection function sample (half-wave rectified) +double OnsetDetectionFunction :: complex_spectral_difference_hwr() +{ + double dev,pdev; + double sum; + double mag_diff,phase_diff; + double value; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate phase value + phase[i] = atan2(out[i][1],out[i][0]); + + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + + // phase deviation + dev = phase[i] - (2*phase_old[i]) + phase_old_2[i]; + + // wrap into [-pi,pi] range + pdev = princarg(dev); + + + // calculate magnitude difference (real part of Euclidean distance between complex frames) + mag_diff = mag[i] - mag_old[i]; + + // if we have a positive change in magnitude, then include in sum, otherwise ignore (half-wave rectification) + if (mag_diff > 0) + { + // calculate phase difference (imaginary part of Euclidean distance between complex frames) + phase_diff = -mag[i]*sin(pdev); + + // square real and imaginary parts, sum and take square root + value = sqrt(pow(mag_diff,2) + pow(phase_diff,2)); + + // add to sum + sum = sum + value; + } + + // store values for next calculation + phase_old_2[i] = phase_old[i]; + phase_old[i] = phase[i]; + mag_old[i] = mag[i]; + } + + return sum; +} + + +//-------------------------------------------------------------------------------------- +// calculates a high frequency content detection function sample +double OnsetDetectionFunction :: high_frequency_content() +{ + double sum; + double mag_diff; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + + sum = sum + (mag[i]*((double) (i+1))); + + // store values for next calculation + mag_old[i] = mag[i]; + } + + return sum; +} + +//-------------------------------------------------------------------------------------- +// calculates a high frequency spectral difference detection function sample +double OnsetDetectionFunction :: high_frequency_spectral_difference() +{ + double sum; + double mag_diff; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + // calculate difference + mag_diff = mag[i] - mag_old[i]; + + if (mag_diff < 0) + { + mag_diff = -mag_diff; + } + + sum = sum + (mag_diff*((double) (i+1))); + + // store values for next calculation + mag_old[i] = mag[i]; + } + + return sum; +} + +//-------------------------------------------------------------------------------------- +// calculates a high frequency spectral difference detection function sample (half-wave rectified) +double OnsetDetectionFunction :: high_frequency_spectral_difference_hwr() +{ + double sum; + double mag_diff; + + // perform the FFT + perform_FFT(); + + sum = 0; // initialise sum to zero + + // compute phase values from fft output and sum deviations + for (int i = 0;i < framesize;i++) + { + // calculate magnitude value + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + + // calculate difference + mag_diff = mag[i] - mag_old[i]; + + if (mag_diff > 0) + { + sum = sum + (mag_diff*((double) (i+1))); + } + + // store values for next calculation + mag_old[i] = mag[i]; + } + + return sum; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////// Methods to Calculate Windows //////////////////////////////////// + +//-------------------------------------------------------------------------------------- +// HANNING: set the window in the buffer 'window' to a Hanning window +void OnsetDetectionFunction :: set_win_hanning() +{ + double N; // variable to store framesize minus 1 + + N = (double) (framesize-1); // framesize minus 1 + + // Hanning window calculation + for (int n = 0;n < framesize;n++) + { + window[n] = 0.5*(1-cos(2*pi*(n/N))); + } +} + +//-------------------------------------------------------------------------------------- +// HAMMING: set the window in the buffer 'window' to a Hanning window +void OnsetDetectionFunction :: set_win_hamming() +{ + double N; // variable to store framesize minus 1 + double n_val; // double version of index 'n' + + N = (double) (framesize-1); // framesize minus 1 + n_val = 0; + + // Hamming window calculation + for (int n = 0;n < framesize;n++) + { + window[n] = 0.54 - (0.46*cos(2*pi*(n_val/N))); + n_val = n_val+1; + } +} + +//-------------------------------------------------------------------------------------- +// BLACKMAN: set the window in the buffer 'window' to a Blackman window +void OnsetDetectionFunction :: set_win_blackman() +{ + double N; // variable to store framesize minus 1 + double n_val; // double version of index 'n' + + N = (double) (framesize-1); // framesize minus 1 + n_val = 0; + + // Blackman window calculation + for (int n = 0;n < framesize;n++) + { + window[n] = 0.42 - (0.5*cos(2*pi*(n_val/N))) + (0.08*cos(4*pi*(n_val/N))); + n_val = n_val+1; + } +} + +//-------------------------------------------------------------------------------------- +// TUKEY: set the window in the buffer 'window' to a Tukey window +void OnsetDetectionFunction :: set_win_tukey() +{ + double N; // variable to store framesize minus 1 + double n_val; // double version of index 'n' + double alpha; // alpha [default value = 0.5]; + + int lim1,lim2; + + alpha = 0.5; + + N = (double) (framesize-1); // framesize minus 1 + + // Tukey window calculation + + n_val = (double) (-1*((framesize/2)))+1; + + for (int n = 0;n < framesize;n++) // left taper + { + if ((n_val >= 0) && (n_val <= (alpha*(N/2)))) + { + window[n] = 1.0; + } + else if ((n_val <= 0) && (n_val >= (-1*alpha*(N/2)))) + { + window[n] = 1.0; + } + else + { + window[n] = 0.5*(1+cos(pi*(((2*n_val)/(alpha*N))-1))); + } + + n_val = n_val+1; + } + +} + +//-------------------------------------------------------------------------------------- +// RECTANGULAR: set the window in the buffer 'window' to a Rectangular window +void OnsetDetectionFunction :: set_win_rectangular() +{ + // Rectangular window calculation + for (int n = 0;n < framesize;n++) + { + window[n] = 1.0; + } +} + + + +//////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////// Other Handy Methods ////////////////////////////////////////// + +//-------------------------------------------------------------------------------------- +// set phase values to the range [-pi,pi] +double OnsetDetectionFunction :: princarg(double phaseval) +{ + // if phase value is less than or equal to -pi then add 2*pi + while (phaseval <= (-pi)) + { + phaseval = phaseval + (2*pi); + } + + // if phase value is larger than pi, then subtract 2*pi + while (phaseval > pi) + { + phaseval = phaseval - (2*pi); + } + + return phaseval; +} + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/btrack_plus/OnsetDetectionFunction.h Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,88 @@ +/* + * OnsetDetectionFunction.h + * + * + * Created by Adam Stark on 22/03/2011. + * Copyright 2011 Queen Mary University of London. All rights reserved. + * + */ + +#ifndef __RTONSETDF_H +#define __RTONSETDF_H + +//#include "fftw3.h" +#include "accFFT.h" + +typedef double fft_complex[2]; + +class OnsetDetectionFunction +{ +public: + OnsetDetectionFunction(); // Constructor + OnsetDetectionFunction(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type); // Constructor (with arguments) + ~OnsetDetectionFunction(); // Destructor + void initialise(int arg_hsize,int arg_fsize,int arg_df_type,int arg_win_type); // Initialisation Function + + double getDFsample(double inputbuffer[]); // process input buffer and calculate detection function sample + void set_df_type(int arg_df_type); // set the detection function type + +private: + + void perform_FFT(); // perform the FFT on the data in 'frame' + + double energy_envelope(); // calculate energy envelope detection function sample + double energy_difference(); // calculate energy difference detection function sample + double spectral_difference(); // calculate spectral difference detection function sample + double spectral_difference_hwr(); // calculate spectral difference (half wave rectified) detection function sample + double phase_deviation(); // calculate phase deviation detection function sample + double complex_spectral_difference(); // calculate complex spectral difference detection function sample + double complex_spectral_difference_hwr(); // calculate complex spectral difference detection function sample (half-wave rectified) + double high_frequency_content(); // calculate high frequency content detection function sample + double high_frequency_spectral_difference(); // calculate high frequency spectral difference detection function sample + double high_frequency_spectral_difference_hwr(); // calculate high frequency spectral difference detection function sample (half-wave rectified) + + void set_win_rectangular(); // calculate a Rectangular window + void set_win_hanning(); // calculate a Hanning window + void set_win_hamming(); // calculate a Hamming window + void set_win_blackman(); // calculate a Blackman window + void set_win_tukey(); // calculate a Tukey window + + + double princarg(double phaseval); // set phase values between [-pi, pi] + + + double pi; // pi, the constant + + int framesize; // audio framesize + int hopsize; // audio hopsize + int df_type; // type of detection function + + accFFT *fft; + fft_complex *out; + double *in; + + //fftw_plan p; // create fft plan + //fftw_complex *in; // to hold complex fft values for input + //fftw_complex *out; // to hold complex fft values for output + + + int initialised; // flag indicating whether buffers and FFT plans have been initialised + + + double *frame; // audio frame + double *window; // window + double *wframe; // windowed frame + + double energy_sum_old; // to hold the previous energy sum value + + double *mag; // magnitude spectrum + double *mag_old; // previous magnitude spectrum + + double *phase; // FFT phase values + double *phase_old; // previous phase values + double *phase_old_2; // second order previous phase values + +}; + + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/btrack_plus/accFFT.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,140 @@ +// +// accFFT.cpp +// AccelerateFFTtool +// +// Created by Adam Stark on 17/07/2012. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#include "accFFT.h" + + +accFFT :: accFFT(int fft_size,int type) +{ + fft_type = type; + + fftSize = fft_size; + fftSizeOver2 = fftSize/2; + log2n = log2f(fftSize); + log2nOver2 = log2n/2; + + if (fft_type == 0) + { + split.realp = (float *) malloc(fftSize * sizeof(float)); + split.imagp = (float *) malloc(fftSize * sizeof(float)); + + // allocate the fft object once + fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2); + if (fftSetup == NULL) { + //printf("FFT Setup failed\n"); + } + } + else if (fft_type == 1) + { + d_split.realp = (double *) malloc(fftSize * sizeof(double)); + d_split.imagp = (double *) malloc(fftSize * sizeof(double)); + + // allocate the fft object once + fftSetupD = vDSP_create_fftsetupD(log2n, FFT_RADIX2); + if (fftSetupD == NULL) { + //printf("FFT Setup failed\n"); + } + } + + + +} + +accFFT :: ~accFFT() +{ + if (fft_type == 0) + { + free(split.realp); + free(split.imagp); + vDSP_destroy_fftsetup(fftSetup); + } + else if (fft_type == 1) + { + free(d_split.realp); + free(d_split.imagp); + vDSP_destroy_fftsetupD(fftSetupD); + } + + +} + +void accFFT :: forward_FFT_f(float *buffer,float *real,float *imag) +{ + //convert to split complex format with evens in real and odds in imag + vDSP_ctoz((COMPLEX *) buffer, 2, &split, 1, fftSizeOver2); + + //calc fft + vDSP_fft_zrip(fftSetup, &split, 1, log2n, FFT_FORWARD); + + // set Nyquist component to imaginary of 0 component + split.realp[fftSizeOver2] = split.imagp[0]; + split.imagp[fftSizeOver2] = 0.0; + + // set 0 component to zero + split.imagp[0] = 0.0; + + // multiply by 0.5 to get correct output (to do with Apple's FFT implementation) + for (i = 0; i <= fftSizeOver2; i++) + { + split.realp[i] *= 0.5; + split.imagp[i] *= 0.5; + } + + // set values above N/2+1 which are complex conjugate mirror image of those below + for (i = fftSizeOver2 - 1;i > 0;--i) + { + split.realp[2*fftSizeOver2 - i] = split.realp[i]; + split.imagp[2*fftSizeOver2 - i] = -1*split.imagp[i]; + + //cout << split_data.realp[2*fftSizeOver2 - i] << " " << split_data.imagp[2*fftSizeOver2 - i] << "i" << endl; + } + + for (i = 0;i < fftSize;i++) + { + real[i] = split.realp[i]; + imag[i] = split.imagp[i]; + } +} + + + +void accFFT :: forward_FFT_d(double *buffer,fft_complex *out) +{ + //convert to split complex format with evens in real and odds in imag + vDSP_ctozD((DOUBLE_COMPLEX *) buffer, 2, &d_split, 1, fftSizeOver2); + + //calc fft + vDSP_fft_zripD(fftSetupD, &d_split, 1, log2n, FFT_FORWARD); + + // set Nyquist component to imaginary of 0 component + d_split.realp[fftSizeOver2] = d_split.imagp[0]; + d_split.imagp[fftSizeOver2] = 0.0; + + // set 0 component to zero + d_split.imagp[0] = 0.0; + + // multiply by 0.5 to get correct output (to do with Apple's FFT implementation) + for (i = 0; i <= fftSizeOver2; i++) + { + d_split.realp[i] *= 0.5; + d_split.imagp[i] *= 0.5; + } + + // set values above N/2+1 which are complex conjugate mirror image of those below + for (i = fftSizeOver2 - 1;i > 0;--i) + { + d_split.realp[2*fftSizeOver2 - i] = d_split.realp[i]; + d_split.imagp[2*fftSizeOver2 - i] = -1*d_split.imagp[i]; + } + + for (i = 0;i < fftSize;i++) + { + out[i][0] = d_split.realp[i]; + out[i][1] = d_split.imagp[i]; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/btrack_plus/accFFT.h Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,41 @@ +// +// accFFT.h +// AccelerateFFTtool +// +// Created by Adam Stark on 17/07/2012. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#ifndef AccelerateFFTtool_accFFT_h +#define AccelerateFFTtool_accFFT_h + +#include <Accelerate/Accelerate.h> + +typedef double fft_complex[2]; + +class accFFT { +public: + accFFT(int fft_size,int type); // constructor + ~accFFT(); // destructor + void forward_FFT_f(float *buffer,float *real,float *imag); // forward fft (float) + void forward_FFT_d(double *buffer,fft_complex *out); // forward fft (double) + + + +private: + size_t fftSize; + size_t fftSizeOver2; + size_t log2n; + size_t log2nOver2; + size_t i; + + FFTSetup fftSetup; + FFTSetupD fftSetupD; + COMPLEX_SPLIT split; + DOUBLE_COMPLEX_SPLIT d_split; + + int fft_type; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "testApp.h" +#include "ofAppGlutWindow.h" + +//======================================================================== +int main( ){ + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp( new testApp()); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.cpp Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,505 @@ +#include "testApp.h" + + +//-------------------------------------------------------------- +void testApp::setup(){ + + ofSetVerticalSync(true); + ofSetCircleResolution(80); + ofBackground(54, 54, 54); + + // 0 output channels, + // 2 input channels + // 44100 samples per second + // 256 samples per buffer + // 4 num buffers (latency) + + soundStream.listDevices(); + soundStream.setDeviceID(0);//this now uses the audio input rather than mic input for mac + //outputStream.setDeviceID(1); + + //if you want to set a different device id + //soundStream.setDeviceID(0); //bear in mind the device id corresponds to all audio devices, including input-only and output-only devices. + + bufferSize = 512; + + left.assign(bufferSize, 0.0); + right.assign(bufferSize, 0.0); + volHistory.assign(400, 0.0); + + bufferCounter = 0; + drawCounter = 0; + smoothedVol = 0.0; + scaledVol = 0.0; + + soundStream.setup(this, 0, 2, 44100, bufferSize, 4); + + //peak analysis + onsetSamples.assign(bufferSize, 0.0); +// recentBufferSamples.assign(bufferSize, 0.0); + holdOn = false; + exactOnsetIndex = 0; + + precisionLocator.setup(bufferSize); + +} + +//-------------------------------------------------------------- +void testApp::update(){ + //lets scale the vol up to a 0-1 range + scaledVol = ofMap(smoothedVol, 0.0, 0.17, 0.0, 1.0, true); + + //lets record the volume into an array + volHistory.push_back( scaledVol ); + + //if we are bigger the the size we want to record - lets drop the oldest value + if( volHistory.size() >= 400 ){ + volHistory.erase(volHistory.begin(), volHistory.begin()+1); + } +} + +//-------------------------------------------------------------- +void testApp::draw(){ + + ofSetColor(225); + ofDrawBitmapString("AUDIO INPUT EXAMPLE " + ofToString(exactOnsetIndex), 32, 32); + ofDrawBitmapString("press 's' to unpause the audio\n'e' to pause the audio", 31, 92); + + ofNoFill(); + + // draw the left channel: + ofPushStyle(); + ofPushMatrix(); + ofTranslate(32, 120, 0); + + ofSetColor(225); + ofDrawBitmapString("Left Channel", 4, 18); + + ofSetLineWidth(1); + ofRect(0, 0, 512, 200); + + ofSetColor(245, 58, 135); + ofSetLineWidth(3); + + ofBeginShape(); + for (int i = 0; i < left.size(); i++){ + ofVertex(i, 100 -left[i]*180.0f); + } + ofEndShape(false); + + ofPopMatrix(); + ofPopStyle(); + + // draw the right channel: + ofPushStyle(); + ofPushMatrix(); + ofTranslate(32, 320, 0); + + ofSetColor(225); + ofDrawBitmapString("Onset DF function", 4, 18); + + ofSetLineWidth(1); + ofRect(0, 0, 512, 200); + + ofSetColor(245, 58, 135); + ofSetLineWidth(3); + + ofBeginShape(); + for (int i = 0; i < peakProcess.recentDFsamples.size(); i++){ + int height = 100 - peakProcess.recentDFsamples[i]*10; + ofVertex(i*6, height); + // if (recentDFonsetFound[i]){ + // ofCircle(32+i*6, 376+height , 10); + // } +// ofVertex(i*2, 100 -right[i]*180.0f); + } + ofEndShape(false); + + ofPopMatrix(); + ofPopStyle(); + + //slope values + ofPushStyle(); + ofPushMatrix(); + ofTranslate(32, 320, 0); + + ofSetLineWidth(1); + + ofSetColor(25, 124, 235); + ofSetLineWidth(3); + + ofBeginShape(); + for (int i = 0; i < peakProcess.recentDFsamples.size(); i++){ + int height = 100 - peakProcess.recentDFslopeValues[i]*10; + ofVertex(i*6, height); + + } + ofEndShape(false); + + ofPopMatrix(); + ofPopStyle(); + + + //ONSETS + ofPushStyle(); + ofPushMatrix(); + ofTranslate(32, 320, 0); + + ofSetColor(25, 224, 135); + ofSetLineWidth(3); + + ofBeginShape(); + for (int i = 0; i < peakProcess.recentDFsamples.size(); i++){ + if (peakProcess.recentDFonsetFound[i]) + ofVertex(i*6, 0); + else { + ofVertex(i*6, 100); + } + } + ofEndShape(false); + + ofPopMatrix(); + ofPopStyle(); + + //ONSET Samples + ofPushStyle(); + ofPushMatrix(); + ofTranslate(32, 520, 0); + + ofSetColor(245, 224, 235); + ofSetLineWidth(3); + + ofBeginShape(); + for (int i = 0; i < precisionLocator.onsetSamples.size(); i++){ + int height = 100 + 100 * precisionLocator.onsetSamples[i]; + ofVertex(i, height); + } + ofEndShape(false); + + ofSetColor(240,0,0); + ofLine(exactOnsetIndex, 0, exactOnsetIndex, 200);//stripe where on + + ofPopMatrix(); + ofPopStyle(); + + + // draw the average volume: + ofPushStyle(); + ofPushMatrix(); + ofTranslate(565, 120, 0); + + ofSetColor(225); + ofDrawBitmapString("Scaled average vol (0-100): " + ofToString(scaledVol * 100.0, 0), 4, 18); + ofRect(0, 0, 400, 400); + + ofSetColor(245, 58, 135); + ofFill(); + ofCircle(200, 200, scaledVol * 190.0f); + + //lets draw the volume history as a graph + ofBeginShape(); + for (int i = 0; i < volHistory.size(); i++){ + if( i == 0 ) ofVertex(i, 400); + + ofVertex(i, 400 - volHistory[i] * 70); + + if( i == volHistory.size() -1 ) ofVertex(i, 400); + } + ofEndShape(false); + + ofPopMatrix(); + ofPopStyle(); + + drawCounter++; + + ofSetColor(225); + string reportString = "buffers received: "+ofToString(bufferCounter)+"\ndraw routines called: "+ofToString(drawCounter)+"\nticks: " + ofToString(soundStream.getTickCount()); + ofDrawBitmapString(reportString, 32, 89); + + + if (peakProcess.newOnsetFound){ + ofSetColor(255,0,0); + ofCircle(200,200,200); + } +} + +//-------------------------------------------------------------- +void testApp::audioIn(float * input, int bufferSize, int nChannels){ + + float curVol = 0.0; + + // samples are "interleaved" + int numCounted = 0; + + double frame[bufferSize]; + + for (int i = 0;i < bufferSize;i++){ + frame[i] = (double) input[i*2]; + } + + double df_sample = (float) odf.getDFsample(frame); + + bool peakFound = peakProcess.peakProcessing(df_sample);//our new fn to look for DF onset events + + //when we find a peak, we get the precise location of it + if (peakFound && !holdOn){ + exactOnsetIndex = precisionLocator.findExactOnset(&frame[0]); + } + + //need to store these continually to help in location process + precisionLocator.storeSamples(&frame[0]); + + + //lets go through each sample and calculate the root mean square which is a rough way to calculate volume + for (int i = 0; i < bufferSize; i++){ + + //recentBufferSamples[i] = frame[i];//store the last buffer in case needed for exact onset detection + + + + + left[i] = input[i*2]*0.5; + right[i] = input[i*2+1]*0.5; + + curVol += left[i] * left[i]; + curVol += right[i] * right[i]; + numCounted+=2; + + } + + //this is how we get the mean of rms :) + curVol /= (float)numCounted; + + // this is how we get the root of rms :) + curVol = sqrt( curVol ); + + smoothedVol *= 0.93; + smoothedVol += 0.07 * curVol; + + bufferCounter++; + +} +/* +int testApp::findExactOnset(){ + double energySum = 0; + double lastEnergySum, hopsizeLastEnergySum; + double energyDifference; + int bestEnergyIndex = 0; + double bestEnergyDifference = 0; + int endIndex = bufferSize; + int hopSize; + + for (int resolution = bufferSize/2;resolution > 1;resolution/=2){ + printf("resolution %i\n", resolution); + /// for (int i = bufferSize - resolution;i < bufferSize;i++){ + // lastEnergySum += recentBufferSamples[i] * recentBufferSamples[i]; + // } + + bestEnergyDifference = 0; + // printf("previous energy %f", lastEnergySum); + //initialise last energySum + hopSize = resolution/2; + + + lastEnergySum = getLastEnergySum(bestEnergyIndex, resolution); + hopsizeLastEnergySum = getLastEnergySum(bestEnergyIndex + hopSize, resolution); + + for (int startIndex = bestEnergyIndex;startIndex + resolution <= endIndex;startIndex += hopSize){ + printf("index %i last energy %f hop energy %f ", startIndex, lastEnergySum, hopsizeLastEnergySum); + + //sum the energy for this new frame + energySum = 0; + for (int i = 0;i < resolution;i++){ + energySum += onsetSamples[startIndex + i] * onsetSamples[startIndex + i]; + } + + printf("energysum %f\n", energySum); + //check if new max difference + energyDifference = energySum - lastEnergySum; + if (energyDifference > bestEnergyDifference){ + bestEnergyDifference = energyDifference; + bestEnergyIndex = startIndex; + } + + //store the values for checking in two loops time (because proceeding at resolution/2 each step) + //eg 0_to_128 compared to -128_to_0, 64_to_196 compared to -64_to_64, then 128_256 compared with 0_to_128, + lastEnergySum = hopsizeLastEnergySum;// energySum; + hopsizeLastEnergySum = energySum; + + } + printf("winning index is %i\n", bestEnergyIndex); + endIndex = bestEnergyIndex + resolution; + + } + printf("TOTAL WINNER %i\n", bestEnergyIndex); + return bestEnergyIndex; + +} + +double testApp::getLastEnergySum(const int& startIndex, const int& vectorSize){ + double lastEnergySum = 0; + + for (int i = startIndex - vectorSize;i < startIndex;i++){ + if (i > 0) + lastEnergySum += onsetSamples[i] * onsetSamples[i]; + else { + lastEnergySum += recentBufferSamples[bufferSize + i] * recentBufferSamples[bufferSize + i]; + } + } + return lastEnergySum; + +} +*/ +/* +bool testApp::peakProcessing(const double& newDFval){ + recentDFsamples.erase (recentDFsamples.begin(), recentDFsamples.begin()+1);//erase first val + recentDFsamples.push_back(newDFval); + + double slopeVal = getBestSlopeValue(newDFval); + + newOnsetFound = checkForSlopeOnset(slopeVal); + printf("slope %f median %f det median %f\n", slopeVal, bestSlopeMedian, detectionTriggerThreshold); + + if (newOnsetFound) + printf("BANG!\n"); + + recentDFslopeValues.erase (recentDFslopeValues.begin(), recentDFslopeValues.begin()+1);//erase first val + recentDFslopeValues.push_back(slopeVal); + + recentDFonsetFound.erase (recentDFonsetFound.begin(), recentDFonsetFound.begin()+1);//erase first val + recentDFonsetFound.push_back(newOnsetFound); + + + //printf("\n"); +// for (int i = 0;i < recentDFsamples.size();i++){ +// printf("rdf[%i] %f\n", i, recentDFsamples[i]); +// } + //printf("SLOPE %f\n", slopeVal); +} + + +double testApp::getBestSlopeValue(const float& dfvalue){ + + //the idea is we want a high slope + double bestValue = 0; + + for (int i = 1;i < min(numberOfDetectionValuesToTest, (int)recentDFsamples.size() - 1);i++){ + double angle = 0; + int otherIndex = recentDFsamples.size() - i + 1; + double testValue = 0; + + if (otherIndex > 0 && recentDFsamples[otherIndex] > 0 + && recentDFsamples[otherIndex] < dfvalue + ){ + angle = atan((float)(i * dfvalue)/ (numberOfDetectionValuesToTest*(dfvalue-recentDFsamples[otherIndex])) ); + testValue = (dfvalue - recentDFsamples[otherIndex]) * cos(angle); + } + + if (testValue > bestValue) + bestValue = testValue; + } + + return bestValue; + +} + + + +bool testApp :: checkForSlopeOnset(const float& bestValue){ + bool onsetDetected = false; + //check for onset relative to our processed slope function + //a mix between increase in value and the gradient of that increase + + currentFrame++; + + if (bestValue > bestSlopeMedian * thresholdRelativeToMedian && //better than recent average + (currentFrame - lastSlopeOnsetFrame) > cutoffForRepeatOnsetsFrames //after cutoff time + && slopeFallenBelowMedian // has had onset and fall away again + && bestValue > detectionTriggerThreshold * detectionTriggerRatio //longer term ratio of winning onsets + ){ + // printf("frame diff between onsets %6.1f", (1000*framesToSeconds(currentFrame - lastMedianOnsetFrame)) ); + onsetDetected = true; + lastSlopeOnsetFrame = currentFrame; + slopeFallenBelowMedian = false; + + updateDetectionTriggerThreshold(bestValue); + } + + + if (bestValue > bestSlopeMedian){ + bestSlopeMedian += (bestValue - bestSlopeMedian)*0.04;//was 1.1 + } + else{ + bestSlopeMedian *= 0.99; + slopeFallenBelowMedian = true;; + } + + //bestSlopeMedian += 0.02* (bestValue - bestSlopeMedian); + + + + return onsetDetected; +} + +void testApp :: updateDetectionTriggerThreshold(const float& val){ + float detectionAdaptSpeed = 0.05;//moving average, roughly last twenty onsets + detectionTriggerThreshold *= 1- detectionAdaptSpeed; + detectionTriggerThreshold += (val * detectionAdaptSpeed); +} + +*/ +//-------------------------------------------------------------- +void testApp::keyPressed (int key){ + if( key == 's' ){ + soundStream.start(); + } + + if( key == 'e' ){ + soundStream.stop(); + } + + if (key == 'h'){ + holdOn = !holdOn; + } +} + +//-------------------------------------------------------------- +void testApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void testApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void testApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void testApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void testApp::dragEvent(ofDragInfo dragInfo){ + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.h Fri Sep 21 16:35:17 2012 +0100 @@ -0,0 +1,84 @@ +#ifndef _TEST_APP +#define _TEST_APP + + +#include "ofMain.h" + +#include "OnsetDetectionFunction.h" +#include "PeakProcessor.h" +#include "PreciseOnsetLocator.h" + +class testApp : public ofBaseApp{ + + public: + + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + void audioIn(float * input, int bufferSize, int nChannels); + + vector <float> left; + vector <float> right; + vector <float> volHistory; + + int bufferCounter; + int drawCounter; + + float smoothedVol; + float scaledVol; + + ofSoundStream soundStream; + + OnsetDetectionFunction odf; + + PeakProcessor peakProcess; + + PreciseOnsetLocator precisionLocator; + + bool holdOn; + int bufferSize; + int exactOnsetIndex; + vector <double> onsetSamples;//holds the audio samples when onset is found +// vector <double> recentBufferSamples; + +/* + //peak processing requires + static const int vectorSize = 512/6; + vector<double> recentDFsamples; + vector<bool> recentDFonsetFound; + vector<double> recentDFslopeValues; + + int numberOfDetectionValuesToTest; + bool peakProcessing(const double& newDFval); + double getBestSlopeValue(const float& dfvalue); + bool checkForSlopeOnset(const float& bestValue); + int currentFrame, lastSlopeOnsetFrame, cutoffForRepeatOnsetsFrames; + void updateDetectionTriggerThreshold(const float& val); + float detectionTriggerThreshold, detectionTriggerRatio; + float bestSlopeMedian, thresholdRelativeToMedian; + bool newOnsetFound, slopeFallenBelowMedian; + */ +/* + + + + double getLastEnergySum(const int& startIndex, const int& vectorSize); + int findExactOnset(); + + */ +}; + + +#endif +