Mercurial > hg > multitrack-audio-matcher
comparison src/AudioEventMatcher.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 | 604add81822f |
comparison
equal
deleted
inserted
replaced
19:1a62561bd72d | 20:4f6006cac9de |
---|---|
29 | 29 |
30 | 30 |
31 | 31 |
32 followingLiveInput = true; | 32 followingLiveInput = true; |
33 startedPlaying = false; | 33 startedPlaying = false; |
34 | 34 recordedTempoIndex = 0; |
35 temporal.setUpEventTimeMatrix(); | 35 // temporal.setUpEventTimeMatrix(); |
36 // recordedTempoData.setUpEventTimeMatrix(); | |
36 } | 37 } |
37 | 38 |
38 | 39 |
39 | 40 |
40 | 41 |
63 | 64 |
64 void AudioEventMatcher::loadAudioFiles(){ | 65 void AudioEventMatcher::loadAudioFiles(){ |
65 recordedTracks.loadTestAudio(); | 66 recordedTracks.loadTestAudio(); |
66 synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples; | 67 synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples; |
67 printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples); | 68 printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples); |
69 | |
70 calculateRecordedTempoData(); | |
71 printf("\n\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); | |
72 setTempoPrior(recordedTempoData.playingTempo); | |
73 calculateRecordedTempoData();//now calculate again using better prior | |
74 | |
75 printf("\n\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); | |
76 printf("GLOBAL TEMPO of RECORDED FILES\n"); | |
77 recordedTempoData.printTempoTimes(); | |
78 } | |
79 | |
80 void AudioEventMatcher::setTempoPrior(double tempo){ | |
81 recordedTempoData.zero(); | |
82 recordedTempoData.tempoPosterior.zero(); | |
83 recordedTempoData.tempoPosterior.addGaussianShapeFromRealTime(tempo, 3, 1); | |
84 | |
85 } | |
86 | |
87 void AudioEventMatcher::calculateRecordedTempoData(){ | |
88 int indexForOnsets[3]; | |
89 indexForOnsets[0] = 0; | |
90 indexForOnsets[1] = 0; | |
91 indexForOnsets[2] = 0; | |
92 int kickTime, snareTime; | |
93 while (indexForOnsets[0] < recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.chromaOnsets.size() || | |
94 indexForOnsets[2] < recordedTracks.loadedAudioFiles[2].fileLoader.onsetDetect.chromaOnsets.size()) { | |
95 | |
96 setNextOnsetTime(0, kickTime, &indexForOnsets[0]); | |
97 setNextOnsetTime(2, snareTime, &indexForOnsets[0]); | |
98 | |
99 if (kickTime < snareTime){ | |
100 printf("update kick at %i\n", kickTime); | |
101 recordedTempoData.updateTempo(0, kickTime); | |
102 printf("recorded tempo is %f\n", recordedTempoData.playingTempo); | |
103 indexForOnsets[0]++; | |
104 }else { | |
105 printf("update snare at %i\n", snareTime); | |
106 recordedTempoData.updateTempo(2, snareTime); | |
107 printf("recorded tempo is %f\n", recordedTempoData.playingTempo); | |
108 indexForOnsets[2]++; | |
109 } | |
110 }//end while | |
111 | |
112 | |
113 } | |
114 | |
115 void AudioEventMatcher::setNextOnsetTime(const int& channel, int& time, int* indexForOnsets){ | |
116 if (indexForOnsets[channel] < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){ | |
117 time = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[indexForOnsets[channel]].millisTime; | |
118 } | |
119 else { | |
120 time = 2147483647;//infinity | |
121 } | |
68 } | 122 } |
69 | 123 |
70 void AudioEventMatcher::startPlaying(){ | 124 void AudioEventMatcher::startPlaying(){ |
71 bayesianStruct.setStartPlaying(); | 125 bayesianStruct.setStartPlaying(); |
72 currentAlignmentPosition = 0; | 126 currentAlignmentPosition = 0; |
75 projectedPrior = bayesianStruct.prior; | 129 projectedPrior = bayesianStruct.prior; |
76 startedPlaying = true; | 130 startedPlaying = true; |
77 synchroniser.reset(); | 131 synchroniser.reset(); |
78 temporal.reset(); | 132 temporal.reset(); |
79 | 133 |
134 recordedTempoIndex = 0; | |
135 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex]; | |
136 | |
137 currentSpeedRatio = 1; | |
138 | |
139 //SET TEMPO PRIOR for Speed Ratio | |
140 //the update this | |
141 setSpeedRatioDistribution(currentSpeedRatio); | |
80 //bayesianStruct.posterior.printArray(); | 142 //bayesianStruct.posterior.printArray(); |
81 } | 143 } |
82 | 144 |
145 | |
146 void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){ | |
147 bayesianStruct.relativeSpeedPosterior.zero(); | |
148 bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1); | |
149 bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(1, 0.06, 0.5); | |
150 } | |
83 | 151 |
84 void AudioEventMatcher::stopPlaying(){ | 152 void AudioEventMatcher::stopPlaying(){ |
85 startedPlaying = false; | 153 startedPlaying = false; |
86 temporal.printEventTimes(); | 154 temporal.printEventTimes(); |
87 } | 155 } |
92 if (!followingLiveInput) | 160 if (!followingLiveInput) |
93 recordedTracks.updatePosition(); | 161 recordedTracks.updatePosition(); |
94 else | 162 else |
95 recordedTracks.updatePositionToMillis(currentAlignmentPosition); | 163 recordedTracks.updatePositionToMillis(currentAlignmentPosition); |
96 | 164 |
97 updateBestAlignmentPosition(); | 165 updateBestAlignmentPosition(); |
98 } | 166 } |
167 | |
168 updateRecordedTempo(); | |
99 | 169 |
100 temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 ); | 170 temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 ); |
171 } | |
172 | |
173 void AudioEventMatcher::updateRecordedTempo(){ | |
174 //tempo of equivalent recorded position is updated | |
175 while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){ | |
176 recordedTempoIndex++; | |
177 } | |
178 recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex]; | |
179 double tmpRatio = currentSpeedRatio; | |
180 currentSpeedRatio = temporal.playingTempo / recordedTempo; | |
181 if (currentSpeedRatio != tmpRatio) | |
182 setSpeedRatioDistribution(currentSpeedRatio); | |
101 } | 183 } |
102 | 184 |
103 void AudioEventMatcher::updateBestAlignmentPosition(){ | 185 void AudioEventMatcher::updateBestAlignmentPosition(){ |
104 //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN | 186 //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN |
105 //DIFFERENT TO WHEN EVENTS COME IN AS THEY ARE TIMESTAMPED - SO EG A PITCH EVENT MAY ARRIVE 16 CHROMA FRAMES LATER - BIG DIFFERENCE | 187 //DIFFERENT TO WHEN EVENTS COME IN AS THEY ARE TIMESTAMPED - SO EG A PITCH EVENT MAY ARRIVE 16 CHROMA FRAMES LATER - BIG DIFFERENCE |
153 alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms"; | 235 alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms"; |
154 alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms"; | 236 alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms"; |
155 ofDrawBitmapString(alignString, 20, 50); | 237 ofDrawBitmapString(alignString, 20, 50); |
156 | 238 |
157 ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600); | 239 ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600); |
158 } | 240 |
159 | 241 temporal.drawTempoArray(bayesLikelihoodWindow); |
242 | |
243 drawRecordedTempo(); | |
244 drawPlayingTempo(); | |
245 | |
246 | |
247 } | |
248 | |
249 void AudioEventMatcher::drawRecordedTempo(){ | |
250 | |
251 int xTempoIndex = ofGetWidth() * (recordedTempo - recordedTempoData.minimumTempoInterval)/(recordedTempoData.maximumTempoInterval - recordedTempoData.minimumTempoInterval); | |
252 ofSetColor(0, 200, 0); | |
253 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height); | |
254 ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10); | |
255 } | |
256 | |
257 void AudioEventMatcher::drawPlayingTempo(){ | |
258 | |
259 int xTempoIndex = ofGetWidth() * (temporal.playingTempo - temporal.minimumTempoInterval)/(temporal.maximumTempoInterval - temporal.minimumTempoInterval); | |
260 ofSetColor(200, 0, 200); | |
261 ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height); | |
262 ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10); | |
263 | |
264 int xSpeedRatioIndex = (double)(temporal.tempoPosterior.getIndexInRealTerms(currentSpeedRatio)*ofGetWidth())/(double)temporal.tempoPosterior.arraySize; | |
265 ofSetColor(200,0,0); | |
266 ofLine(xSpeedRatioIndex, bayesTempoWindow.y, xSpeedRatioIndex, bayesTempoWindow.y + bayesTempoWindow.height); | |
267 ofDrawBitmapString(ofToString(currentSpeedRatio), 100, bayesTempoWindow.y+50); | |
268 | |
269 } | |
270 | |
271 | |
160 void AudioEventMatcher::setScreenDisplayTimes(){ | 272 void AudioEventMatcher::setScreenDisplayTimes(){ |
161 screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); | 273 screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); |
162 // if (!followingLiveInput){ | 274 // if (!followingLiveInput){ |
163 | 275 |
164 screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame); | 276 screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame); |
232 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); | 344 bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); |
233 | 345 |
234 ofSetColor(255,0,0); | 346 ofSetColor(255,0,0); |
235 projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); | 347 projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); |
236 | 348 |
237 temporal.drawTempoArray(bayesLikelihoodWindow); | 349 |
238 | 350 |
239 } | 351 } |
240 | 352 |
241 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ | 353 void AudioEventMatcher::newPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ |
242 if (pitchIn > 0){ | 354 if (pitchIn > 0){ |