Mercurial > hg > aubio-onset-detector
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