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