view src/testApp.cpp @ 4:f40577e6b30d

revised this to work with onset and chroma and looking now to do sequential DTW
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Wed, 08 Jun 2011 17:35:56 +0100
parents 9ce18f24b266
children 0d51e93bfe74
line wrap: on
line source
#include "testApp.h"
#include "stdio.h"
#include "aubio.h"
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib> 



//FIX CHORDS IN THE NEW POINTER VERSION OF THE PROCESS AUDIO FN

//BUG IN WHETHER SECOND SONG LOADED OR NOT


//CHECK THAT DTW will not call beyond the limits of the two chroma if different sizes

//CALC DTW on different sizes

//CHECK CORRECT BEST ALIGNMENT METHOD FOR DTW

//RE-DO DRAW SO THAT IT DOES NOT CALCULATE EVERY POINT BUT DOES IN SQUARE CHUNKS	

//UPDATE START FRAME SO ALIGNMENT IS ALWAYS ON SCREEN
//--------------------------------------------------------------

/*
 Main functions here:
 
 Load file from a dialogue box with LibSndFile
 We then iterate through all the samples and call our relevant functions in the timeWarp object - i.e. onset, chroma
 and do the calculations for similarity and alignment
 
 
 TO DO:
 Find continual alignment between the playing file and the non-playing file
 - show the current location in the energy amd chroma draw fn for the non-playing file
 
 simplify the loading procedure
 
 */


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)
	

//	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;
	
	scrollWidth = 1600;
	
	conversionFactor = 1;//CHROMA_CONVERSION_FACTOR;
	chromoLength = scrollWidth / conversionFactor;// CHROMA_CONVERSION_FACTOR;

	
	sfinfo.format = 0;
	
	moveOn = true;
	
	
	chromaG.initialise(FRAMESIZE, CHROMAGRAM_FRAMESIZE);
	onset = new OnsetDetectionFunction(512,1024,6,1);
	
	//loading audio files
	loadSoundFiles();			
	
	soundFileName = "../../../data/sound/Bach_short2.wav";
	
	loadFirstAudioFile();
	
	secondFileName = "../../../data/sound/Bach_short2.wav";

	loadSecondAudio(secondFileName);//i.e. load same as first file
	
	backwardsAlignmentIndex = 0;//remember that this goes backwards!

	tw.initialiseVariables();
	
	calculateSimilarityAndAlignment();
	
	printf("\n gettem hereafter!");	
	//set not to play
	audioPlaying = false;

	drawSecondMatrix = false;
	drawSpectralDifferenceFunction = false;
	drawSimilarity = true;

	screenHeight = ofGetHeight() ;
	screenWidth = ofGetWidth();
	
	diagonalPenalty = 2;//penalises diagonal so all path gradients equal weighting
	
	initialiseVariables();
	
	
}


void testApp::calculateSimilarityAndAlignment(){
	//here is the main TimeWarp similarity matrix calc, the minimum alignment matrix via dtw and then the backwards path estimate 

//	tw.calculateSimilarityMatrixWithPointers(tw.chromaMatrix, tw.secondMatrix, &tw.similarityMatrix);	
//	tw.calculateAlignmentMatrix(tw.chromaMatrix, tw.secondMatrix, &tw.alignmentMeasureMatrix);
	
	tw.calculateSimilarityMatrixWithPointers(tw.firstChromaEnergyMatrix, tw.secondChromaEnergyMatrix, &tw.similarityMatrix);
	tw.calculateAlignmentMatrix(tw.firstChromaEnergyMatrix, tw.secondChromaEnergyMatrix, &tw.alignmentMeasureMatrix);								
	tw.calculateMinimumAlignmentPath(tw.alignmentMeasureMatrix);

	int hopsize = 200;
	int startFrameY = 0;
	for (int startFrameX = 0;startFrameX < 400;startFrameX += hopsize){
	tw.calculatePartSimilarityMatrix(tw.firstChromaEnergyMatrix, tw.secondChromaEnergyMatrix, &tw.tmpSimilarityMatrix, startFrameX, startFrameY, startFrameX+400);
	tw.calculateAlignmentMatrix(tw.firstChromaEnergyMatrix, tw.secondChromaEnergyMatrix, &tw.tmpAlignmentMeasureMatrix);
	tw.calculateMinimumAlignmentPath(tw.tmpAlignmentMeasureMatrix);
	tw.extendForwardAlignmentPath(200);
	}
	
//	tw.calculatePartMinimumAlignmentPath(0, 0, 100, 100, &tw.partAlignmentMeasureMatrix);

	printf("ENERGY SIZE:%i, SIM SIZE:%i\n",(int)tw.firstEnergyVector.size(), (int)tw.similarityMatrix.size());
	conversionFactor = (int)(tw.firstEnergyVector.size() / tw.similarityMatrix.size());
	printf("CONVERSION factor %i\n", conversionFactor);
	chromoLength = scrollWidth / conversionFactor;// CHROMA_CONVERSION_FACTOR;
}

void testApp::initialiseVariables(){
	
	chromaIndex = 0;
//	chromoGramm.initialise(FRAMESIZE,2048);//framesize 512 and hopsize 2048
	audioPosition = 0;
	
	backwardsAlignmentIndex = tw.backwardsAlignmentPath[0].size()-1;//go back to beginning for drawing
	numberOfScrollWidthsForFirstFile = 0;
	numberOfScrollWidthsForSecondFile = 0;
	
	(*playingAudio).setPaused(true);	
	audioPlaying = false;
	audioPaused = true;
	
	tw.initialiseVariables();
}


//--------------------------------------------------------------
void testApp::update(){
	textString = "energy index [";
	textString += ofToString(xIndex);
	textString += "] = ";
	textString += ofToString(energy[xIndex]);
	
//	chordString = "Chord : ";
//	chordString += ofToString(rootChord[currentPlayingFrame/conversionFactor]);//CHROMA_CONVERSION_FACTOR]);
	
	if (firstAudioFilePlaying){
	audioPosition = (*playingAudio).getPosition() * tw.firstEnergyVector.size();
		updateAlignmentPathIndex(0);
	}
	else {
	audioPosition = (*playingAudio).getPosition() * tw.secondEnergyVector.size();	
		updateAlignmentPathIndex(1);
	}
	
	//if(!audioPaused)
	//printScoreForRow(audioPosition/CHROMA_CONVERSION_FACTOR, (audioPosition/CHROMA_CONVERSION_FACTOR)+10);

	
	currentPlayingFrame = audioPosition;
	audioPosition = (int) audioPosition % scrollWidth ;
	audioPosition /= scrollWidth;
	
	ofSoundUpdate();
	
	
}

void testApp::updateAlignmentPathIndex(int identifier){

	//this is the alignment where we are currently playing - i.e. switching between files
	
	int chromaPosition = audioPosition/conversionFactor;//CHROMA_CONVERSION_FACTOR;
	
	while (tw.backwardsAlignmentPath[identifier][backwardsAlignmentIndex] < chromaPosition)
	{
		backwardsAlignmentIndex--;
	}
	
}

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

	if (drawSimilarity)
		drawSimilarityMatrix();
	else
	drawChromoGram();

		
}


void testApp::drawEnergyVectorFromPointer(DoubleVector* energyVec){
	
	float screenHeight = ofGetHeight() ;
	float screenWidth = ofGetWidth();  
	float heightFactor = 1;
	int i, j, startingFrame;
	startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
	startingFrame *= scrollWidth;
	
	for (i = 0; i < scrollWidth - 1; i++){
		j = min(i + startingFrame, (int)energyVec->size()-1);
		ofLine(i*screenWidth/scrollWidth, screenHeight - ((*energyVec)[j]*screenHeight/heightFactor),
			   screenWidth*(i+1)/scrollWidth, screenHeight - ((*energyVec)[j+1]*screenHeight/heightFactor));
		
	}
}

void testApp::drawSpectralDifference(DoubleMatrix* dMatrix){
	if ((*dMatrix).size()>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 /= conversionFactor;// CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
	
	
	for (i = 1; i < chromoLength; i++){//changed to add 1
		j = min(i + startingFrame, (int) dMatrix->size()-1 );//in case out of range
		for (int y = 0;y < 12;y++){			
			difference = (*dMatrix)[j][11-y] - (*dMatrix)[j-1][11-y];
				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");
	}
	
}


void testApp::drawChromoGram(){
	
	DoubleMatrix* dptr;
	DoubleVector* eptr;
	string whichFileString;
	
	if (drawSecondMatrix){
		
		dptr = &tw.secondMatrix;
		eptr = &tw.secondEnergyVector;

		whichFileString = "second file";
		
	}else {
		
		dptr = &tw.chromaMatrix;
		eptr = &tw.firstEnergyVector;
		whichFileString = "first file";
	}
	
	
	
	if (drawSpectralDifferenceFunction)
		drawSpectralDifference(dptr);
	else
		drawDoubleMatrix(dptr);
	
	ofSetColor(0xFF6666);
	drawEnergyVectorFromPointer(eptr);
	
	ofDrawBitmapString(textString,80,480);
	
	
	ofSetColor(0xFFFFFF);
	ofLine(audioPosition*width, 0, audioPosition*width, height);
	
	 
	ofDrawBitmapString(chordString,80,580);
	
	ofDrawBitmapString(soundFileName,80,480);
	
	ofDrawBitmapString(whichFileString,80,80);

}

void testApp::drawDoubleMatrix(DoubleMatrix* dMatrix){
	if ((*dMatrix).size()>0){
			
	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 /= conversionFactor;//CHROMA_CONVERSION_FACTOR; //in terms of chroma frames
	
		float chromoLength = scrollWidth/conversionFactor;// CHROMA_CONVERSION_FACTOR;
	for (i = 0; i < chromoLength; i++){
		j = min(i + startingFrame, (int) dMatrix->size()-1 ) ;
		for (int y = 0;y < 12;y++){
			ofSetColor(0,0,255 * (*dMatrix)[j][11-y]);//, 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::drawSimilarityMatrix(){

	int simHeight = (tw.similarityMatrix[0]).size();
	int simWidth = tw.similarityMatrix.size();
	
	int sizeOfMatrix = (int) tw.similarityMatrix.size();//tw.chromaMatrix.size();
	int sizeOfSecondMatrix = (int) tw.similarityMatrix[0].size();
	
	int startingXframe = tw.backwardsAlignmentPath[0][backwardsAlignmentIndex] / (scrollWidth/conversionFactor);
	int startingYframe = tw.backwardsAlignmentPath[1][backwardsAlignmentIndex] / (scrollWidth/conversionFactor);
	
	int startingFrame = findStartWidthFrame();
	startingFrame = numberOfScrollWidthsForFirstFile * scrollWidth/conversionFactor;
	
	startingXframe = startingXframe * scrollWidth/conversionFactor;
	startingYframe = startingYframe * scrollWidth/conversionFactor;
	//need to fix for second file too
	
	int *indexOfAlignmentPathTested;
	int lengthOfPath = tw.backwardsAlignmentPath[0].size()-1;
	indexOfAlignmentPathTested = &lengthOfPath;
	
	int xcoord;
	for (int x = 0;x < screenWidth;x++)
	{
		for (int y =0;y < screenHeight;y++){
		
			xcoord = (x / screenWidth) * chromoLength;//was simWidth
			//xcoord += startingFrame;
			xcoord += startingXframe;
			
			int ycoord = y * chromoLength/ screenHeight;
			//ycoord += startingFrame;
			ycoord += startingYframe;
			
			int colour = 0;
			//int ycoord = y * simHeight/ screenHeight;
			//y += startingFrame;
			if (xcoord < sizeOfMatrix && ycoord < sizeOfSecondMatrix)
			colour = tw.similarityMatrix[xcoord][ycoord]*255;
			

		 ofSetColor(colour,0,0);
		
		ofRect(x,y,1,1);
			
		}
	}
	
	drawAlignmentPath(startingXframe, startingYframe);
	drawForwardsAlignmentPath(startingXframe, startingYframe);
	
	//SET TEXT
	string textString;
	textString = "width : ";
	textString += ofToString(simWidth);
	
	textString += "  height : ";
	textString += ofToString(simHeight);
	
	textString += "  startframe : ";
	textString += ofToString(startingFrame);

	textString += "  Xframe : ";
	textString += ofToString(startingXframe);

	textString += "  Yframe : ";
	textString += ofToString(startingYframe);
	
	textString += "  currentFrame : ";
	textString += ofToString(currentPlayingFrame);

	textString += "  scrollwidth: ";
	textString += ofToString(scrollWidth);

	textString += "  xcoord: ";
	textString += ofToString(xcoord);

	textString += "  Clength: ";
	textString += ofToString(chromoLength);

	textString += "  no.Scrolls: ";
	textString += ofToString(numberOfScrollWidthsForFirstFile);
	//END SET TEXT
	
	ofSetColor(0x0000FF);
	if (firstAudioFilePlaying){
	ofLine(audioPosition*screenWidth, 0, audioPosition*screenWidth, height);
		checkIfAudioPositionExceedsWidthForFirstFile();	
		
			//draw values:
		xcoord = currentPlayingFrame / conversionFactor;
		ofSetColor(255, 255, 255);
			for (int y = 0;y < chromoLength; y+=max(1, (int)(20 * chromoLength / screenHeight))){
		
				float value = tw.alignmentMeasureMatrix[xcoord][y+startingYframe];
				int ycoord = y * screenHeight/chromoLength;
				ofDrawBitmapString(ofToString(value, 2) , audioPosition*screenWidth , ycoord);
			}
	}
	else{
	ofLine(0, audioPosition*screenHeight, screenWidth, audioPosition*screenHeight);	
	}
		
	ofDrawBitmapString(textString,80,580);
	
	ofDrawBitmapString(userInfoString,80,80);
	
}


void  testApp::checkIfAudioPositionExceedsWidthForFirstFile()
{
	if (currentPlayingFrame > scrollWidth*(numberOfScrollWidthsForFirstFile+1))
		numberOfScrollWidthsForFirstFile++;
}

int testApp::findStartWidthFrame(){
	int startingFrame;
		startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in
		startingFrame *= scrollWidth;//starting frame in terms of energy frames
	startingFrame /= conversionFactor;// CHROMA_CONVERSION_FACTOR; 

 return startingFrame;
}

void testApp::drawAlignmentPath(int startingChromaXFrame, int startingChromaYFrame){
	//draw alignment path
	int endingChromaXFrame = startingChromaXFrame + chromoLength;
	int endingChromaYFrame = startingChromaYFrame + chromoLength;
	
	float chromoWidth = screenWidth / chromoLength;
	float chromoHeight = screenHeight / chromoLength;
	
	int index = tw.backwardsAlignmentPath[0].size()-1;
	//OPTIMISE XXX

	
	while (tw.backwardsAlignmentPath[0][index] < startingChromaXFrame){
		index --;
	}
	
	int printIndex = index;
	int backAlign = tw.backwardsAlignmentPath[0][index];
	int printxcoord;
	int xcoord;
	
	while (tw.backwardsAlignmentPath[0][index] < endingChromaXFrame) {
		xcoord = min((int)(tw.similarityMatrix.size())-1,tw.backwardsAlignmentPath[0][index]);
		int ycoord = min((int)tw.backwardsAlignmentPath[1][index], (int)(tw.alignmentMeasureMatrix[0].size())-1);
		
		printxcoord = xcoord;
		int colour = tw.similarityMatrix[xcoord][ycoord]*255;
		
		float value = tw.alignmentMeasureMatrix[xcoord][ycoord] ;
		
								
		xcoord -= startingChromaXFrame;
		ycoord -= startingChromaYFrame;
		ofSetColor(0,0,colour);
		ofRect(xcoord*chromoWidth, ycoord*chromoHeight, chromoWidth, chromoHeight);
//		ofSetColor(255, 255, 255);
//		ofDrawBitmapString(ofToString(value, 2), xcoord*chromoWidth, ycoord*chromoHeight);
		index--;
	}
	
//	drawHoverAlignmentValues();
//	printf("ALIGN score :[%i] : %f \n", backwardsAlignmentPath[1][backwardsAlignmentIndex], alignmentMeasureMatrix[ backwardsAlignmentPath[0][backwardsAlignmentIndex] ][ (int) backwardsAlignmentPath[1][backwardsAlignmentIndex] ]);

	
	//SET TEXT
	string textString;
	textString = "ALIGNMENT PATH  ";
	
	textString += "backward A index ";
	textString += ofToString(backwardsAlignmentIndex);
	
	textString += "  starting X frame ";
	textString += ofToString(startingChromaXFrame);
	
	textString += "  initial xcoord ";
	textString += ofToString(printxcoord);
	
	textString += "  first index ";
	textString += ofToString(printIndex);

	textString += "  backalign[index] ";
	textString += ofToString(backAlign);
	
	textString += "  final xcoord ";
	textString += ofToString(xcoord);
	
	
	
	
	ofSetColor(255,255,255); 
	ofDrawBitmapString(textString,80,640);
	
}







void testApp::drawForwardsAlignmentPath(int startingChromaXFrame, int startingChromaYFrame){
	if (tw.forwardsAlignmentPath.size() > 0){
	int endingChromaXFrame = startingChromaXFrame + chromoLength;
	int endingChromaYFrame = startingChromaYFrame + chromoLength;
	
	float chromoWidth = screenWidth / chromoLength;
	float chromoHeight = screenHeight / chromoLength;
	
	int index = 0;
	//OPTIMISE XXX
	
	while (tw.forwardsAlignmentPath[0][index] < startingChromaXFrame){
		//get to NOW
		index ++;
	}
		
//	int printIndex = index;
//	int forwardsAlign = tw.forwardsAlignmentPath[0][index];
//	int printxcoord;
	int xcoord;
	
	while (index < tw.forwardsAlignmentPath[0].size() && tw.forwardsAlignmentPath[0][index] < endingChromaXFrame) {
		xcoord = min((int)(tw.similarityMatrix.size())-1,tw.forwardsAlignmentPath[0][index]);
		int ycoord = min((int)tw.forwardsAlignmentPath[1][index], (int)(tw.alignmentMeasureMatrix[0].size())-1);
		
//		printxcoord = xcoord;
		int colour = 255;//tw.similarityMatrix[xcoord][ycoord]*255;
		//float value = tw.alignmentMeasureMatrix[xcoord][ycoord] ;
		
		xcoord -= startingChromaXFrame;
		ycoord -= startingChromaYFrame;
		ofSetColor(0,colour,0);
		ofRect(xcoord*chromoWidth, ycoord*chromoHeight, chromoWidth, chromoHeight);
		index++;
	}//end while
		
	}//end if forwards path exista
	
}






void testApp::loadSoundFiles(){
		
		//assume libsndfile looks in the folder where the app is run
		//therefore ../../../ gets to the bin folder
		//we then need data/sounds/to get to the sound folder
		//this is different to the usual OF default folder
	//was const char	
	const char	*infilename = "../../../data/sound/Bach_short1.wav";	
	loadLibSndFile(infilename);

	string loadfilename = "sound/Bach_short1.wav";//PicturesMixer6.aif";	
	loadedAudio.loadSound(loadfilename);
	playingAudio = &loadedAudio;

}

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 opened file %s okay.\n", infilename);
		sndfileInfoString = "Opened okay ";
		
	};
	
}

void testApp::processAudioToDoubleMatrix(DoubleMatrix* myDoubleMatrix, DoubleVector* energyVector){
	//wendy
	myDoubleMatrix->clear();
	energyVector->clear();

	
	
	chromaG.initialise(FRAMESIZE, CHROMAGRAM_FRAMESIZE);//framesize 512 and hopsize 2048 - already done
	chromaG.maximumChromaValue = 1;
	double maximumEnergyValue = 1;
	
	int readcount = 1; // counts number of samples read from sound file
	printf("processing audio from doublematrix \n");
			printf("readcount %i", readcount);
	while(readcount != 0 && moveOn == true)
	{
		
		// read FRAMESIZE samples from 'infile' and save in 'data'
		readcount = sf_read_float(infile, frame, FRAMESIZE);
		
		double doubleFrame[FRAMESIZE];
		for (int k = 0;k< FRAMESIZE;k++){
			doubleFrame[k] = frame[k];
		}
		
		
		
		//8192 samples per chroma frame  //processing frame - downsampled to 11025Hz
		chromaG.processframe(frame);
		
		if (chromaG.chromaready)
		{
				DoubleVector d;
				
				for (int i = 0;i<12;i++){
					d.push_back(chromaG.rawChroma[i]);// / chromaG->maximumChromaValue);	
					
				}	
				//this would do chord detection
				
				myDoubleMatrix->push_back(d);
				//so now is storing at d[i][current_index]
			
		}//end if chromagRamm ready
		
		
	//	double energyValue = getEnergyOfFrame();
		double energyValue = onset->getDFsample(doubleFrame);
		energyVector->push_back(energyValue);
		if (energyValue > maximumEnergyValue)
			maximumEnergyValue = energyValue;
		
		
	}//end while readcount
	
	printf("Max chroma value is %f \n", chromaG.maximumChromaValue);
	printf("length of chromagram is %d frames\n", (int)myDoubleMatrix->size());
	printf("height of dmatrix is %d\n", (int)(*myDoubleMatrix)[0].size());
	//normalise chroma matrix	
	for (int i = 0; i < myDoubleMatrix->size();i++){
		for (int j = 0; j < ((*myDoubleMatrix)[0]).size();j++){
			//non-causal normalisation
			(*myDoubleMatrix)[i][j] /= chromaG.maximumChromaValue;	
		}
	}
	

	printf("size of energy vector is %d \n", (int)energyVector->size());	
	//non causal normalisation
	for (int i = 0; i < energyVector->size();i++){
		(*energyVector)[i] /= maximumEnergyValue;
	}
	
//	totalNumberOfFrames = (int)energyVector->size();
	chromaConversionRatio = myDoubleMatrix->size() / (int)energyVector->size();
	
//	int size = myDoubleMatrix->size() * CHROMA_CONVERSION_FACTOR;
	
}


//--------------------------------------------------------------
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 == OF_KEY_DOWN){
		if (scrollWidth > 600)
		scrollWidth += 400;
		else
		scrollWidth *= 2;
		
		chromoLength = scrollWidth/conversionFactor;// CHROMA_CONVERSION_FACTOR;
	}
	
	if (key == OF_KEY_UP){
		if (scrollWidth > 600)
		scrollWidth -= 400;
		else
		scrollWidth /= 2;
		
		chromoLength = scrollWidth/conversionFactor;// CHROMA_CONVERSION_FACTOR;
	}

	if (key == OF_KEY_LEFT){
		
		(*playingAudio).setSpeed(-4);
		backwardsAlignmentIndex = tw.backwardsAlignmentPath[0].size()-1;
	}

	if (key == OF_KEY_RIGHT){
		
		(*playingAudio).setSpeed(4);
	}
	
	if (key == OF_KEY_RETURN){
		loadedAudio.stop();
		audioPlaying = false;
		audioPaused = true;
		initialiseVariables();
	}
	
		if (key == ' '){
			if (!audioPlaying) {
				(*playingAudio).play();
				(*playingAudio).setPaused(false);
				secondAudio.play();
				secondAudio.setPaused(true);
				
				firstAudioFilePlaying = true; 
				
				audioPlaying = true;
				audioPaused = false;
			}
			else{
			audioPaused = !audioPaused;
			(*playingAudio).setPaused(audioPaused);
			}
		
		}
	
	if (key == 'p'){
		swapBetweenPlayingFilesUsingAlignmentMatch();
		
		}
	
	if (key == 'o'){
		openNewAudioFileWithdialogBox();
	}
	
	if (key == 'l'){
		//open audio file
		string *filePtr, secondFileName;
		filePtr = &secondFileName;
		//so filePtr points to secondFileName
		
		if (getFilenameFromDialogBox(filePtr)){
			printf("Loaded name okay :\n'%s' \n", secondFileName.c_str());	
		 }
		
		loadSecondAudio(secondFileName);
		
		calculateSimilarityAndAlignment();

	}
	
	if (key == 's'){
		drawSimilarity = !drawSimilarity;
	}
	
	
	if (key == 'm'){
		drawSecondMatrix = !drawSecondMatrix;
	}
	
	if (key == 'd'){
		drawSpectralDifferenceFunction = !drawSpectralDifferenceFunction;
	}
	
}

//--------------------------------------------------------------
void testApp::keyReleased  (int key){
	if (key == OF_KEY_LEFT || OF_KEY_RIGHT){
		(*playingAudio).setSpeed(1);
		backwardsAlignmentIndex = tw.backwardsAlignmentPath[0].size()-1;
	}
	
}

void testApp::openNewAudioFileWithdialogBox(){
	
	//open audio file
	string *filePtr;
	filePtr = &soundFileName;	
	
	if (getFilenameFromDialogBox(filePtr)){
		printf("Mainfile: Loaded name okay :\n'%s' \n", soundFileName.c_str());	
	}
	
	//openFileDialogBox(); - replaced this lone by call to openFile Dialoguebox
	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);
	targetFrequency = 2000.0f * heightPct;
	phaseAdderTarget = (targetFrequency / (float) sampleRate) * TWO_PI;
	xIndex = (int)(pan*ENERGY_LENGTH);
}

//--------------------------------------------------------------
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;
	screenHeight = ofGetHeight() ;
	screenWidth = ofGetWidth();
	
}
//--------------------------------------------------------------
void testApp::audioRequested 	(float * output, int bufferSize, int nChannels){
	//pan = 0.5f;
	float leftScale = 1 - pan;
	float rightScale = pan;

	// sin (n) seems to have trouble when n is very large, so we
	// keep phase in the range of 0-TWO_PI like this:
	while (phase > TWO_PI){
		phase -= TWO_PI;
	}


}


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


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 cancelled. ";
	}
	
	

}


void testApp::loadNewAudio(string soundFileName){

	loadedAudio.loadSound(soundFileName);
	
	//snd file method
	const char	*infilename = soundFileName.c_str() ;
	
	loadLibSndFile(infilename);
	
	loadFirstAudioFile();
	
	audioPlaying = false;
}



void testApp::loadFirstAudioFile(){
/*
 Chromagram* cptr;
	DoubleMatrix* dptr;
	DoubleVector* eptr;
	
	cptr = &(tw.chromoGramm);
	dptr = &(tw.chromaMatrix);
	eptr = &(tw.firstEnergyVector);
	*/
	processAudioToDoubleMatrix(&tw.chromaMatrix, &tw.firstEnergyVector);
	tw.createCombinedMatrix(tw.chromaMatrix, tw.firstEnergyVector, &tw.firstChromaEnergyMatrix);
	
}

void testApp::loadSecondAudio(string soundFileName){

	secondAudio.loadSound(soundFileName);

	const char	*infilename = soundFileName.c_str() ;	
	loadLibSndFile(infilename);

/*	Chromagram* cptr;
	DoubleMatrix* dptr;
	DoubleVector* eptr;
	cptr = &(tw.secondChromoGramm);
	dptr = &(tw.secondMatrix);
	eptr = &(tw.secondEnergyVector);
 */
	
	processAudioToDoubleMatrix(&tw.secondMatrix, &tw.secondEnergyVector);//dptr, eptr);//chromaMatrix);
	tw.createCombinedMatrix(tw.secondMatrix, tw.secondEnergyVector, &tw.secondChromaEnergyMatrix);
	
}



void testApp::swapBetweenPlayingFilesUsingAlignmentMatch(){
	ofSoundUpdate();
	//swapping between files
	//printf("current playing (energy scale) frame was %i \n", currentPlayingFrame);
	float oldPosition = (*playingAudio).getPosition();
	printf("playing position is %f \n", (*playingAudio).getPosition());

	//(*playingAudio).stop(); 
	(*playingAudio).setPaused(true);
	int newIndicator;
	if (firstAudioFilePlaying){
		playingAudio = &secondAudio;
		newIndicator = 1;	
		}
	else{
		playingAudio = &loadedAudio;
		newIndicator = 0;
		}
	
	printf("new indicator %i \n", newIndicator);
	printf("playing pos according to energy frames is %f \n ", 
		   (currentPlayingFrame/((float)tw.backwardsAlignmentPath[1-newIndicator][0]*  conversionFactor)) );//CHROMA_CONVERSION_FACTOR
	printf("predicts frame to be %f \n", (oldPosition*tw.backwardsAlignmentPath[1-newIndicator][0]));
	
	currentChromaFrame = oldPosition * (float) tw.backwardsAlignmentPath[1-newIndicator][0];
	printf("current chroma frame %i and using energy frames would have been %i \n", currentChromaFrame, currentPlayingFrame / conversionFactor);//CHROMA_CONVERSION_FACTOR);

	int matchingFrame = findMatchFromAlignment(firstAudioFilePlaying);		
	float relativePosition = matchingFrame / (float) tw.backwardsAlignmentPath[newIndicator][0];
	//i.e. the position as float [0,1] 0:beginning, 1 is end
	
	(*playingAudio).setPaused(false);
	(*playingAudio).setPosition(relativePosition);
	
	printf("matching frame is %i and length is %i \n", matchingFrame, tw.backwardsAlignmentPath[newIndicator][0]);
	printf("new playing position is %f \n", (*playingAudio).getPosition());
	
	firstAudioFilePlaying = !firstAudioFilePlaying;
	
	
}

int testApp::findMatchFromAlignment(bool whichFileToTest){
	//could use technique from middle of file and go either way to reduce latency for long search? 
	//- (not that this is a problem yet)
	int indicator;
	if (whichFileToTest)
		indicator = 0;
		else
		indicator = 1;

	int oppositeIndicator = 1 - indicator;
  
	int frame = tw.backwardsAlignmentPath[indicator].size()-1;

	
	while (tw.backwardsAlignmentPath[indicator][frame] < currentChromaFrame){
		frame--;
	}
	//printf("frame found is %i \n", frame);
	int frameToSwitchTo = tw.backwardsAlignmentPath[oppositeIndicator][frame];
	
	float calculatedPosition = (currentChromaFrame / (float) tw.backwardsAlignmentPath[indicator][0]);
	
	printf("(length was %i)\n",  tw.backwardsAlignmentPath[indicator][0]);
	
	printf("compares to position calculated from chroma length %f \n", calculatedPosition);
	printf("current frame %i maps to new frame %i \n", currentChromaFrame, frameToSwitchTo);
	printf("relative position of new frame is %f \n", (frameToSwitchTo / (float) tw.backwardsAlignmentPath[oppositeIndicator][0]) );
	return frameToSwitchTo; 

}

void testApp::printSimilarityMatrix(int sizeToPrint){
	
	printf("\n _ _ _ _\n");
	printf("Similarity Matrix \n");
	int i,j;
	DoubleVector d;
	int rowSize = sizeToPrint;
	
	for (int j = 0;j < rowSize;j++){
		printf("row %i : ", j);
		
		for (i = 0;i < rowSize;i++){			
			printf("%f , ", tw.similarityMatrix[i][j] );
		}
		printf("\n");
	}
	printf("...............\n");
	
}


void testApp::printAlignmentMatrix(){
	
	int size = tw.alignmentMeasureMatrix.size();
printf("\n _ _ _ _\n");
printf("align size is %i \n", size);
	
	int i,j;
	DoubleVector d;
	int rowSize = tw.alignmentMeasureMatrix.size();
	d = tw.alignmentMeasureMatrix[0];//choose initial size

	for (int j = 0;j < d.size();j++){
		printf("row %i : ", j);
		
		for (i = 0;i < rowSize;i++){
		d = tw.alignmentMeasureMatrix[i];
		
		//	printf("row %i , col %i, val : %f \n", i, j, alignmentMeasureMatrix[i][j] );
			printf("%f , ", tw.alignmentMeasureMatrix[i][j] );
		}
		printf("\n");
	}
	printf("...............\n");
	
}


void testApp::printScoreForRow(int row, int max){
	printf("alignment scores row %i \n", row);
	float minimum = tw.alignmentMeasureMatrix[row][0];
	int minimumIndex = 0;
	for (int i =0;i < max;i++){
		printf("[%i] %f ", i, tw.alignmentMeasureMatrix[row][i]);
		if (tw.alignmentMeasureMatrix[row][i] < minimum)
		{
			minimum = tw.alignmentMeasureMatrix[row][i] ;
			minimumIndex = i;
		}
		printf(" \n");
			}
	printf("Minimum [%i] : %f \n", minimumIndex, minimum);
	printf("ALIGN score :[%i] : %f \n", tw.backwardsAlignmentPath[1][backwardsAlignmentIndex], tw.alignmentMeasureMatrix[tw.backwardsAlignmentPath[0][backwardsAlignmentIndex] ][ (int) tw.backwardsAlignmentPath[1][backwardsAlignmentIndex] ]);
 
}













/*
 void testApp::calculateSimilarityMatrix(){
 similarityMatrix.clear();
 printf("calculating similarity matrix...");
 userInfoString = "calculating similarity matrix...";
 
 double distance, firstSum, secondSum;
 
 for (int x = 0;x < tw.chromaMatrix.size();x++){
 DoubleVector d;
 for (int y = 0;y < tw.secondMatrix.size();y++){
 
 //d.push_back( drand48() );	
 
 distance = 0;
 firstSum = 0;
 secondSum = 0;
 for (int z = 0;z < chromaMatrix[x].size();z++){//z is the twelve chromagram values
 
 distance += chromaMatrix[x][z] * secondMatrix[y][z];
 
 firstSum += chromaMatrix[x][z] * chromaMatrix[x][z];
 secondSum += secondMatrix[y][z] * secondMatrix[y][z];
 }
 
 if (firstSum > 0 && secondSum > 0)
 distance /= sqrt(firstSum * secondSum);
 
 
 d.push_back( distance);	
 
 }	//end for y
 
 similarityMatrix.push_back(d);
 
 }//end for x
 userInfoString += "; size =";
 userInfoString += ofToString(similarityMatrix.size() , 0);
 printf("..sim size: %i, height: %i \n", similarityMatrix.size(), (chromaMatrix[0]).size());
 
 }//end self sim
 
 */
/*
 void testApp::calculateAlignmentMatrix(){
 
 //initialise alignment
 alignmentMeasureMatrix.clear();
 DoubleVector d;
 d.push_back(getDistance(0,0));
 alignmentMeasureMatrix.push_back(d);
 
 bool chromaCalculated = false;
 bool secondCalculated = false;
 
 while (!chromaCalculated || !secondCalculated) {
 
 if (!chromaCalculated)
 chromaCalculated = extendAlignmentAlong();
 
 if (!secondCalculated)
 secondCalculated = extendAlignmentUp();
 
 }
 
 }
 
 bool testApp::extendAlignmentUp(){
 DoubleVector d;
 d = alignmentMeasureMatrix[0];
 int heightSize = d.size();
 if (heightSize < secondMatrix.size()){
 //then we haven't finished yet
 for (int i = 0;i < alignmentMeasureMatrix.size();i++){
 double value = getDistance(i, heightSize);
 value += getMinimum(i, heightSize, value);	
 alignmentMeasureMatrix[i].push_back(value);
 }
 }
 if (alignmentMeasureMatrix[0].size() == secondMatrix.size())
 return true;
 else
 return false;
 
 }
 
 
 bool testApp::extendAlignmentAlong(){
 DoubleVector d;
 int widthSize = alignmentMeasureMatrix.size();
 if (widthSize < chromaMatrix.size()){
 //then we can extend along
 double value = getDistance(widthSize, 0);
 value += getMinimum(widthSize, 0, value);
 
 d.push_back(value);
 alignmentMeasureMatrix.push_back(d);
 
 for (int j = 1;j < alignmentMeasureMatrix[widthSize - 1].size();j++){
 value = getDistance(widthSize, j);
 value += getMinimum(widthSize, j, value);
 alignmentMeasureMatrix[widthSize].push_back(value);
 }
 
 //alignmentMeasureMatrix.push_back(d);
 }
 
 if (alignmentMeasureMatrix.size() == chromaMatrix.size())
 return true;
 else
 return false;
 
 }
 
 
 void testApp::calculateMinimumAlignmentPath(){
 //this requires one pass of the DTW algorithm and then works backwards from (N,M)
 //to find the optimal path to (0,0), where N and M are the lengths of the two chromoVectors respectively
 //minimumAlignmentPath.clear();
 backwardsAlignmentPath.clear();
 
 printf("Finding minimum Path \n");
 IntVector v;
 v.push_back(chromaMatrix.size()-1);
 backwardsAlignmentPath.push_back(v);
 v.clear();
 v.push_back(secondMatrix.size()-1);
 backwardsAlignmentPath.push_back(v);
 //so now backwards path[0][0] = size(chroma) and path[1][0] = size(secondMatrix)
 printf("backwards path %i : %i \n", backwardsAlignmentPath[0][0], backwardsAlignmentPath[1][0]);
 
 
 int indexOfBackwardsPath = 0;
 while (!findPreviousMinimumInBackwardsPath())	{
 indexOfBackwardsPath++;
 printf("backwards path %i : %i \n", backwardsAlignmentPath[0][indexOfBackwardsPath], backwardsAlignmentPath[1][indexOfBackwardsPath]);
 
 }
 //printf("final index of backwards path is %i and i is %i \n", backwardsAlignmentPath[0].size()-1, indexOfBackwardsPath);
 
 backwardsAlignmentIndex = backwardsAlignmentPath[0].size()-1;//remember that this goes backwards!
 
 }
 
 
 bool testApp::findPreviousMinimumInBackwardsPath(){
 int chromaPosition, secondPosition;
 int i,j;
 i = backwardsAlignmentPath[0][backwardsAlignmentPath[0].size()-1];
 j  = backwardsAlignmentPath[1][backwardsAlignmentPath[1].size()-1];
 
 double newMinimum;
 double *ptr;
 ptr = &newMinimum;
 newMinimum = alignmentMeasureMatrix[i][j];
 DoubleVector d;
 
 
 bool finishedAligning = true;
 
 if (i > 0){
 if (testForNewAlignmentMinimum(ptr, i-1, j)){
 chromaPosition = i-1;
 secondPosition = j;
 finishedAligning = false;
 }
 
 if (j>0 && testForNewAlignmentMinimum(ptr, i-1, j-1)){
 chromaPosition = i-1;
 secondPosition = j-1;
 finishedAligning = false;
 }
 }
 
 if (j > 0 && testForNewAlignmentMinimum(ptr, i, j-1)){
 chromaPosition = i;
 secondPosition = j-1;
 //newMinimum = alignmentMeasureMatrix[chromaPosition][secondPosition];
 finishedAligning = false;
 }
 
 if (!finishedAligning){
 backwardsAlignmentPath[0].push_back(chromaPosition);
 backwardsAlignmentPath[1].push_back(secondPosition);
 }
 
 return finishedAligning;
 
 }	
 
 
 
 bool testApp::testForNewAlignmentMinimum(double *previousMinimum, int i, int j){
 bool newMinimumFound = false;
 if (alignmentMeasureMatrix[i][j] < *previousMinimum){
 *previousMinimum = alignmentMeasureMatrix[i][j];							   
 newMinimumFound = true;
 }
 
 return newMinimumFound;							   
 }		
 */ 


/*
 int testApp::findMinimumOfVector(DoubleVector *d){
 int minimumIndex = 0;
 double minimumValue = (*d)[0];
 for (int i = 0;i < d->size();i++){
 if ((*d)[i] < minimumValue){
 minimumIndex = i;
 minimumValue = (*d)[i];
 }
 }
 
 return minimumIndex;
 }
 */
/*
 double testApp::getDistance(int i, int j){
 return (1 - similarityMatrix[i][j]);
 }
 
 double testApp::getMinimum(int i, int j, float newValue){
 double minimumValue = 0;
 
 if (i > 0){
 minimumValue = tw.alignmentMeasureMatrix[i-1][j];
 if (j > 0){
 minimumValue = min(minimumValue, alignmentMeasureMatrix[i-1][j-1] + newValue ) ;//penalises diagonal by 2
 minimumValue = min(minimumValue, alignmentMeasureMatrix[i][j-1]);
 }
 }
 else{//i.e. i == 0 
 if (j > 0)
 minimumValue = tw.alignmentMeasureMatrix[i][j-1];
 }
 
 return minimumValue;
 }
 
 */