view src/PeakProcessor.cpp @ 8:184a7c232049 tip

changed files since updating computer
author Venetian
date Thu, 14 Aug 2014 17:53:57 +0100
parents 93b9a9471011
children
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;//true;//false;


/*
how it works
detectionTriggerThreshold is a fairly fdast moving average (every twenty frames)
 tend to require newValue > detectionTriggerRatio * detectionTriggerThreshold 
*/

PeakProcessor::PeakProcessor(){
	
	recentDFsamples.assign(vectorSize, 0.0);
	recentDFonsetFound.assign(vectorSize, false);
	recentDFslopeValues.assign(vectorSize, 0.0);
	/*
	 //all in reset
	numberOfDetectionValuesToTest = 10;
	currentFrame = 0;
	cutoffForRepeatOnsetsFrames = 8;
	detectionTriggerRatio = 0.34f;//was 0.5
	detectionTriggerThreshold = 0.2;//was 1.5 is trigger?
	bestSlopeMedian = 3;
	thresholdRelativeToMedian = 1.1;
	slopeFallenBelowMedian = true;
	lastSlopeOnsetFrame = 0;
	*/
	initialise();
	reset();
	minimumThreshold = 15.;
}

PeakProcessor::~PeakProcessor(){
	
	recentDFsamples.clear();
	recentDFonsetFound.clear();
	recentDFslopeValues.clear();
}


void PeakProcessor::initialise(){
	numberOfDetectionValuesToTest = 10;
	cutoffForRepeatOnsetsFrames = 8;
	detectionTriggerRatio = 0.234f;//was 0.5
	thresholdRelativeToMedian = 1.01;//need to be this multiple above median value
	//median tends to move relatively slowly
	reset();
/*	slopeFallenBelowMedian = true;
	lastSlopeOnsetFrame = 0;
	currentFrame = 0;
 */
}

void PeakProcessor::reset(){
	/*
	numberOfDetectionValuesToTest = 10;
	
	cutoffForRepeatOnsetsFrames = 8;
	detectionTriggerRatio = 0.234f;//was 0.5
	detectionTriggerThreshold = 0.2;
	bestSlopeMedian = 3;
	thresholdRelativeToMedian = 1.01;//need to be this multiple above median value
	*/
	//median tends to move relatively slowly
	slopeFallenBelowMedian = true;
	lastSlopeOnsetFrame = 0;
	currentFrame = 0;
	detectionTriggerThreshold = 0.4;
	bestSlopeMedian = 16;
}

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;
	double bestCosAngle = 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;
			bestCosAngle = cos(angle);
		}
	}
	if (printingOn)
		printf("best value %f dfValue %f cosAngle %f\n", bestValue, dfvalue, bestCosAngle);

	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 
		&& bestValue > minimumThreshold//fixed minimum requirement
		){
		//	printf("frame diff between onsets %6.1f", (1000*framesToSeconds(currentFrame - lastMedianOnsetFrame)) );
		onsetDetected = true;
		lastSlopeOnsetFrame = currentFrame;
		slopeFallenBelowMedian = false;
		
		updateDetectionTriggerThreshold(bestValue);
		
		if (printingOn)
			printf("ONSET, best value %f, min %f\n", bestValue, minimumThreshold);
	}
	
	
	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);
}