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 }
|