Mercurial > hg > drum-timing-analyser
comparison DrumTimingLoader_OF/src/RecordedMultipleAudio.cpp @ 0:82352cfc0b23
Added files from ISMIR groove drum timing work
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Mon, 01 Oct 2012 22:24:32 +0100 |
parents | |
children | 50ba55abea8c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:82352cfc0b23 |
---|---|
1 /* | |
2 * RecordedMultipleAudio.cpp | |
3 * MultipleAudioMathcher | |
4 * | |
5 * Created by Andrew on 31/01/2012. | |
6 * Copyright 2012 QMUL. All rights reserved. | |
7 * | |
8 */ | |
9 | |
10 #include "RecordedMultipleAudio.h" | |
11 | |
12 RecordedMultipleAudio::RecordedMultipleAudio(){ | |
13 | |
14 infoFilepath = "../../../data/errorData.txt"; | |
15 //infoFilepath = "/Users/andrew/errorData.txt"; | |
16 | |
17 timingOffset = 0; | |
18 } | |
19 | |
20 void RecordedMultipleAudio::loadTestAudio(){ | |
21 | |
22 | |
23 numberOfAudioTracks = 2; | |
24 | |
25 printf("loaded max val is %f\n", loadedAudioFiles[0].fileLoader.onsetDetect.onsetDetector.maximumDetectionValue); | |
26 | |
27 int multitrackToLoad = 5; | |
28 setDifferentMultitracks(multitrackToLoad);//command to load this set of audio files - see below | |
29 | |
30 drumTimingAnalyser.phaseCost = 1000;//v high - i.e. dont do phase | |
31 | |
32 drawWindow = 1; | |
33 trackScreenHeight = 0.25; | |
34 | |
35 | |
36 | |
37 // printf("AFTER LOADING: \n"); | |
38 // printInfo(); | |
39 | |
40 } | |
41 #pragma mark -loadingPrerecordedTracks | |
42 void RecordedMultipleAudio::setDifferentMultitracks(const int& setToLoad){ | |
43 const char *kickfilename ;//= "../../../data/sound/LiveDues/kick_liveDues.wav"; | |
44 const char *roomfilename ;//"../../../data/sound/LiveDues/bass_upsideLive.wav"; | |
45 const char *snarefilename ; | |
46 std::string sonicVizBeatsFilename ; | |
47 | |
48 switch (setToLoad) { | |
49 case 0: | |
50 kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/kickFuture.wav"; | |
51 roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/roomFuture.wav"; | |
52 snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/snareFuture.wav"; | |
53 sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/FutureHidesBeats.txt"; | |
54 break; | |
55 | |
56 | |
57 case 1: | |
58 roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown.wav"; | |
59 kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/kick.wav"; | |
60 snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/snare.wav"; | |
61 sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown_beats.txt"; | |
62 break; | |
63 | |
64 case 2: | |
65 roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/colesL_bip.wav"; | |
66 kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Kick_bip.wav"; | |
67 snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Snare_bip.wav"; | |
68 sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/IngramGreenSectionBeats.txt"; | |
69 break; | |
70 | |
71 case 3: | |
72 roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/coles_bip.wav"; | |
73 kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/kick d112_bip.wav"; | |
74 snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/snare bottom_bip.wav"; | |
75 sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/TakeOneBeats.txt"; | |
76 break; | |
77 | |
78 case 4: | |
79 roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/neuamnn_bip.wav"; | |
80 kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/kick_bip.wav"; | |
81 snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/snare_bip.wav"; | |
82 sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/PennyArcade_take4_beats.txt"; | |
83 break; | |
84 | |
85 case 5: | |
86 roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/neuamnn_bip.wav"; | |
87 kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/kick_bip.wav"; | |
88 snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/snare_bip.wav"; | |
89 sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/PennyArcade_take5_beats.txt"; | |
90 break; | |
91 | |
92 | |
93 | |
94 } | |
95 if (kickfilename != NULL){ | |
96 | |
97 loadAudioTrack(kickfilename, 0); | |
98 } | |
99 | |
100 if (roomfilename != NULL){ | |
101 printf("roomfilename: %s\n", roomfilename); | |
102 loadAudioTrack(roomfilename, 1); | |
103 } | |
104 | |
105 if (snarefilename != NULL) | |
106 loadAudioTrack(snarefilename, 2); | |
107 | |
108 if (sonicVizBeatsFilename.c_str() != NULL){ | |
109 readInBeatsFile(sonicVizBeatsFilename); | |
110 printBeatTimes(); | |
111 checkFileErrors(0); | |
112 checkFileErrors(2); | |
113 findBeatOnsets(); | |
114 } | |
115 } | |
116 | |
117 void RecordedMultipleAudio::loadAudioTrack(std::string name, const int& channel){ | |
118 //kick - track type 0 | |
119 //bass - type 1 | |
120 //snare type 2 | |
121 //guitar type 3 | |
122 if (channel >= 0 && channel <= numberOfAudioTracks){ | |
123 loadedAudioPtr = new LoadedAudioHolder; | |
124 //set tracktype before we do analysis | |
125 //so we dont do unnecessary chroma and pitch calculations | |
126 if (channel == 0 || channel == 2){ | |
127 loadedAudioPtr->setTrackType(channel); | |
128 } | |
129 else{ | |
130 loadedAudioPtr->setTrackType(0); | |
131 } | |
132 loadedAudioPtr->loadAudioFile(name); | |
133 | |
134 loadedAudioFiles[channel] = *loadedAudioPtr; | |
135 loadedAudioFiles[channel].fileLoader.onsetDetect.window.setToRelativeSize(0, trackScreenHeight*channel, 1, trackScreenHeight); | |
136 //loadedAudioFiles[channel].setTrackType(channel); | |
137 } | |
138 } | |
139 | |
140 | |
141 | |
142 void RecordedMultipleAudio::readInBeatsFile(std::string& pathName){ | |
143 | |
144 // "/Users/andrew/Documents/work/MuseScore/RWC/ANNOTATION/RM-C002_annotation+WavPos.csv" | |
145 beatTimes.clear(); | |
146 | |
147 printf("- - - - \n\nREAD FILE %s\n", pathName.c_str()); | |
148 ifstream file ( pathName.c_str()); | |
149 string value, tmpLine; | |
150 stringstream iss; | |
151 int count = 0; | |
152 | |
153 while ( file.good() ) | |
154 { | |
155 getline(file, tmpLine); | |
156 iss << tmpLine; | |
157 int lineCount = 0; | |
158 // printf("tmp line %s\n", tmpLine.c_str()); | |
159 while(getline ( iss, value, '\t' )){ // read a string until next comma: http://www.cplusplus.com/reference/string/getline/ | |
160 // cout << string( value, 1, value.length()-2 ); // display value removing the first and the last character from it | |
161 // printf("line:%s\n", value.c_str()); | |
162 string::size_type start = value.find_first_not_of(" ,\t\v\n"); | |
163 | |
164 string part = value.substr(start, string::npos); | |
165 | |
166 //printf("%s\n", firstpart.c_str()); | |
167 if (lineCount == 0){ | |
168 //printf("First part of line found '%s'\n", part.c_str()); | |
169 double newBeatTime = atof(part.c_str()); | |
170 beatTimes.push_back(newBeatTime); | |
171 } | |
172 lineCount++; | |
173 | |
174 }//end while reading line | |
175 iss.clear(); | |
176 | |
177 | |
178 }//end while | |
179 | |
180 // printBeatTimes(); | |
181 printf("There are %i BEAT annotations\n", (int)beatTimes.size()); | |
182 | |
183 } | |
184 | |
185 void RecordedMultipleAudio::printBeatTimes(){ | |
186 for (int i = 0;i < beatTimes.size();i++){ | |
187 printf("Beat[%i] = %f\n", i, beatTimes[i]); | |
188 } | |
189 } | |
190 | |
191 | |
192 void RecordedMultipleAudio::checkFileErrors(int channel){ | |
193 int beatIndex = 0; | |
194 int cutoff = 50;//ms width to check | |
195 for (int i = 0;i < loadedAudioFiles[channel].onsetTimesMillis.size();i++){ | |
196 while (beatIndex < beatTimes.size() && 1000.0*beatTimes[beatIndex] < loadedAudioFiles[channel].onsetTimesMillis[i] - cutoff) { | |
197 beatIndex++; | |
198 } | |
199 double error = (1000.0*beatTimes[beatIndex] - loadedAudioFiles[channel].onsetTimesMillis[i]); | |
200 if (fabs(error) < cutoff){ | |
201 if (channel == 0) | |
202 printf("Pos: %i Beat Time %f Kick Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); | |
203 else | |
204 printf("Pos: %i Beat Time %f Snare Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); | |
205 | |
206 }else{ | |
207 if (channel == 0) | |
208 printf("Out of Beat: Kick Time %f beat error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); | |
209 else | |
210 printf("Out of Beat: %f Snare Time %f best error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); | |
211 | |
212 } | |
213 } | |
214 } | |
215 | |
216 | |
217 #pragma mark -labelExactOnsets | |
218 | |
219 void RecordedMultipleAudio::findBeatOnsets(){ | |
220 //tries to find kicks on 1, 3; snares on 2,4 | |
221 int beatIndex = 0; | |
222 int kickIndex = 0; | |
223 int snareIndex = 0; | |
224 double kickTime, snareTime; | |
225 int cutoff = 50;//ms width to check | |
226 | |
227 onsetInfo.clear(); | |
228 | |
229 // kickErrors.clear(); | |
230 // snareErrors.clear(); | |
231 | |
232 bool beatFound; | |
233 for (int k = 0;k < beatTimes.size();k++){ | |
234 beatFound = false; | |
235 double newBeatTime = beatTimes[k]*1000.0; | |
236 int beatPosition = k % 4; | |
237 OnsetInformation information; | |
238 switch (beatPosition) { | |
239 case 0: case 2://check for kick when it is on the `one' or 'three' (0 or 2 in our metrical position) | |
240 // printf("check %i kindex %i\n", beatPosition, kickIndex); | |
241 while (kickIndex < loadedAudioFiles[0].onsetTimesMillis.size() && loadedAudioFiles[0].onsetTimesMillis[kickIndex] < newBeatTime - cutoff){ | |
242 kickIndex++; | |
243 kickTime = loadedAudioFiles[0].onsetTimesMillis[kickIndex]; | |
244 // printf("checking beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0)); | |
245 if (fabs(kickTime - beatTimes[k]*1000.0) < cutoff){ | |
246 beatFound = true; | |
247 printf("beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0)); | |
248 | |
249 information.error = (kickTime - beatTimes[k]*1000.0);//FOR NOW ONLY | |
250 information.metricalPosition = beatPosition; | |
251 information.type = 0; | |
252 information.exactOnsetTime = kickTime; | |
253 // exactBeatPositions.push_back(kickTime); | |
254 } | |
255 } | |
256 | |
257 break; | |
258 case 1: case 3://snare | |
259 while (snareIndex < loadedAudioFiles[1].onsetTimesMillis.size() && loadedAudioFiles[1].onsetTimesMillis[snareIndex] < newBeatTime - cutoff ){ | |
260 snareIndex++; | |
261 snareTime = loadedAudioFiles[1].onsetTimesMillis[snareIndex]; | |
262 if (fabs(snareTime - beatTimes[k]*1000.0) < cutoff){ | |
263 beatFound = true; | |
264 // snareErrors.push_back((beatTimes[k]*1000.0 - snareTime)); | |
265 information.error = (snareTime - beatTimes[k]*1000.0); | |
266 information.metricalPosition = beatPosition;//.push_back(beatPosition); | |
267 information.type = 1; | |
268 information.exactOnsetTime = snareTime; | |
269 printf("beat[%i] %f snare %f error %f\n", k, beatTimes[k]*1000.0, snareTime, (snareTime - beatTimes[k]*1000.0)); | |
270 // exactBeatPositions.push_back(snareTime); | |
271 } | |
272 } | |
273 | |
274 break; | |
275 } | |
276 if (!beatFound){ | |
277 information.type = -1;//not a kick or snare | |
278 information.exactOnsetTime = beatTimes[k]*1000.0; | |
279 information.metricalPosition = beatPosition;//.push_ | |
280 // exactBeatPositions.push_back(beatTimes[k]*1000.0);//have to go with the annotated beat instead (no matching kick or snare) | |
281 | |
282 printf("beat[%i] %f NOT FOUND, kicktime %f snaretime %f\n", k, beatTimes[k]*1000.0, kickTime, snareTime ); | |
283 } | |
284 | |
285 onsetInfo.push_back(information); | |
286 | |
287 }//end for all beat annotations | |
288 | |
289 correctExactBeatTiming();//get rid of the first onset time | |
290 | |
291 calculateTimingAnalysis(); | |
292 | |
293 } | |
294 | |
295 #pragma mark -doTimingAnalysis | |
296 void RecordedMultipleAudio::correctExactBeatTiming(){ | |
297 //get rid of firtst onset time | |
298 if (onsetInfo.size() > 0){ | |
299 timingOffset = onsetInfo[0].exactOnsetTime;//s[0]; | |
300 double tmpPosn; | |
301 for (int i = 0;i < onsetInfo.size();i++){ | |
302 onsetInfo[i].beatTimeToProcess = onsetInfo[i].exactOnsetTime - timingOffset; | |
303 printf("exact [%i] type %i %f, corrected %f\n", i, onsetInfo[i].type, onsetInfo[i].exactOnsetTime, onsetInfo[i].beatTimeToProcess ); | |
304 } | |
305 } | |
306 } | |
307 | |
308 void RecordedMultipleAudio::calculateTimingAnalysis(){ | |
309 | |
310 for (int i = 0;i < onsetInfo.size();i++){ | |
311 drumTimingAnalyser.updateCostToPoint(onsetInfo[i].beatTimeToProcess, i); | |
312 //updatecounter is the beat position for this note event - can be used to do other kinds of durations than just simple beats | |
313 | |
314 drumTimingAnalyser.beatPosition.push_back(onsetInfo[i].exactOnsetTime); | |
315 } | |
316 drumTimingAnalyser.processPathHistory(); | |
317 drumTimingAnalyser.calculateTempoLimits(); | |
318 | |
319 getErrorTimesFromAnalysis(); | |
320 | |
321 alternativeKickRelativeAnalysis(); | |
322 | |
323 exportErrorInformation(); | |
324 | |
325 displayKickRelativeMedianErrors();//NB messes ther order of these | |
326 | |
327 //this was how we did it in multimatch program | |
328 // timer.processPathHistory(); | |
329 // timer.calculateTempoLimits(); | |
330 // timer.exportTimingData(); | |
331 // timer.exportProcessedBeatTimes(firstNoteTime); | |
332 } | |
333 | |
334 void RecordedMultipleAudio::getErrorTimesFromAnalysis(){ | |
335 printf("\nDrumTimingLoader: get error times from analysis!!!\n"); | |
336 setUpErrorsByMetricalPosition(); | |
337 //gets the errors from the drum timing analyser (i.e. ISMIR paper code) and attributes these to the onsets | |
338 for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){ | |
339 onsetInfo[i].error = drumTimingAnalyser.timingData[i][5]; | |
340 onsetInfo[i].clickTime = drumTimingAnalyser.timingData[i][1] + timingOffset;//this is where teh timing analyser placed the click times | |
341 errorsByMetricalPosition[onsetInfo[i].metricalPosition].push_back(onsetInfo[i].error); | |
342 printf("beat %i metrical posn %i exact beat time %f error %i\n", i, onsetInfo[i].metricalPosition, onsetInfo[i].exactOnsetTime, (int)onsetInfo[i].error); | |
343 } | |
344 displayMedianErrors(); | |
345 } | |
346 | |
347 | |
348 void RecordedMultipleAudio::alternativeKickRelativeAnalysis(){ | |
349 printf("\n\nAnalysis Relative to the Kick Drum on the ONE\n"); | |
350 //this sees kicks as ON the beat, looks at relative error of the three other beats if we chop the bar evenly | |
351 | |
352 double recentBeatTime, currentTempo; | |
353 kickRelativeErrors.clear(); | |
354 kickRelativeClickTimes.clear(); | |
355 | |
356 for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){ | |
357 int beatPosition = i%4; | |
358 if (beatPosition == 0){ | |
359 recentBeatTime = onsetInfo[i].exactOnsetTime; | |
360 if (i+4 < onsetInfo.size()) | |
361 currentTempo = (onsetInfo[i+4].exactOnsetTime - onsetInfo[i].exactOnsetTime)/4.0; | |
362 printf("new beat time %f tempo %f\n", recentBeatTime, currentTempo); | |
363 } | |
364 double error = onsetInfo[i].exactOnsetTime - (recentBeatTime + beatPosition*currentTempo); | |
365 printf("Beat %i KR Predicted Beat %f Actual exact %f KRerror %f DTerror %i\n", beatPosition, (recentBeatTime + beatPosition*currentTempo), onsetInfo[i].exactOnsetTime, error, (int)onsetInfo[i].error); | |
366 kickRelativeErrors.push_back(error); | |
367 kickRelativeClickTimes.push_back(recentBeatTime + beatPosition*currentTempo); | |
368 } | |
369 } | |
370 | |
371 #pragma label -exportInfo | |
372 void RecordedMultipleAudio::exportErrorInformation(){ | |
373 printf("Export final timing information\n"); | |
374 | |
375 ofstream ofs(infoFilepath.c_str()); | |
376 for (int i = 0;i < onsetInfo.size() && kickRelativeErrors.size();i++){// drumTimingAnalyser.timingData.size() | |
377 ofs << i << "," << (i%4) << "," << onsetInfo[i].exactOnsetTime << ","; | |
378 ofs << onsetInfo[i].clickTime << "," << onsetInfo[i].error << ",";//the error for the ISMIR timing analyser | |
379 ofs << kickRelativeClickTimes[i] << "," << kickRelativeErrors[i];//the click and error for beats evenly between kicks | |
380 ofs << endl; | |
381 } | |
382 | |
383 } | |
384 | |
385 void RecordedMultipleAudio::printKickRelativeErrors(){ | |
386 for (int i = 0;i < kickRelativeErrors.size();i++){ | |
387 printf("KR error [%i] : %.1f\n", i, kickRelativeErrors[i]); | |
388 } | |
389 } | |
390 | |
391 void RecordedMultipleAudio::setUpErrorsByMetricalPosition(){ | |
392 //clear this matrix | |
393 errorsByMetricalPosition.clear(); | |
394 for (int i = 0;i < 4;i++){ | |
395 DoubleVector v; | |
396 errorsByMetricalPosition.push_back(v); | |
397 } | |
398 | |
399 } | |
400 | |
401 void RecordedMultipleAudio::displayMedianErrors(){ | |
402 printf("Medians of the Decoded Tempo variations\n"); | |
403 for (int i = 0;i < 4;i++){ | |
404 //printErrorsForMetricalPosition(i); | |
405 std::sort(errorsByMetricalPosition[i].begin(), errorsByMetricalPosition[i].end());//sort vector | |
406 double median = errorsByMetricalPosition[i][(int)(errorsByMetricalPosition[i].size()/2)]; | |
407 printf("median for metrical position %i is %f\n", i, median); | |
408 } | |
409 } | |
410 | |
411 | |
412 void RecordedMultipleAudio::displayKickRelativeMedianErrors(){ | |
413 printf("Medians of the KR variations\n"); | |
414 | |
415 DoubleVector tmpKRErrors; | |
416 | |
417 | |
418 for (int i = 0;i < 4;i++){ | |
419 | |
420 tmpKRErrors.clear(); | |
421 int index = 0; | |
422 | |
423 while (index+i < kickRelativeErrors.size()) { | |
424 tmpKRErrors.push_back(kickRelativeErrors[index + i]); | |
425 index += 4; | |
426 } | |
427 | |
428 // for (int k = 0;k < tmpKRErrors.size();k++) | |
429 // printf("kr %i [%i] = %f\n", i, k, tmpKRErrors[k]); | |
430 | |
431 //printErrorsForMetricalPosition(i); | |
432 std::sort(tmpKRErrors.begin(), tmpKRErrors.end());//sort vector | |
433 | |
434 // for (int k = 0;k < tmpKRErrors.size();k++) | |
435 // printf("sorted kr %i [%i] = %f\n", i, k, tmpKRErrors[k]); | |
436 | |
437 | |
438 double median = tmpKRErrors[(int)(tmpKRErrors.size()/2)]; | |
439 printf("median for metrical position %i is %f\n", i, median); | |
440 } | |
441 } | |
442 | |
443 void RecordedMultipleAudio::printErrorsForMetricalPosition(const int& i){ | |
444 for (int k = 0;k < errorsByMetricalPosition[i].size();k++){ | |
445 printf("metrical posn %i, [%i] = %f\n", i, k, errorsByMetricalPosition[i][k]); | |
446 } | |
447 } | |
448 | |
449 #pragma mark -drawTracks | |
450 | |
451 void RecordedMultipleAudio::drawTracks(){ | |
452 if (drawWindow == 0){ | |
453 for (int i = 0;i < numberOfAudioTracks;i++){ | |
454 loadedAudioFiles[i].draw(); | |
455 } | |
456 } else { | |
457 drumTimingAnalyser.drawTempoCurve(); | |
458 } | |
459 } | |
460 | |
461 #pragma mark -update | |
462 void RecordedMultipleAudio::updatePosition(){ | |
463 for (int i = 0;i < numberOfAudioTracks;i++) | |
464 loadedAudioFiles[i].updateToPlayPosition(); | |
465 } | |
466 | |
467 void RecordedMultipleAudio::updatePositionToMillis(const double& millis){ | |
468 for (int i = 0;i < numberOfAudioTracks;i++) | |
469 loadedAudioFiles[i].updateToMillisPosition(millis); | |
470 } | |
471 | |
472 void RecordedMultipleAudio::updatePlaybackPositionToMillis(const double& millis){ | |
473 for (int i = 0;i < numberOfAudioTracks;i++) | |
474 loadedAudioFiles[i].updatePlaybackPositionToMillis(millis); | |
475 } | |
476 | |
477 void RecordedMultipleAudio::switchScreens(){ | |
478 for (int i = 0;i < numberOfAudioTracks;i++) | |
479 loadedAudioFiles[i].switchScreens(); | |
480 } | |
481 | |
482 | |
483 void RecordedMultipleAudio::togglePlay(){ | |
484 for (int i = 0;i < numberOfAudioTracks;i++) | |
485 loadedAudioFiles[i].togglePlay(); | |
486 } | |
487 | |
488 void RecordedMultipleAudio::stop(){ | |
489 for (int i = 0;i < numberOfAudioTracks;i++) | |
490 loadedAudioFiles[i].stop(); | |
491 } | |
492 | |
493 | |
494 void RecordedMultipleAudio::printInfo(){ | |
495 loadedAudioFiles[0].fileLoader.onsetDetect.printChromaInfo(); | |
496 loadedAudioFiles[0].printEvents(); | |
497 } | |
498 | |
499 void RecordedMultipleAudio::windowResized(const int& w, const int& h){ | |
500 for (int i = 0;i < numberOfAudioTracks;i++) | |
501 loadedAudioFiles[i].windowResized(w, h); | |
502 } | |
503 | |
504 void RecordedMultipleAudio::zoomIn(){ | |
505 if (drawWindow == 0){ | |
506 printf("zoom in\n"); | |
507 for (int i = 0;i < numberOfAudioTracks;i++) | |
508 loadedAudioFiles[i].fileLoader.zoomIn(); | |
509 } | |
510 | |
511 if (drawWindow == 1) | |
512 drumTimingAnalyser.zoomIn();//numberOfPointsPerPage /= 2; | |
513 } | |
514 | |
515 void RecordedMultipleAudio::zoomOut(){ | |
516 printf("zoom out\n"); | |
517 for (int i = 0;i < numberOfAudioTracks;i++) | |
518 loadedAudioFiles[i].fileLoader.zoomOut(); | |
519 | |
520 if (drawWindow == 1) | |
521 drumTimingAnalyser.zoomOut();//numberOfPointsPerPage *= 2; | |
522 | |
523 } | |
524 | |
525 |