Mercurial > hg > multitrack-audio-matcher
diff src/TempoFollower.cpp @ 19:1a62561bd72d
Added in tempo follower class that models the tempo of played events
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Thu, 09 Feb 2012 18:09:34 +0000 |
parents | |
children | 4f6006cac9de |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/TempoFollower.cpp Thu Feb 09 18:09:34 2012 +0000 @@ -0,0 +1,134 @@ +/* + * 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; +} + + +void TempoFollower::reset(){ + + 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); + } + + //[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::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; + + int recentEvent = eventTimes[channel][recentIndex]; + + for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){ + interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i]; + + if (testTempoInterval(channel, interval, d)) + printf("channel %i interval %i at division 1 == tempo update %i\n", channel, interval, interval); + + for (double divisionInEighthNotes = 2.0;divisionInEighthNotes < 9.0;divisionInEighthNotes+=2){ + + 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); + + } + } + + (tempoIntervals[channel]).push_back(d); + updateTempoDistribution(d); + +} + + +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; + tempoLikelihood.zero(); + double amount = tempoLikelihoodToNoiseRatio/d.size(); + for (int i = 0;i < d.size();i++){ + tempoLikelihood.addGaussianShapeFromRealTime(d[i], 10, 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); + ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40); +}