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

changed files since updating computer
author Venetian
date Thu, 14 Aug 2014 17:53:57 +0100
parents 7ec1ed0b2eb0
children
line wrap: on
line source
#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 :: PRECISE ONSET DETECTION " + 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);
	
		//param
		float heightFactor = 0.15;
	
		ofSetColor(245, 58, 135);
		ofSetLineWidth(3);
					
			ofBeginShape();
			for (int i = 0; i < peakProcess.recentDFsamples.size(); i++){
				int height = 200 - peakProcess.recentDFsamples[i]*heightFactor;
				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 = 200 - peakProcess.recentDFslopeValues[i]*heightFactor;
		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, 200);
		}
	}
	ofEndShape(false);
	
	ofPopMatrix();
	ofPopStyle();
	
	
	
	//ONSET Samples
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 520, 0);
	
	ofSetColor(245, 224, 235);
	ofDrawBitmapString("exact onset index (in buffer) "+ofToString(exactOnsetIndex), 0, 20);
	
	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]);//divide by 512.0 or bufferSize to get [0,1] value
	}
	
	//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){ 

}