view src/testApp.cpp @ 1:ba2a17cf81bf

first working version of audio file loder. Loads bach clip from the apps->audio-file-loader->bin->data->sounds foler. Three classes: SoundFileLoader does the loading and parsing of thefile with libSndFile. audio samples are kept in AudioFile and analysis of features are kept in AudioAnalysis, at this stage just chromagramm and basic energy
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Sun, 04 Sep 2011 22:45:35 +0100
parents bcb0d40158f4
children
line wrap: on
line source
#include "testApp.h"
#include "stdio.h"
#include "aubio.h"
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib> 


const double samplingFrequency = 44100.0;
	
//--------------------------------------------------------------
void testApp::setup(){

	ofBackground(255,255,255);

	
	// 2 output channels,
	// 0 input channels
	// 22050 samples per second
	// 256 samples per buffer
	// 4 num buffers (latency)
	
	//nb THIS CODE WOULD BE USEFUL IF WE EVER WANTED REAL-TIME INPUT - VIA ofSoundSteam
	

//	ofSetDataPathRoot("../bin/data/");

//DONT NEED ANY OF THIS
	sampleRate 			= 44100;
//	phase 				= 0;
//	phaseAdder 			= 0.0f;
//	phaseAdderTarget 	= 0.0f;
	volume				= 0.1f;
	bNoise 				= false;
	lAudio = new float[256];
	rAudio = new float[256];
	ofSoundStreamSetup(2,0,this, sampleRate,256, 4);
//UNTIL HERE
	
	
	ofSetFrameRate(60);
	
//	fvec_t * my_fvec_t;
//	aubio_onset_t* my_aubio_result;
//	aubio_onsetdetection_t * my_onset_detection;
	
	audioScale = 1000.0;
	

	
	//int readcount = 0; // counts number of samples read from sound file

	//string inputFilename = "sound/GetIntoTheGroove.wav";// input file name placed in bin


	
	moveOn = true;

	//loading audio files

	const char	*infilename = "../../../data/sound/bach4_short1.wav";	
	loadNewAudio(infilename);
	
	audioPlaying = false;

	drawSpectralDifferenceFunction = false;

	screenToDraw = 1;
	

}


void testApp::initialiseVariables(){
	
//	chromoGramm.initialise(FRAMESIZE,2048);//framesize 512 and hopsize 2048
}


//--------------------------------------------------------------
void testApp::update(){

	audioPosition = loadedAudio.getPosition() * fileLoader.totalNumberOfFrames;//frameIndex;//the position in number of frames
	fileLoader.chromaAnalysis.currentPlayingFrame = audioPosition;
	audioPosition = (int) audioPosition % fileLoader.chromaAnalysis.scrollWidth ;
	audioPosition /= fileLoader.chromaAnalysis.scrollWidth;
	
	fileLoader.audioHolder.playPosition = loadedAudio.getPosition() * fileLoader.audioHolder.audioVector.size();
}

//--------------------------------------------------------------
void testApp::draw(){
	switch (screenToDraw){
		case 0:
			if (drawSpectralDifferenceFunction)
				fileLoader.chromaAnalysis.drawSpectralDifference();
			else
				drawDoubleMatrix(&fileLoader.chromaAnalysis.chromaMatrix);
			
			fileLoader.chromaAnalysis.drawEnergyVectorFromPointer();
			
			ofSetColor(0xFFFFFF);
			ofLine(audioPosition*width, 0, audioPosition*width, height);
			break;
			case 1:
		//	audioHolder.drawAudioVectorMillis(1000, 1000+audioScale);
			fileLoader.audioHolder.drawAudioVectorSamples(fileLoader.audioHolder.playPosition - fileLoader.audioHolder.audioScaleSamples*0.5, fileLoader.audioHolder.playPosition+fileLoader.audioHolder.audioScaleSamples*0.5);
			ofSetColor(100,100,100);
			ofLine(width/2, 0, width/2, height);
			break;
	}
	

	
	//ofSetColor(255,0,0);
	//drawEnergyVectorFromPointer(&audioVector);
	


	ofDrawBitmapString(soundFileName,80,480);
		
}



void testApp::drawDoubleMatrix(DoubleMatrix* dMatrix){
	//used to draw the chromagram matrix
	int matrixSize = (*dMatrix).size();
	if (matrixSize > 0){
			
	float screenHeight = ofGetHeight() ;
	float screenWidth = ofGetWidth();
	float heightFactor = 8;
	int i, j, startingFrame;
	startingFrame = fileLoader.chromaAnalysis.currentPlayingFrame / fileLoader.chromaAnalysis.scrollWidth;//i.e. number of scroll widths in
	startingFrame *= fileLoader.chromaAnalysis.scrollWidth;//starting frame in terms of energy frames
	startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
	
	float chromoLength = fileLoader.chromaAnalysis.scrollWidth/CHROMA_CONVERSION_FACTOR;
	for (i = 0; i < chromoLength; i++){
		j = i + startingFrame;
		for (int y = 0;y < 12;y++){
			
			if (j < matrixSize)
			ofSetColor(0,0,255 * (*dMatrix)[j][11-y]);
			else 
			ofSetColor(0,0,0);

			ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12);
		}//end y
	}//end i
	
	}///end if matrix has content
	else{
		printf("Error - please load audio first");
	}
	
	
}



/*
void testApp::loadLibSndFile(const char *infilename){
	
	if (!sf_close(infile)){
		printf("closed sndfile okay \n");
	}
	
	// Open Input File with lib snd file
    if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
    {   // Open failed
        printf ("SF OPEN routine Not able to open input file %s.\n", infilename) ;
        // Print the error message from libsndfile. 
        puts (sf_strerror (NULL)) ;
		
	} else{
		printf("SF OPEN : file %s okay, ", infilename);
		printf("number of channels is %i\n", sfinfo.channels);
		sndfileInfoString = "Opened okay ";
		
	};
	
}
*/
/*
void testApp::processAudioToDoubleMatrix(Chromagram* chromaG, DoubleMatrix* myDoubleMatrix, DoubleVector* energyVector){

	myDoubleMatrix->clear();
	energyVector->clear();
	
	audioHolder.audioVector.clear();
	audioHolder.audioMatrix.clear();
	
//	energyIndex = 0;
//	frameIndex = 0;
//	chromaIndex = 0;//	WHY NEED THIS?
	chromaG->initialise(FRAMESIZE,2048);//framesize 512 and hopsize 2048 
	chromaG->maximumChromaValue = 0;
	
	


// HERE IS THE CLASSIC LOADING FILE CODE
 //DEALS WITH MORE THAN MONO
	int channels = sfinfo.channels;
	int blocksize = FRAMESIZE;
	
	float buf [channels * blocksize] ;
	int k, m, readcount ;
	
	DoubleVector d;
	while ((readcount = sf_readf_float (infile, buf, blocksize)) > 0){
		for (k = 0 ; k < readcount ; k++){	
			d.clear();
			for (m = 0 ; m < channels ; m++){
				d.push_back(buf [k * channels + m]);
				//		 fprintf (outfile, " % 12.10f", buf [k * channels + m]) ;
				//		 fprintf (outfile, "\n") ;
					if (m == 0){
					//makes the vector hold the mono file
					//this is the one we use for chromagram analysis etc
					audioHolder.audioVector.push_back(buf[k * channels + 0]);
					frame[k] = buf[k*channels + 0];
					}
				
			} 
			audioHolder.audioMatrix.push_back(d);
			//storing the full soundfile in multiple channels in the audioMatrix
		}
		
		
		chromaG->processframe(frame);
		
		if (chromaG->chromaready)
		{
			DoubleVector d;
			
			for (int i = 0;i<12;i++){
				//chromoGramVector[chromaIndex][i] = chromoGramm.rawChroma[i] / chromoGramm.maximumChromaValue;
				d.push_back(chromaG->rawChroma[i]);// / chromaG->maximumChromaValue);	
				
			}	
			
			myDoubleMatrix->push_back(d);
			
			//There was a method to detect chord but deleted
			//	chord.C_Detect(chromoGramm.chroma,chromoGramm.chroma_low);
			//	rootChord[chromaIndex] = chord.root;
			
			
		}//end if chromagRamm ready
		
	//	frameIndex++;
		
		//get energy of the current frame and wait
		double energyValue = getEnergyOfFrame();
		energyVector->push_back(energyValue);
		
		
		
	}//end readcount
	

	
	printf("Max chroma value is %f \n", chromaG->maximumChromaValue);

	
	
	//normalise
	int length = myDoubleMatrix->size();
	printf("length of chromagram is %d frames\n", length);
	length = ((*myDoubleMatrix)[0]).size();
		printf("height of dmatrix is %d\n", length);
	
	for (int i = 0; i < myDoubleMatrix->size();i++){
		for (int j = 0; j < ((*myDoubleMatrix)[0]).size();j++){
	(*myDoubleMatrix)[i][j] /= chromaG->maximumChromaValue;	
		}
	}
	

	printf("size of energy vector is %d \n", (int) energyVector->size());
	
	totalNumberOfFrames = (int) energyVector->size();//frameIndex;//used to use this - but switch to energy vector's size instead

//	printf("Total frames %i energy index %i and Chroma index %i \n", frameIndex, energyIndex, chromaIndex);
	
	printf("audio vector size is %i\n", (int) audioHolder.audioVector.size());
	audioHolder.length = (int) audioHolder.audioVector.size();
}

*/
//--------------------------------------------------------------
void testApp::keyPressed  (int key){
	if (key == '-'){
		volume -= 0.05;
		volume = MAX(volume, 0);
	} else if (key == '+'){
		volume += 0.05;
		volume = MIN(volume, 1);
	}

	if (key == 'q')
		screenToDraw = 1 - screenToDraw;
	
	if (key == OF_KEY_DOWN){
		if (fileLoader.chromaAnalysis.scrollWidth > 600)
		fileLoader.chromaAnalysis.scrollWidth += 400;
		else
		fileLoader.chromaAnalysis.scrollWidth *= 2;
	}
	
	if (key == OF_KEY_RIGHT){
		loadedAudio.setPosition(min(1.0, loadedAudio.getPosition() + (fileLoader.audioHolder.audioScaleSamples/(4.0*fileLoader.audioHolder.audioVector.size()))) );
//	audioHolder.playPosition = loadedAudio.getPosition() * audioHolder.audioVector.size();
	}
	
	if (key == OF_KEY_LEFT){
		loadedAudio.setPosition(max(0.0, loadedAudio.getPosition() - (fileLoader.audioHolder.audioScaleSamples/(4.0*fileLoader.audioHolder.audioVector.size()))));
		//	audioHolder.playPosition = loadedAudio.getPosition() * audioHolder.audioVector.size();
	}
	
	
	if (key == OF_KEY_UP){
		if (fileLoader.chromaAnalysis.scrollWidth > 600)
		fileLoader.chromaAnalysis.scrollWidth -= 400;
		else
		fileLoader.chromaAnalysis.scrollWidth /= 2;
	}
		
		if (key == ' '){
			if (!audioPlaying) {
				loadedAudio.play();
				loadedAudio.setPaused(false);
				audioPlaying = true;
				audioPaused = false;
			}
			else{
			audioPaused = !audioPaused;
			loadedAudio.setPaused(audioPaused);
			}
		
		}

	if (key == OF_KEY_RETURN){
			audioPlaying = false;
			loadedAudio.setPaused(true);
		loadedAudio.setPosition(0.0);
	}
	
	
	if (key == 'o'){
		openNewAudioFileWithdialogBox();
	}

		
	if (key == 'd'){
		drawSpectralDifferenceFunction = !drawSpectralDifferenceFunction;
	}
	
	if (key == 'u'){
		audioScale *= 2.;
	fileLoader.audioHolder.audioScaleSamples *= 2.;
	}
	
	if (key == 'j'){
		audioScale /= 2.;	
		fileLoader.audioHolder.audioScaleSamples /= 2.;
	}
}

//--------------------------------------------------------------
void testApp::keyReleased  (int key){

}

void testApp::openNewAudioFileWithdialogBox(){
	
	//open audio file
	string *filePtr;
	filePtr = &soundFileName;	
	
	if (getFilenameFromDialogBox(filePtr)){
		printf("Mainfile: Loaded name okay :\n'%s' \n", soundFileName.c_str());	
	}
	
	loadNewAudio(soundFileName);

}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
	width = ofGetWidth();
	pan = (float)x / (float)width;
	float height = (float)ofGetHeight();
	float heightPct = ((height-y) / height);
	xIndex = (int)(pan*fileLoader.chromaAnalysis.energyVector.size());
}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
	width = ofGetWidth();
	pan = (float)x / (float)width;
}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
	bNoise = true;
	moveOn = true;
}


//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
	bNoise = false;
}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){
width = w;
height = h;
}
//--------------------------------------------------------------
void testApp::audioRequested 	(float * output, int bufferSize, int nChannels){
	//pan = 0.5f;
	float leftScale = 1 - pan;
	float rightScale = pan;

}


//--------------------------------------------------------------


bool testApp::getFilenameFromDialogBox(string* fileNameToSave){
	//this uses a pointer structure within the loader and returns true if the dialogue box was used successfully
	// first, create a string that will hold the URL
	string URL;
	
	// openFile(string& URL) returns 1 if a file was picked
	// returns 0 when something went wrong or the user pressed 'cancel'
	int response = ofxFileDialogOSX::openFile(URL);
	if(response){
		// now you can use the URL 
		*fileNameToSave = URL;
		//printf("\n filename is %s \n", soundFileName.c_str());
		return true;
	}
	else {
	//	soundFileName = "OPEN canceled. ";
		printf("\n open file cancelled \n");
		return false;
	}
	
}

void testApp::openFileDialogBox(){

	// first, create a string that will hold the URL
	string URL;
	
	// openFile(string& URL) returns 1 if a file was picked
	// returns 0 when something went wrong or the user pressed 'cancel'
	int response = ofxFileDialogOSX::openFile(URL);
	if(response){
		// now you can use the URL 
		soundFileName = URL;//"URL to open: \n "+URL;
	}else {
		soundFileName = "OPEN canceled. ";
	}
	
	

}


void testApp::loadNewAudio(string soundFileName){

	loadedAudio.loadSound(soundFileName);
	
	//snd file method
	const char	*infilename = soundFileName.c_str() ;
	fileLoader.loadLibSndFile(infilename);

	
	
	audioPlaying = false;
}





/*
 
double testApp::getEnergyOfFrame(){
	
	float totalEnergyInFrame = 0;
	
	for (int i = 0;i<FRAMESIZE;i++){
		
		totalEnergyInFrame += (frame[i] * frame[i]);
		
	}
	totalEnergyInFrame = sqrt(totalEnergyInFrame);
	
	return totalEnergyInFrame;
}

*/


//JUNK METHODS BEFORE SWITCHING TO VECTORS TO HOLD ENERGY AND CHROMA
//THESE ARE BETTER AS THEY ARE DYNAMIC

/*
 void testApp::drawChromoGram(){
 float screenHeight = ofGetHeight() ;
 float screenWidth = ofGetWidth();
 float heightFactor = 8;
 int i, j, startingFrame;
 startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
 startingFrame *= scrollWidth;//starting frame in terms of energy frames
 startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
 
 float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR;
 for (i = 0; i < chromoLength; i++){
 j = i + startingFrame;
 for (int y = 0;y < 12;y++){
 ofSetColor(255*chromoGramVector[j][11-y],0,0);
 ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12);
 }//end y
 }//end i
 
 }
 */



/*
 void testApp::drawChromaMatrix(){
 float screenHeight = ofGetHeight() ;
 float screenWidth = ofGetWidth();
 float heightFactor = 8;
 int i, j, startingFrame;
 startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
 startingFrame *= scrollWidth;//starting frame in terms of energy frames
 startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
 
 float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR;
 for (i = 0; i < chromoLength; i++){
 j = i + startingFrame;
 for (int y = 0;y < 12;y++){
 ofSetColor(0,255*chromaMatrix[j][11-y],0);
 ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12);
 }//end y
 }//end i
 
 }
 */




/*
 
 
 int readcount = 1; // counts number of samples read from sound file
 printf("processing audio from doublematrix \n");
 
 while(readcount != 0 && moveOn == true)
 {
 
 // read FRAMESIZE samples from 'infile' and save in 'data'
 readcount = sf_read_float(infile, frame, FRAMESIZE);
 
 
 for (int i = 0;i < FRAMESIZE;i++)
 audioHolder.audioVector.push_back(frame[i]);
 
 printf("frame%f\n", frame[0]);
 //processing frame - downsampled to 11025Hz
 //8192 samples per chroma frame
 chromaG->processframe(frame);
 
 if (chromaG->chromaready)
 {
 DoubleVector d;
 
 for (int i = 0;i<12;i++){
 //chromoGramVector[chromaIndex][i] = chromoGramm.rawChroma[i] / chromoGramm.maximumChromaValue;
 d.push_back(chromaG->rawChroma[i]);// / chromaG->maximumChromaValue);	
 
 }	
 
 myDoubleMatrix->push_back(d);
 
 //There was a method to detect chord but deleted
 //	chord.C_Detect(chromoGramm.chroma,chromoGramm.chroma_low);
 //	rootChord[chromaIndex] = chord.root;
 
 
 }//end if chromagRamm ready
 
 //printf("calling drawSndFile %i", frameIndex);
 //	frameIndex++;
 
 //get energy of the current frame and wait
 double energyValue = getEnergyOfFrame();
 energyVector->push_back(energyValue);
 
 
 }//end while readcount
 
 
 void testApp::drawEnergyVectorFromPointer(DoubleVector* energyVec){
 
 ofSetColor(0xFF0066);
 float screenHeight = ofGetHeight() ;
 float screenWidth = ofGetWidth();  
 float heightFactor = 8;
 int i, j, startingFrame;
 startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
 startingFrame *= scrollWidth;
 
 for (i = 0; i < scrollWidth - 1; i++){
 j = i + startingFrame;
 if (j < (*energyVec).size())
 ofLine(i*screenWidth/scrollWidth, screenHeight - ((*energyVec)[j]*screenHeight/heightFactor),
 screenWidth*(i+1)/scrollWidth, screenHeight - ((*energyVec)[j+1]*screenHeight/heightFactor));
 
 }
 }
 
 void testApp::drawSpectralDifference(DoubleMatrix* dMatrix){
 int matrixSize = (*dMatrix).size();
 if (matrixSize > 0){
 
 float screenHeight = ofGetHeight() ;
 float screenWidth = ofGetWidth();
 float heightFactor = 8;
 double difference;
 int i, j, startingFrame;
 startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
 startingFrame *= scrollWidth;//starting frame in terms of energy frames
 startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
 
 float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR;
 for (i = 1; i < chromoLength; i++){//changed to add 1
 j = i + startingFrame;
 for (int y = 0;y < 12;y++){			
 
 if (j < matrixSize)
 difference = (*dMatrix)[j][11-y] - (*dMatrix)[j-1][11-y];
 else 
 difference = 0;
 
 if (difference < 0)
 difference = 0;//half wave rectify
 
 ofSetColor(0,0,255 * difference);//, 0;
 ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12);
 }//end y
 }//end i
 
 }///end if matrix has content
 else{
 printf("Error - please load audio first");
 }
 
 }
 
 */