changeset 3:979125db34ab

added OF visualiser src code. Added a long term median trigger threshold. New method is working very well on onsets
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 21 Nov 2011 23:22:40 +0000
parents b4c899822b4e
children fb106f14e0a4
files Source/AubioOnsetDetector.cpp Source/AubioOnsetDetector.h Source/aubioOnsetDetect~.cpp aubioOnsetDetectorOFvisualiser/src/main.cpp aubioOnsetDetectorOFvisualiser/src/testApp.cpp aubioOnsetDetectorOFvisualiser/src/testApp.h
diffstat 6 files changed, 563 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/Source/AubioOnsetDetector.cpp	Wed Oct 19 21:08:45 2011 +0100
+++ b/Source/AubioOnsetDetector.cpp	Mon Nov 21 23:22:40 2011 +0000
@@ -26,6 +26,9 @@
 	cutoffForRepeatOnsetsMillis = 100;
 	medianSpeed = 10;
 	pos = 0;
+	
+	detectionTriggerRatio = 0.5f;
+	detectionTriggerThreshold = 10;
 }
 
 AubioOnsetDetector :: ~AubioOnsetDetector(){
@@ -192,26 +195,36 @@
 	//check for onset relative to our processed slope function
 	//a mix between increase in value and the gradient of that increase
 	
-	if (bestValue > bestSlopeMedian * thresholdRelativeToMedian && 
-		1000*framesToSeconds(currentFrame - lastSlopeOnsetFrame) > cutoffForRepeatOnsetsMillis
-		&& slopeFallenBelowMedian
+	if (bestValue > bestSlopeMedian * thresholdRelativeToMedian && //better than recent average 
+		1000*framesToSeconds(currentFrame - lastSlopeOnsetFrame) > cutoffForRepeatOnsetsMillis //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.1;
+		bestSlopeMedian += (bestValue - bestSlopeMedian)*0.02;//was 1.1
 	else{
-		bestSlopeMedian *= 0.995;
+		bestSlopeMedian *= 0.99;
 		slopeFallenBelowMedian = true;;
 	}
 	return onsetDetected;
 }
 
+
+void AubioOnsetDetector::updateDetectionTriggerThreshold(const float& val){
+	float detectionAdaptSpeed = 0.05;//moving average, roughly last twenty onsets
+	detectionTriggerThreshold *= 1- detectionAdaptSpeed;
+	detectionTriggerThreshold += (val * detectionAdaptSpeed);
+}
+
 double  AubioOnsetDetector::framesToSeconds(float frames){
 	double seconds = frames * buffersize / 44100.;
 	return seconds;
--- a/Source/AubioOnsetDetector.h	Wed Oct 19 21:08:45 2011 +0100
+++ b/Source/AubioOnsetDetector.h	Mon Nov 21 23:22:40 2011 +0000
@@ -64,6 +64,10 @@
 	bool slopeFallenBelowMedian;
 	bool checkForSlopeOnset(float bestValue);
 	
+	void updateDetectionTriggerThreshold(const float& val);
+	
+	float detectionTriggerThreshold, detectionTriggerRatio;
+	
 };
 
 #endif
\ No newline at end of file
--- a/Source/aubioOnsetDetect~.cpp	Wed Oct 19 21:08:45 2011 +0100
+++ b/Source/aubioOnsetDetect~.cpp	Mon Nov 21 23:22:40 2011 +0000
@@ -24,6 +24,7 @@
 	
 	AubioOnsetDetector			*onsetDetector;
 	
+	
 	void						*bangoutlet;
 	void						*medianBangOutlet;
 	
@@ -214,7 +215,7 @@
 	// aubio onset detector then processes current frame - returns bool true when new detection is output
 	if (x->onsetDetector->processframe(frame, n)){
 	//if buffer full and new result is processed (buffer is 1024 with hopsize 512 - can be set to other values)
-		outlet_float(x->medianDetectionFunctionOutlet, x->onsetDetector->medianDetectionValue);
+		outlet_float(x->medianDetectionFunctionOutlet, x->onsetDetector->bestSlopeMedian);//medianDetectionValue
 		outlet_float(x->rawDetectionFunctionOutlet, x->onsetDetector->rawDetectionValue);
 	//	outlet_float(x->detectionFunctionOutlet, x->onsetDetector->peakPickedDetectionValue);
 		outlet_float(x->detectionFunctionOutlet, x->onsetDetector->bestSlopeValue);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aubioOnsetDetectorOFvisualiser/src/main.cpp	Mon Nov 21 23:22:40 2011 +0000
@@ -0,0 +1,16 @@
+#include "ofMain.h"
+#include "testApp.h"
+#include "ofAppGlutWindow.h"
+
+//========================================================================
+int main( ){
+
+    ofAppGlutWindow window;
+	ofSetupOpenGL(&window, 640,480, 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/aubioOnsetDetectorOFvisualiser/src/testApp.cpp	Mon Nov 21 23:22:40 2011 +0000
@@ -0,0 +1,423 @@
+#include "testApp.h"
+//#include "math.h" 
+
+#define SAMPLING_FREQUENCY 44100
+#define FOURIER_LENGTH 2048
+#define TEXT_HEIGHT 10
+//--------------------------------------------------------------
+void testApp::setup(){
+	// listen on the given port
+//	cout << "listening for osc messages on port " << PORT << "\n";
+	receiver.setup( PORT );
+
+	current_msg_string = 0;
+	mouseX = 0;
+	mouseY = 0;
+	mouseButtonState = "";
+
+	ofBackground( 30, 30, 130 );
+
+
+	outputGraphics = false;
+	
+	maximumDetectionFunction = 20;
+	minimumDetectionFunction = -20;
+	
+	screenWidth = (float) ofGetWidth();
+	screenHeight = (float) ofGetHeight();
+	
+	mouseDownX = 0;
+	mouseDownY = 0;
+	
+	amplitudeNumber = 256;//number of amplitudes shown on screen
+		
+	maxValue = 1.0;
+	
+	detectionType = "complex";
+	lastOnsetDetectionValue;
+	
+	logMode = false;
+	
+	midiMode = true;
+	
+	resetMaxima = false;
+	
+	reIndexFlag = false;
+
+	ofBackground(0,0,0);
+	
+	rawOnsetIndex = 0;
+}
+
+//--------------------------------------------------------------
+void testApp::update(){
+maxValue *= 0.995;
+	// hide old messages
+
+	// check for waiting messages
+	while( receiver.hasWaitingMessages() )
+	{
+		// get the next message
+		ofxOscMessage m;
+		receiver.getNextMessage( &m );
+
+			// unrecognized message: display on the bottom of the screen
+	//		string msg_string;
+	//		msg_string = m.getAddress();
+			if (m.getAddress() == "/aubioData" ){
+			
+				if( m.getArgType( 0 ) == OFXOSC_TYPE_FLOAT ){
+				
+				onsetIndex++;
+				onsetRecorded[onsetIndex] = false;
+				
+					if (onsetIndex >= NUM_DETECTION_SAMPLES)
+					onsetIndex = 0;
+				
+				onsetFunction[onsetIndex] =  m.getArgAsFloat(0);
+				
+				checkMaxima(m.getArgAsFloat(0));
+				
+				}//end if type FLOAT
+			}//end if aubioData
+			
+					
+	if (m.getAddress() == "/rawAubioData" ){
+			
+				if( m.getArgType( 0 ) == OFXOSC_TYPE_FLOAT ){
+				
+				rawOnsetIndex++;
+						
+					if (rawOnsetIndex >= NUM_DETECTION_SAMPLES)
+					rawOnsetIndex = 0;
+				
+				rawOnsetFunction[rawOnsetIndex] =  m.getArgAsFloat(0);
+				checkRawMaxima(m.getArgAsFloat(0));
+				
+				}//end if type FLOAT
+			}//end spec diff message
+
+
+		if (m.getAddress() == "/medianAubioData" ){
+			
+			if( m.getArgType( 0 ) == OFXOSC_TYPE_FLOAT ){
+				
+				medianOnsetIndex++;
+				
+				if (medianOnsetIndex >= NUM_DETECTION_SAMPLES){
+					medianOnsetIndex = 0;
+				}
+				
+				if(medianOnsetIndex > 0)
+				medianOnsetRecorded[medianOnsetIndex] = false;//but how do we know this happens first!
+				
+				medianOnsetFunction[medianOnsetIndex] =  m.getArgAsFloat(0);
+				
+			}//end if type FLOAT
+		}//end spec diff message
+		
+		
+		
+
+		if (m.getAddress() == "/onset" ){
+			onsetRecorded[onsetIndex] = true;
+			lastOnsetDetectionValue = onsetFunction[onsetIndex];
+		}
+
+		if (m.getAddress() == "/medianOnset" ){
+			medianOnsetRecorded[onsetIndex] = true;
+		}
+
+		
+		
+		if (m.getAddress() == "/rawOnset" ){
+			rawOnsetRecorded[rawOnsetIndex] = true;
+
+		}
+
+		if (m.getAddress() == "/mode" ){
+		resetMaxima = true; 
+		detectionType = m.getArgAsString(0);
+		}
+
+	}//end while
+
+}
+
+
+void testApp::checkMaxima(float f){
+
+//maximumDetectionFunction *= 0.99999;
+//minimumDetectionFunction += (maximumDetectionFunction - minimumDetectionFunction)*0.00001;
+
+	if (maximumDetectionFunction * 1.08 < f){
+		maximumDetectionFunction = 1.08*f;
+	}
+
+	if (minimumDetectionFunction + (fabs(minimumDetectionFunction * 0.08)) > f){
+		minimumDetectionFunction = f - (0.08 * fabs(f));
+	}
+	
+	if (resetMaxima == true){
+			maximumDetectionFunction = 30;
+			minimumDetectionFunction = 0;
+			resetMaxima = false;
+			}
+	
+}
+
+
+void testApp::checkRawMaxima(float f){
+
+//maximumDetectionFunction *= 0.99999;
+//minimumDetectionFunction += (maximumDetectionFunction - minimumDetectionFunction)*0.00001;
+
+	if (maximumDetectionFunction * 1.08 < f){
+		maximumDetectionFunction = 1.08*f;
+	}
+
+	if (minimumDetectionFunction + (fabs(minimumDetectionFunction * 0.08)) > f){
+		minimumDetectionFunction = f - (0.08 * fabs(f));
+	}
+
+}
+
+
+
+//--------------------------------------------------------------
+void testApp::draw(){
+
+	drawOnsetFunction();
+	printInfo();
+
+}
+
+void testApp::printMessages(){
+	string buf;
+	buf = "listening for osc messages on port" + ofToString( PORT );
+	ofDrawBitmapString( buf, 10, 20 );
+
+	for ( int i=0; i<NUM_MSG_STRINGS; i++ )
+	{
+	ofDrawBitmapString( msg_strings[i], 10, 40+15*i );
+	}
+	
+}
+
+void testApp::printInfo(){	
+	ofSetColor(255,255,255);
+	string printString;
+
+/*	printString = "Max ";
+	printString += ofToString(maximumDetectionFunction);
+	printString += "    Min ";
+	printString += ofToString(minimumDetectionFunction);
+*/	
+
+	printString += detectionType;
+	printString +="    ";
+	printString += ofToString(lastOnsetDetectionValue, 1);
+	ofDrawBitmapString( printString  , 10, ofGetHeight() - 20);
+}
+
+//--------------------------------------------------------------
+void testApp::keyPressed  (int key){
+
+	if (key == OF_KEY_UP){
+
+	}
+
+	if (key == OF_KEY_DOWN ){
+
+	}		
+
+
+	if (key == OF_KEY_RIGHT ){
+
+	}		
+
+	if (key == OF_KEY_LEFT ){
+
+	}		
+
+	if (key == 'L' || key == 'l'){
+	logMode = !logMode;
+	}
+
+	if (key == 'p' || key == 'P'){
+
+	}
+
+	if (key == 'm' || key == 'M'){
+	midiMode = !midiMode;
+	}
+		
+	if (key == 'x' || key == 'X'){
+	amplitudeNumber *= 2;
+	}
+
+	if (key == 'z' || key == 'Z'){
+	amplitudeNumber /= 2;
+	}
+
+if ((key == '=' || key == '+') && amplitudeNumber < 120){
+	amplitudeNumber += 8;
+	}
+
+if ((key == '-' || key == '_') && amplitudeNumber > 12){
+	amplitudeNumber -= 8;
+	}		
+
+}
+
+
+
+void testApp::drawOnsetFunction(){
+	int tmpIndex = onsetIndex;
+	float width = screenWidth / (float) amplitudeNumber;	
+	float maximumValue = maximumDetectionFunction ;
+	float minimumValue = minimumDetectionFunction ;
+	float difference = maximumValue - minimumValue;
+	float scale_factor = screenHeight/ difference;
+	
+	//draw axis
+	ofSetColor(255,255,255);
+	ofLine(0, screenHeight - (scale_factor*(0 - minimumValue)), 
+			(int) (width*(amplitudeNumber)),  screenHeight - (scale_factor*(0 - minimumValue)) );
+
+	
+	for (int Xvalue = 0;Xvalue < amplitudeNumber; Xvalue++){
+	
+	int Xindex = (onsetIndex-Xvalue) ;
+	int previousIndex = (Xindex-1);
+	
+	ofSetColor(55,100,255);
+
+	ofLine((int) (width*(amplitudeNumber - Xvalue - 1)), screenHeight - (scale_factor*(onsetFunction[previousIndex]- minimumValue)), 
+			(int) (width*(amplitudeNumber - Xvalue)),  screenHeight - (scale_factor*(onsetFunction[Xindex]- minimumValue)) );
+
+	if (onsetRecorded[Xindex] == true){
+		ofSetColor(255,100,255);
+		ofCircle(width*(amplitudeNumber - Xvalue), screenHeight - (scale_factor*(onsetFunction[Xindex]- minimumValue)) , 3);
+	}
+	
+//specDiffOnsets	
+	ofSetColor(55,100,55);
+ Xindex = (rawOnsetIndex-Xvalue) ;
+ previousIndex = (Xindex-1);
+
+	ofLine((int) (width*(amplitudeNumber - Xvalue - 1)), screenHeight - (scale_factor*(rawOnsetFunction[previousIndex]- minimumValue)), 
+			(int) (width*(amplitudeNumber - Xvalue)),  screenHeight - (scale_factor*(rawOnsetFunction[Xindex]- minimumValue)) );
+	
+		//median of Onset fn	
+		ofSetColor(205,0,0);
+		Xindex = (medianOnsetIndex-Xvalue) ;
+		previousIndex = (Xindex-1);
+		
+		ofLine((int) (width*(amplitudeNumber - Xvalue - 1)), screenHeight - (scale_factor*(medianOnsetFunction[previousIndex]- minimumValue)), 
+			   (int) (width*(amplitudeNumber - Xvalue)),  screenHeight - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) );
+		
+		
+
+	if (rawOnsetRecorded[Xindex] == true){
+		ofSetColor(255,100,0);
+		ofCircle(width*(amplitudeNumber - Xvalue), screenHeight - (scale_factor*(rawOnsetFunction[Xindex]- minimumValue)) , 3);
+	}
+		
+		if (medianOnsetRecorded[Xindex] == true){
+			ofSetColor(255,0,0);
+			ofCircle(width*(amplitudeNumber - Xvalue), screenHeight - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) , 3);
+		}
+		
+		
+		/*
+	if (medianOnsetRecorded[Xindex] == true){
+		ofSetColor(255,0,0);
+		ofCircle(width*(amplitudeNumber - Xvalue), screenHeight - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) , 3);
+	}	
+	*/
+		ofSetColor(255,100,0);
+		
+	}//end for Xvalue (across the recent observations of osc data)
+
+	
+	//label y axis
+	int axisHeight, stepSize;
+	ofSetColor(255,255,255);
+	stepSize = 1000;
+
+	while((difference / stepSize) < 3)
+	stepSize /= 2;
+	
+	while ((difference / stepSize) > 7)// maximum 6 numbers to display
+	stepSize *= 2;
+
+	
+	for (axisHeight = 0; axisHeight < maximumDetectionFunction; axisHeight += stepSize){
+	ofDrawBitmapString( ofToString((int)axisHeight), ofGetWidth()-50,
+	 (int) ((TEXT_HEIGHT/2) +(screenHeight - (scale_factor*(axisHeight- minimumValue)))) );
+	}
+	
+	for (axisHeight = max(0, (int)minimumDetectionFunction); axisHeight > min(0, (int)minimumDetectionFunction); axisHeight -= stepSize){
+	ofDrawBitmapString( ofToString((int)axisHeight), ofGetWidth()-50,
+	 (int) ((TEXT_HEIGHT/2) +(screenHeight - (scale_factor*(axisHeight- minimumValue)))) );
+	}
+	
+	//label x axis
+	stepSize = 20;//need to make sure not too many of these:
+	
+	while((amplitudeNumber / stepSize) < 4)
+	stepSize /= 2;
+	
+	while ((amplitudeNumber / stepSize) > 8)
+	stepSize *= 2;
+
+	int labelIndex = onsetIndex - (onsetIndex % stepSize);
+	for (int y = labelIndex; y > onsetIndex - amplitudeNumber; y -= stepSize){
+		ofDrawBitmapString( ofToString((int)y), (int) (width*(amplitudeNumber - (onsetIndex - y))),
+	 (int) ((TEXT_HEIGHT+2) + (screenHeight - (scale_factor*(0 - minimumValue)))) );
+	}
+	
+}//end label 
+//--------------------------------------------------------------
+void testApp::mouseMoved(int x, int y ){
+
+
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseDragged(int x, int y, int button){
+if ((x - mouseDownX) > 50 ){
+mouseDownX = x;
+}
+
+if ((x - mouseDownX) < -50){
+
+mouseDownX = x;
+}
+
+
+}
+
+//--------------------------------------------------------------
+void testApp::mousePressed(int x, int y, int button){
+
+mouseDownX = x;
+mouseDownY = y;
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::windowResized(int w, int h){
+
+	screenWidth = (float) ofGetWidth();
+	screenHeight = (float) ofGetHeight();
+	
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aubioOnsetDetectorOFvisualiser/src/testApp.h	Mon Nov 21 23:22:40 2011 +0000
@@ -0,0 +1,100 @@
+#ifndef _TEST_APP
+#define _TEST_APP
+
+
+#include "ofMain.h"
+
+#include "ofxOsc.h"
+
+// listen on port 12345
+#define PORT 12345
+#define NUM_MSG_STRINGS 20
+#define NUM_DETECTION_SAMPLES 128000
+
+//--------------------------------------------------------
+class testApp : public ofBaseApp{
+
+	public:
+
+		void setup();
+		void update();
+		void draw();
+
+		void keyPressed  (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 printMessages();
+		void printInfo();
+
+		
+		void checkMaxima(float f);
+		void checkRawMaxima(float f);
+				
+		void drawOnsetFunction();
+		ofTrueTypeFont		font;
+
+		
+
+private:
+		ofxOscReceiver	receiver;
+
+		int				current_msg_string;
+
+//aubio onset detection		
+		float			onsetFunction[NUM_DETECTION_SAMPLES];
+		int				onsetIndex;
+		bool			onsetRecorded[NUM_DETECTION_SAMPLES];
+
+//specDiffOnset2~ detection
+		int				rawOnsetIndex;
+		float			rawOnsetFunction[NUM_DETECTION_SAMPLES];		
+		bool			rawOnsetRecorded[NUM_DETECTION_SAMPLES];
+	
+	//median of the detection function
+	int				medianOnsetIndex;
+	float			medianOnsetFunction[NUM_DETECTION_SAMPLES];		
+	bool			medianOnsetRecorded[NUM_DETECTION_SAMPLES];
+
+		
+		float			maximumDetectionFunction;
+		float			minimumDetectionFunction;		
+		
+		float			maxValue;
+		
+		int				amplitudeNumber;
+		bool			outputGraphics;
+		bool			resetMaxima;
+		
+		string			msg_strings[NUM_MSG_STRINGS];
+		float			timers[NUM_MSG_STRINGS];
+		string			detectionType;
+		float			lastOnsetDetectionValue;
+		int				mouseX, mouseY;
+		string			mouseButtonState;
+
+		string			axisString[128];
+
+		bool reIndexFlag;
+		bool logMode;
+		bool midiMode;
+		
+		float screenWidth;
+		float screenHeight;
+		
+		
+		string midiString[128];
+		
+		int mouseDownX;
+		int mouseDownY;
+		
+		float freqMin ;
+		float freqMax ;
+		float freqLog ;
+		float logMin ;
+};
+
+#endif