Mercurial > hg > multitrack-audio-matcher
view 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 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; } 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); }