view src/TempoFollower.cpp @ 55:2eca10a31ae2

improving printing of information, looking at how tempo is modelled
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Mon, 10 Dec 2012 17:07:21 +0000
parents 93d21c20cfbc
children
line wrap: on
line source
/*
 *  TempoFollower.cpp
 *  MultipleAudioMathcher
 *
 *  Created by Andrew on 09/02/2012.
 *  Copyright 2012 QMUL. All rights reserved.
 *
 */

#include "TempoFollower.h"

TempoFollower::TempoFollower(){
	
	
	
	
	maximumTempoInterval = 600;
	minimumTempoInterval = 200;
	tempoArraySize = maximumTempoInterval - minimumTempoInterval;;
	
	tempoPrior.createVector(tempoArraySize);
	tempoPosterior.createVector(tempoArraySize);
	tempoLikelihood.createVector(tempoArraySize);
	
	tempoPosterior.addConstant(1);
	
	tempoPrior.offset = minimumTempoInterval;
	tempoPosterior.offset = minimumTempoInterval;
	tempoLikelihood.offset = minimumTempoInterval;
	
	tempoPrior.scalar = 1;
	tempoPosterior.scalar = 1;
	tempoLikelihood.scalar = 1;

	intervalsToTest[0] = 1;
	intervalsToTest[1] = 2;
	intervalsToTest[2] = 4;
	intervalsToTest[3] = 8;
	intervalsToTest[4] = 16;
	
	setUpEventTimeMatrix();
}

void TempoFollower::zero(){
	eventTimes.clear();
	tempoIntervals.clear();
	divisions.clear();
	tempo.clear();
	globalTempo.clear();
	globalTempoTimes.clear();
	setUpEventTimeMatrix();
}

void TempoFollower::reset(){
	printf("reset temporal follower\n");
	tempoPrior.zero();
	tempoPosterior.addConstant(1);

}


void TempoFollower::setUpEventTimeMatrix(){
	for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
		IntVector v;
		eventTimes.push_back(v);
		
		DoubleMatrix m;	
		tempoIntervals.push_back(m);
		
		IntMatrix h;
		divisions.push_back(h);
		
		DoubleVector d;
		tempo.push_back(d);
		
	}
	
	//[channel][index]
}



void TempoFollower::printEventTimes(){
	for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
		printf("CHANNEL %i EVENT TIMES...\n", i);
		for (int j = 0;j < eventTimes[i].size();j++)
			printf("%i\n", eventTimes[i][j]);
	}
}


void TempoFollower::printTempoTimes(){

	for (int i = 0;i < globalTempo.size();i++){
		printf("Time %i : tempo %f\n", globalTempoTimes[i], globalTempo[i]);
	}
}

void TempoFollower::updateTempo(const int& channel, const int& timeIn){
	
	eventTimes[channel].push_back(timeIn);
	
	int interval = 0;
	int intervalLimit = 3600;
	
	int recentIndex = eventTimes[channel].size()-1;
	
	DoubleVector d;
	IntVector div;
	int recentEvent = eventTimes[channel][recentIndex];
	
	for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){
		interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i];
		
		for (int k = 0;k < 3;k++){
			
			double divisionInEighthNotes = intervalsToTest[k];
			double testInterval = interval / divisionInEighthNotes;
			if (testTempoInterval(channel, testInterval, d)){
				printf("channel %i interval %i at division %.0f == tempo update %f\n", channel, interval, divisionInEighthNotes, testInterval);
				div.push_back((int)divisionInEighthNotes);
			}
		}
	}
	
	(tempoIntervals[channel]).push_back(d);
	(divisions[channel]).push_back(div);
	updateTempoDistribution(d);
	
	tempo[channel].push_back(playingTempo);
	
	globalTempo.push_back(playingTempo);
	globalTempoTimes.push_back(timeIn);
	
	
}


bool TempoFollower::testTempoInterval(const int& channel, const double& testInterval, DoubleVector& d){

	bool updated = false;
	if (testInterval >= minimumTempoInterval && testInterval <= maximumTempoInterval){
		d.push_back(testInterval);
		updated = true;
	}
	return updated;
}

void TempoFollower::updateTempoDistribution(const DoubleVector& d){
	double tempoLikelihoodToNoiseRatio = 0.8;
	tempoLikelihoodStdDev = 4;
	
	tempoLikelihood.zero();
	double amount = tempoLikelihoodToNoiseRatio/d.size();
	for (int i = 0;i < d.size();i++){
		tempoLikelihood.addGaussianShapeFromRealTime(d[i], tempoLikelihoodStdDev, amount);
	}
	tempoLikelihood.addConstant(0.1*(1-tempoLikelihoodToNoiseRatio));
	calculatePosterior();
	tempoPosterior.renormalise();
	playingTempo = tempoPosterior.getIndexInRealTerms(tempoPosterior.getMAPestimate());
	
}



void TempoFollower::calculatePosterior(){
	tempoPrior.copyFromDynamicVector(tempoPosterior);
	for (int i = 0;i < tempoArraySize;i++){
		tempoPosterior.array[i] = tempoLikelihood.array[i] * tempoPrior.array[i];
	}
}

void TempoFollower::drawTempoArray(ofxWindowRegion& window){
	ofSetColor(150,0,250);
	tempoPosterior.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window);
	
	ofSetColor(150,150,150);
	tempoLikelihood.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window);
	
	if (printOutput)
	ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40);
	

	for (int channel = 0;channel < 3;channel+=2){
		int index = tempoIntervals[channel].size()-1;
		
		for (int i = 0;i < 9 && index - i>=0 ;i++){
			for (int j = 0;j < tempoIntervals[channel][index - i].size();j++){
				ofSetColor(channel*125, 0, 250);
				ofCircle(window.x+((tempoIntervals[channel][index - i][j] - minimumTempoInterval)*window.width)/tempoArraySize, window.y+6+(window.height*i/9.0), 4);
				ofSetColor(255,255,255);
				ofDrawBitmapString(ofToString(divisions[channel][index-i][j]), (window.x+((tempoIntervals[channel][index - i][j] - minimumTempoInterval)*window.width)/tempoArraySize)-3, window.y+8+(window.height*i/9.0));
			}
		}
	}
}