view src/PeakProcessor.cpp @ 4:93b9a9471011

Changes to precise onset
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 06 Jan 2014 18:10:01 +0000
parents 7ec1ed0b2eb0
children 184a7c232049
line wrap: on
line source
/*
 *  PeakProcessor.cpp
 *  peakOnsetDetector
 *
 *  Created by Andrew Robertson on 07/09/2012.
 *  Copyright 2012 QMUL. All rights reserved.
 *
 */

#include "PeakProcessor.h"

const bool printingOn = false;//true;//false;

PeakProcessor::PeakProcessor(){
	
	recentDFsamples.assign(vectorSize, 0.0);
	recentDFonsetFound.assign(vectorSize, false);
	recentDFslopeValues.assign(vectorSize, 0.0);
	
	numberOfDetectionValuesToTest = 10;
	currentFrame = 0;
	cutoffForRepeatOnsetsFrames = 4;
	detectionTriggerRatio = 0.34f;//was 0.5
	detectionTriggerThreshold = 1.5;//0.1;
	bestSlopeMedian = 3;
	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);

	if (printingOn)
		printf("PeakProcessor: slope %f best slope median %f det trigger thresh median %f\n", slopeVal, bestSlopeMedian, detectionTriggerThreshold);
	
	if (newOnsetFound && printingOn){
		printf("PeakProcessor: 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);
}