Mercurial > hg > multitrack-audio-matcher
comparison src/TempoFollower.cpp @ 20:4f6006cac9de
added evaluation of recorded tempo, holding of this data, drawing of recorded and playing tempo estimates
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Sun, 12 Feb 2012 00:48:07 +0000 |
parents | 1a62561bd72d |
children | 9806a4f22fd0 |
comparison
equal
deleted
inserted
replaced
19:1a62561bd72d | 20:4f6006cac9de |
---|---|
8 */ | 8 */ |
9 | 9 |
10 #include "TempoFollower.h" | 10 #include "TempoFollower.h" |
11 | 11 |
12 TempoFollower::TempoFollower(){ | 12 TempoFollower::TempoFollower(){ |
13 | |
14 | |
15 | |
16 | |
13 maximumTempoInterval = 600; | 17 maximumTempoInterval = 600; |
14 minimumTempoInterval = 200; | 18 minimumTempoInterval = 200; |
15 tempoArraySize = maximumTempoInterval - minimumTempoInterval;; | 19 tempoArraySize = maximumTempoInterval - minimumTempoInterval;; |
16 | 20 |
17 tempoPrior.createVector(tempoArraySize); | 21 tempoPrior.createVector(tempoArraySize); |
25 tempoLikelihood.offset = minimumTempoInterval; | 29 tempoLikelihood.offset = minimumTempoInterval; |
26 | 30 |
27 tempoPrior.scalar = 1; | 31 tempoPrior.scalar = 1; |
28 tempoPosterior.scalar = 1; | 32 tempoPosterior.scalar = 1; |
29 tempoLikelihood.scalar = 1; | 33 tempoLikelihood.scalar = 1; |
34 | |
35 intervalsToTest[0] = 1; | |
36 intervalsToTest[1] = 2; | |
37 intervalsToTest[2] = 4; | |
38 intervalsToTest[3] = 8; | |
39 intervalsToTest[4] = 16; | |
40 | |
41 setUpEventTimeMatrix(); | |
30 } | 42 } |
31 | 43 |
44 void TempoFollower::zero(){ | |
45 eventTimes.clear(); | |
46 tempoIntervals.clear(); | |
47 divisions.clear(); | |
48 tempo.clear(); | |
49 globalTempo.clear(); | |
50 globalTempoTimes.clear(); | |
51 setUpEventTimeMatrix(); | |
52 } | |
32 | 53 |
33 void TempoFollower::reset(){ | 54 void TempoFollower::reset(){ |
34 | 55 |
35 tempoPrior.zero(); | 56 tempoPrior.zero(); |
36 tempoPosterior.addConstant(1); | 57 tempoPosterior.addConstant(1); |
58 | |
37 } | 59 } |
38 | 60 |
39 | 61 |
40 void TempoFollower::setUpEventTimeMatrix(){ | 62 void TempoFollower::setUpEventTimeMatrix(){ |
41 for (int i = 0;i < NUMBER_OF_CHANNELS;i++){ | 63 for (int i = 0;i < NUMBER_OF_CHANNELS;i++){ |
42 IntVector v; | 64 IntVector v; |
43 eventTimes.push_back(v); | 65 eventTimes.push_back(v); |
44 | 66 |
45 DoubleMatrix m; | 67 DoubleMatrix m; |
46 tempoIntervals.push_back(m); | 68 tempoIntervals.push_back(m); |
69 | |
70 IntMatrix h; | |
71 divisions.push_back(h); | |
72 | |
73 DoubleVector d; | |
74 tempo.push_back(d); | |
75 | |
47 } | 76 } |
48 | 77 |
49 //[channel][index] | 78 //[channel][index] |
50 } | 79 } |
51 | 80 |
58 printf("%i\n", eventTimes[i][j]); | 87 printf("%i\n", eventTimes[i][j]); |
59 } | 88 } |
60 } | 89 } |
61 | 90 |
62 | 91 |
92 void TempoFollower::printTempoTimes(){ | |
93 | |
94 for (int i = 0;i < globalTempo.size();i++){ | |
95 printf("Time %i : tempo %f\n", globalTempoTimes[i], globalTempo[i]); | |
96 } | |
97 } | |
98 | |
63 void TempoFollower::updateTempo(const int& channel, const int& timeIn){ | 99 void TempoFollower::updateTempo(const int& channel, const int& timeIn){ |
64 | 100 |
65 eventTimes[channel].push_back(timeIn); | 101 eventTimes[channel].push_back(timeIn); |
66 | 102 |
67 int interval = 0; | 103 int interval = 0; |
68 int intervalLimit = 3600; | 104 int intervalLimit = 3600; |
69 | 105 |
70 int recentIndex = eventTimes[channel].size()-1; | 106 int recentIndex = eventTimes[channel].size()-1; |
71 | 107 |
72 DoubleVector d; | 108 DoubleVector d; |
73 | 109 IntVector div; |
74 int recentEvent = eventTimes[channel][recentIndex]; | 110 int recentEvent = eventTimes[channel][recentIndex]; |
75 | 111 |
76 for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){ | 112 for (int i = 1;i < eventTimes[channel].size() && interval < intervalLimit;i++){ |
77 interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i]; | 113 interval = eventTimes[channel][recentIndex] - eventTimes[channel][recentIndex - i]; |
78 | 114 |
79 if (testTempoInterval(channel, interval, d)) | 115 for (int k = 0;k < 3;k++){ |
80 printf("channel %i interval %i at division 1 == tempo update %i\n", channel, interval, interval); | |
81 | |
82 for (double divisionInEighthNotes = 2.0;divisionInEighthNotes < 9.0;divisionInEighthNotes+=2){ | |
83 | 116 |
117 double divisionInEighthNotes = intervalsToTest[k]; | |
84 double testInterval = interval / divisionInEighthNotes; | 118 double testInterval = interval / divisionInEighthNotes; |
85 if (testTempoInterval(channel, testInterval, d)) | 119 if (testTempoInterval(channel, testInterval, d)){ |
86 printf("channel %i interval %i at division %.0f == tempo update %f\n", channel, interval, divisionInEighthNotes, testInterval); | 120 printf("channel %i interval %i at division %.0f == tempo update %f\n", channel, interval, divisionInEighthNotes, testInterval); |
87 | 121 div.push_back((int)divisionInEighthNotes); |
122 } | |
88 } | 123 } |
89 } | 124 } |
90 | 125 |
91 (tempoIntervals[channel]).push_back(d); | 126 (tempoIntervals[channel]).push_back(d); |
127 (divisions[channel]).push_back(div); | |
92 updateTempoDistribution(d); | 128 updateTempoDistribution(d); |
129 | |
130 tempo[channel].push_back(playingTempo); | |
131 | |
132 globalTempo.push_back(playingTempo); | |
133 globalTempoTimes.push_back(timeIn); | |
134 | |
93 | 135 |
94 } | 136 } |
95 | 137 |
96 | 138 |
97 bool TempoFollower::testTempoInterval(const int& channel, const double& testInterval, DoubleVector& d){ | 139 bool TempoFollower::testTempoInterval(const int& channel, const double& testInterval, DoubleVector& d){ |
104 return updated; | 146 return updated; |
105 } | 147 } |
106 | 148 |
107 void TempoFollower::updateTempoDistribution(const DoubleVector& d){ | 149 void TempoFollower::updateTempoDistribution(const DoubleVector& d){ |
108 double tempoLikelihoodToNoiseRatio = 0.8; | 150 double tempoLikelihoodToNoiseRatio = 0.8; |
151 tempoLikelihoodStdDev = 4; | |
152 | |
109 tempoLikelihood.zero(); | 153 tempoLikelihood.zero(); |
110 double amount = tempoLikelihoodToNoiseRatio/d.size(); | 154 double amount = tempoLikelihoodToNoiseRatio/d.size(); |
111 for (int i = 0;i < d.size();i++){ | 155 for (int i = 0;i < d.size();i++){ |
112 tempoLikelihood.addGaussianShapeFromRealTime(d[i], 10, amount); | 156 tempoLikelihood.addGaussianShapeFromRealTime(d[i], tempoLikelihoodStdDev, amount); |
113 } | 157 } |
114 tempoLikelihood.addConstant(0.1*(1-tempoLikelihoodToNoiseRatio)); | 158 tempoLikelihood.addConstant(0.1*(1-tempoLikelihoodToNoiseRatio)); |
115 calculatePosterior(); | 159 calculatePosterior(); |
116 | |
117 tempoPosterior.renormalise(); | 160 tempoPosterior.renormalise(); |
118 playingTempo = tempoPosterior.getIndexInRealTerms(tempoPosterior.getMAPestimate()); | 161 playingTempo = tempoPosterior.getIndexInRealTerms(tempoPosterior.getMAPestimate()); |
162 | |
163 | |
119 } | 164 } |
120 | 165 |
121 | 166 |
122 | 167 |
123 void TempoFollower::calculatePosterior(){ | 168 void TempoFollower::calculatePosterior(){ |
128 } | 173 } |
129 | 174 |
130 void TempoFollower::drawTempoArray(ofxWindowRegion& window){ | 175 void TempoFollower::drawTempoArray(ofxWindowRegion& window){ |
131 ofSetColor(150,0,250); | 176 ofSetColor(150,0,250); |
132 tempoPosterior.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window); | 177 tempoPosterior.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window); |
178 | |
179 ofSetColor(150,150,150); | |
180 tempoLikelihood.drawConstrainedVector(0, tempoArraySize, 0, ofGetWidth(), window); | |
181 | |
182 | |
133 ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40); | 183 ofDrawBitmapString("tempo "+ofToString(playingTempo), window.x+ 20, window.y + 40); |
184 | |
185 | |
186 for (int channel = 0;channel < 3;channel+=2){ | |
187 int index = tempoIntervals[channel].size()-1; | |
188 | |
189 for (int i = 0;i < 9 && index - i>=0 ;i++){ | |
190 for (int j = 0;j < tempoIntervals[channel][index - i].size();j++){ | |
191 ofSetColor(channel*125, 0, 250); | |
192 ofCircle(window.x+((tempoIntervals[channel][index - i][j] - minimumTempoInterval)*window.width)/tempoArraySize, window.y+6+(window.height*i/9.0), 4); | |
193 ofSetColor(255,255,255); | |
194 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)); | |
195 } | |
196 } | |
197 } | |
134 } | 198 } |
199 |