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