annotate 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
rev   line source
andrew@19 1 /*
andrew@19 2 * TempoFollower.cpp
andrew@19 3 * MultipleAudioMathcher
andrew@19 4 *
andrew@19 5 * Created by Andrew on 09/02/2012.
andrew@19 6 * Copyright 2012 QMUL. All rights reserved.
andrew@19 7 *
andrew@19 8 */
andrew@19 9
andrew@19 10 #include "TempoFollower.h"
andrew@19 11
andrew@19 12 TempoFollower::TempoFollower(){
andrew@19 13 maximumTempoInterval = 600;
andrew@19 14 minimumTempoInterval = 200;
andrew@19 15 tempoArraySize = maximumTempoInterval - minimumTempoInterval;;
andrew@19 16
andrew@19 17 tempoPrior.createVector(tempoArraySize);
andrew@19 18 tempoPosterior.createVector(tempoArraySize);
andrew@19 19 tempoLikelihood.createVector(tempoArraySize);
andrew@19 20
andrew@19 21 tempoPosterior.addConstant(1);
andrew@19 22
andrew@19 23 tempoPrior.offset = minimumTempoInterval;
andrew@19 24 tempoPosterior.offset = minimumTempoInterval;
andrew@19 25 tempoLikelihood.offset = minimumTempoInterval;
andrew@19 26
andrew@19 27 tempoPrior.scalar = 1;
andrew@19 28 tempoPosterior.scalar = 1;
andrew@19 29 tempoLikelihood.scalar = 1;
andrew@19 30 }
andrew@19 31
andrew@19 32
andrew@19 33 void TempoFollower::reset(){
andrew@19 34
andrew@19 35 tempoPrior.zero();
andrew@19 36 tempoPosterior.addConstant(1);
andrew@19 37 }
andrew@19 38
andrew@19 39
andrew@19 40 void TempoFollower::setUpEventTimeMatrix(){
andrew@19 41 for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
andrew@19 42 IntVector v;
andrew@19 43 eventTimes.push_back(v);
andrew@19 44
andrew@19 45 DoubleMatrix m;
andrew@19 46 tempoIntervals.push_back(m);
andrew@19 47 }
andrew@19 48
andrew@19 49 //[channel][index]
andrew@19 50 }
andrew@19 51
andrew@19 52
andrew@19 53
andrew@19 54 void TempoFollower::printEventTimes(){
andrew@19 55 for (int i = 0;i < NUMBER_OF_CHANNELS;i++){
andrew@19 56 printf("CHANNEL %i EVENT TIMES...\n", i);
andrew@19 57 for (int j = 0;j < eventTimes[i].size();j++)
andrew@19 58 printf("%i\n", eventTimes[i][j]);
andrew@19 59 }
andrew@19 60 }
andrew@19 61
andrew@19 62
andrew@19 63 void TempoFollower::updateTempo(const int& channel, const int& timeIn){
andrew@19 64
andrew@19 65 eventTimes[channel].push_back(timeIn);
andrew@19 66
andrew@19 67 int interval = 0;
andrew@19 68 int intervalLimit = 3600;
andrew@19 69
andrew@19 70 int recentIndex = eventTimes[channel].size()-1;
andrew@19 71
andrew@19 72 DoubleVector d;
andrew@19 73
andrew@19 74 int recentEvent = eventTimes[channel][recentIndex];
andrew@19 75
andrew@19 76 for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){
andrew@19 77 interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i];
andrew@19 78
andrew@19 79 if (testTempoInterval(channel, interval, d))
andrew@19 80 printf("channel %i interval %i at division 1 == tempo update %i\n", channel, interval, interval);
andrew@19 81
andrew@19 82 for (double divisionInEighthNotes = 2.0;divisionInEighthNotes < 9.0;divisionInEighthNotes+=2){
andrew@19 83
andrew@19 84 double testInterval = interval / divisionInEighthNotes;
andrew@19 85 if (testTempoInterval(channel, testInterval, d))
andrew@19 86 printf("channel %i interval %i at division %.0f == tempo update %f\n", channel, interval, divisionInEighthNotes, testInterval);
andrew@19 87
andrew@19 88 }
andrew@19 89 }
andrew@19 90
andrew@19 91 (tempoIntervals[channel]).push_back(d);
andrew@19 92 updateTempoDistribution(d);
andrew@19 93
andrew@19 94 }
andrew@19 95
andrew@19 96
andrew@19 97 bool TempoFollower::testTempoInterval(const int& channel, const double& testInterval, DoubleVector& d){
andrew@19 98
andrew@19 99 bool updated = false;
andrew@19 100 if (testInterval >= minimumTempoInterval && testInterval <= maximumTempoInterval){
andrew@19 101 d.push_back(testInterval);
andrew@19 102 updated = true;
andrew@19 103 }
andrew@19 104 return updated;
andrew@19 105 }
andrew@19 106
andrew@19 107 void TempoFollower::updateTempoDistribution(const DoubleVector& d){
andrew@19 108 double tempoLikelihoodToNoiseRatio = 0.8;
andrew@19 109 tempoLikelihood.zero();
andrew@19 110 double amount = tempoLikelihoodToNoiseRatio/d.size();
andrew@19 111 for (int i = 0;i < d.size();i++){
andrew@19 112 tempoLikelihood.addGaussianShapeFromRealTime(d[i], 10, amount);
andrew@19 113 }
andrew@19 114 tempoLikelihood.addConstant(0.1*(1-tempoLikelihoodToNoiseRatio));
andrew@19 115 calculatePosterior();
andrew@19 116
andrew@19 117 tempoPosterior.renormalise();
andrew@19 118 playingTempo = tempoPosterior.getIndexInRealTerms(tempoPosterior.getMAPestimate());
andrew@19 119 }
andrew@19 120
andrew@19 121
andrew@19 122
andrew@19 123 void TempoFollower::calculatePosterior(){
andrew@19 124 tempoPrior.copyFromDynamicVector(tempoPosterior);
andrew@19 125 for (int i = 0;i < tempoArraySize;i++){
andrew@19 126 tempoPosterior.array[i] = tempoLikelihood.array[i] * tempoPrior.array[i];
andrew@19 127 }
andrew@19 128 }
andrew@19 129
andrew@19 130 void TempoFollower::drawTempoArray(ofxWindowRegion& window){
andrew@19 131 ofSetColor(150,0,250);
andrew@19 132 tempoPosterior.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window);
andrew@19 133 ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40);
andrew@19 134 }