Mercurial > hg > drum-timing-analyser
comparison DrumTimingLoader_OF/PerformanceAnalyserSrc/TimingAnalyser.cpp @ 1:106bc2d4f702
added timing analyser file
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Sat, 23 Nov 2013 15:44:47 +0000 |
parents | |
children | 50ba55abea8c |
comparison
equal
deleted
inserted
replaced
0:82352cfc0b23 | 1:106bc2d4f702 |
---|---|
1 /* | |
2 * TimingAnalyser.cpp | |
3 * performanceTimingAnalyser | |
4 * | |
5 * Created by Andrew on 17/12/2011. | |
6 * Copyright 2011 QMUL. All rights reserved. | |
7 * | |
8 */ | |
9 | |
10 #include "TimingAnalyser.h" | |
11 | |
12 //FROM TestApp.cpp | |
13 //change these to your preferred filepaths for exporting the data | |
14 //timingDataFilepath = "/Users/andrew/outputFile.txt";//here as decoded tempo and phase | |
15 //change this to your filepath for storing the final path as output | |
16 //can then load it back in easily without reanalysing using this... | |
17 // importFileFromStoredData(fileToLoad); | |
18 //processBeatTimesFilepath = "//Users/andrew/processedBeats";//here as a list of beat times | |
19 //this latter will be a smoothed version of the original | |
20 | |
21 //RESTRICT PHASE HOP POSSIBLE | |
22 | |
23 | |
24 //Correct or DELETE this BeatPosition variable - what is it? Why used? | |
25 | |
26 | |
27 TimingAnalyser::TimingAnalyser(){ | |
28 | |
29 moveMatrixToOptimalCostPosition = true; | |
30 | |
31 tempoScalar = 2.0; | |
32 phaseScalar = 2.0; | |
33 | |
34 phaseCost = 1000.4;//a phase jump is 1.5 (y-x) where y now becomes the predicted position | |
35 tempoCost = 2.8;//a tempo jump of z msec per period is charged at 2z units | |
36 | |
37 drawIOIintervals = false; | |
38 | |
39 drawExpressiveTimingData = true; | |
40 | |
41 printHistory = false; | |
42 mozartTriplets = false; | |
43 | |
44 movementFactor = 0.5; | |
45 drawBPM = true; | |
46 | |
47 //COST VARIABLES - Assuming that a simple error is costing linear (t-x) where x is predicted time | |
48 | |
49 | |
50 blackAndWhite = true; | |
51 | |
52 setTempoLimits(400); | |
53 | |
54 | |
55 //index between which we look at the variation | |
56 tempoVariationStartIndex = 4; | |
57 | |
58 | |
59 DoubleVector v; | |
60 v.assign(phaseRange, 0.0); | |
61 logProbabilityMatrix.assign(tempoRange, v); | |
62 previousLogMatrix = logProbabilityMatrix; | |
63 | |
64 //[tempo][phase] | |
65 phaseMinimumOffset = -1 * phaseScalar*(phaseRange - 1)/2;//offset in millis | |
66 globalTimeOffset = 0;//global offset in millis | |
67 | |
68 lastBeatPosition = 0; | |
69 | |
70 | |
71 numberOfPointsPerPage = 80; | |
72 startPoint = 0; | |
73 | |
74 // initialiseRoutes(); | |
75 | |
76 recentPhaseShift = 0; | |
77 recentTempoShift = 0; | |
78 | |
79 /* meanGlobalTempo = 440; | |
80 tempoMinimumOffset = meanGlobalTempo - (tempoRange-1)/2; | |
81 meanTempoIndex = (tempoRange - 1)/2; | |
82 meanTempo = tempoMinimumOffset + meanTempoIndex; | |
83 */ | |
84 meanPhaseIndex = (phaseRange - 1)/2; | |
85 | |
86 currentBestTempo = meanTempoIndex; | |
87 currentBestPhase = meanPhaseIndex; | |
88 | |
89 printf("Mean tempo initialised at %i and mean index %i\n", meanTempo, meanTempoIndex); | |
90 int minDrawTempo = minimumTempo + minimumPhaseHop - 4; | |
91 int maxDrawTempo = maximumTempo + maximumPhaseHop + 4; | |
92 | |
93 ofTrueTypeFont::setGlobalDpi(72); | |
94 timesFont.loadFont("TimesNewRoman.ttf", 18, true, true); | |
95 timesFont.setLineHeight(18.0f); | |
96 timesFont.setLetterSpacing(1.037); | |
97 | |
98 } | |
99 | |
100 void TimingAnalyser::initialiseRoutes(){ | |
101 } | |
102 | |
103 void TimingAnalyser::clearData(){ | |
104 timingData.clear(); | |
105 basicInterOnsetInterval.clear(); | |
106 beatPosition.clear(); | |
107 } | |
108 | |
109 void TimingAnalyser::setTempoLimits(const int& newGlobalTempo){ | |
110 | |
111 meanGlobalTempo = newGlobalTempo; | |
112 tempoMinimumOffset = meanGlobalTempo - (tempoScalar*(tempoRange-1)/2); | |
113 meanTempoIndex = (tempoRange - 1)/2; | |
114 meanTempo = tempoMinimumOffset + meanTempoIndex*tempoScalar; | |
115 | |
116 printf("Setting tempo to %i units i.e. %f ms\n", newGlobalTempo, getTempo(meanTempoIndex)); | |
117 } | |
118 | |
119 | |
120 double TimingAnalyser::getPhaseIndexFromEventTime(const double& eventTime){ | |
121 return eventTime / phaseScalar; | |
122 } | |
123 | |
124 double TimingAnalyser::getTempoInUnits(const double& tempoInMs){ | |
125 return tempoInMs / tempoScalar; | |
126 } | |
127 | |
128 //NEW UPDATE METHOD | |
129 double TimingAnalyser::getBestMinimumCost(const int& newTempoInUnits, const int& newPhaseInUnits, Route& r){ | |
130 //new method to check all points in last matrix | |
131 //new phase is the phase point from zero in units | |
132 //including any offsets etc | |
133 | |
134 double cost = 0; | |
135 double bestCost = INFINITY; | |
136 Path* lastPath; | |
137 int minPhase = 0; | |
138 int minTempo = 0; | |
139 r.tempoHop = 0; | |
140 r.phaseHop = 0; | |
141 | |
142 //int tempoHop, phaseHop; no need | |
143 if (pathHistory.size() > 0) | |
144 lastPath = &pathHistory[pathHistory.size()-1]; | |
145 else{ | |
146 // printf("Initiating first path...\n"); | |
147 } | |
148 | |
149 for (int tempo = 0;tempo < tempoRange;tempo++){ | |
150 | |
151 for (int phase = 0;phase < phaseRange;phase++){ | |
152 //change tempo | |
153 cost = 0; | |
154 int phasePoint = 0; | |
155 | |
156 if (pathHistory.size() > 0){ | |
157 cost = (*lastPath).currentRoute[tempo][phase].totalCost; | |
158 cost += tempoCost * abs(newTempoInUnits - (tempo + (*lastPath).tempoOffset)); | |
159 | |
160 //our point then projects forwards at the new tempo | |
161 phasePoint = phase + (*lastPath).phaseOffset + newTempoInUnits; | |
162 //phase cost is | |
163 cost += phaseHopCost(newPhaseInUnits - phasePoint);//i.e. phaseCost * abs(newPhaseInUnits - phasePoint); | |
164 }//else it's the first point and all previous cost is zero | |
165 | |
166 if (cost < bestCost){ | |
167 bestCost = cost; | |
168 minPhase = phase; | |
169 minTempo = tempo; | |
170 | |
171 if (pathHistory.size() > 0){ | |
172 r.tempoHop = newTempoInUnits - (tempo + (*lastPath).tempoOffset); | |
173 r.phaseHop = newPhaseInUnits - phasePoint; | |
174 } else{ | |
175 r.tempoHop = 0; | |
176 r.phaseHop = 0; | |
177 } | |
178 | |
179 r.previousTempoIndex = tempo; | |
180 r.previousPhaseIndex = phase; | |
181 | |
182 }//end if mew minimum | |
183 } | |
184 } | |
185 | |
186 /* printf("best cost for tempo-phase pair %i, %i from tempo %i and phase %i, hop %i, %i is %.2f\n", | |
187 newTempoInUnits, newPhaseInUnits, | |
188 minTempo, minPhase, | |
189 r.tempoHop, r.phaseHop, bestCost); | |
190 */ return bestCost; | |
191 } | |
192 | |
193 | |
194 void TimingAnalyser::printCostMatrix(const RouteMatrix& m){ | |
195 printf("\n"); | |
196 for (int i = 0; i< m.size();i++){ | |
197 printf("Tempo %.1f (index %i)\n", getTempo(i), i); | |
198 for (int k = 0;k < m[i].size();k++){ | |
199 printf("%.1f (new %.1f + prev %.1f (%i,%i)), ", m[i][k].totalCost, | |
200 m[i][k].addedCost,m[i][k].previousCost, | |
201 m[i][k].previousTempoIndex, m[i][k].previousPhaseIndex ); | |
202 } | |
203 printf("\n"); | |
204 } | |
205 } | |
206 | |
207 void TimingAnalyser::updateCostToPoint(const int& eventTime, const int& eventBeatLocation){ | |
208 | |
209 // previousLogMatrix = logProbabilityMatrix;//store previous matrix - settings are in pathHistory vector | |
210 printf("\nTiming Analyser: update cost to %i, \n", eventTime); | |
211 //event beat location %i is 1 so don't bother printing | |
212 // printf("old phase range is %.1f to %.1f\n", getPhase(0), getPhase(phaseRange-1)); | |
213 // printf("old tempo range is %.1f to %.1f\n", getTempo(0), getTempo(tempoRange-1)); | |
214 | |
215 int interval = 1; | |
216 | |
217 //setting the new path offset points | |
218 RouteMatrix r_mat; | |
219 Path* lastPath; | |
220 | |
221 Path p;//the new path point | |
222 p.tempoOffset = tempoMinimumOffset;//for now keep it the same | |
223 | |
224 if (pathHistory.size() > 0){ | |
225 lastPath = &pathHistory[pathHistory.size()-1]; | |
226 int ioi = (int) getTempoInUnits(eventTime - (*lastPath).eventTimeObserved); | |
227 p.tempoOffset = ioi - ((tempoRange-1)/2); | |
228 tempoMinimumOffset = p.tempoOffset; | |
229 printf("New time %i, last time %i diff %i: IOI is %i\n", | |
230 eventTime, (*lastPath).eventTimeObserved, | |
231 (eventTime - (*lastPath).eventTimeObserved), ioi); | |
232 } | |
233 | |
234 //and in tempo units! | |
235 p.phaseOffset = round(getPhaseIndexFromEventTime(eventTime)) + phaseMinimumOffset;//in units | |
236 //abandoned - now using the offset too - dont need - (phaseRange/2) as in the get phase fn | |
237 printf("NEW PHASE and tempo offsets %i and %i, \n", p.phaseOffset, p.tempoOffset); | |
238 //end set offset pts | |
239 | |
240 for (int tempoIndex = 0;tempoIndex < logProbabilityMatrix.size();tempoIndex++){ | |
241 RouteVector r_vec; | |
242 | |
243 for (int phase = 0;phase < logProbabilityMatrix[tempoIndex].size();phase++){ | |
244 | |
245 | |
246 Route r; | |
247 | |
248 double bestCost = getBestMinimumCost(p.tempoOffset + tempoIndex, phase + p.phaseOffset, r); | |
249 double newCost = fabs(getPhaseIndexFromEventTime(eventTime) - (p.phaseOffset + phase)); | |
250 | |
251 //this is the phase position that would lead to this current tempo and phase iwthout any hopping | |
252 //the bestPreviousCost calculates the best oposition including hopping | |
253 | |
254 //then we compare the past cost | |
255 | |
256 r.previousCost = bestCost; | |
257 | |
258 //this is the best past cost that can get us to current location | |
259 //then we need new cost | |
260 | |
261 r.addedCost = newCost; | |
262 | |
263 //r.globalPhaseOffset = globalTimeOffset; | |
264 | |
265 logProbabilityMatrix[tempoIndex][phase] = bestCost + newCost; | |
266 r.totalCost = bestCost + newCost; | |
267 | |
268 //just to check we get this right! | |
269 r.tempoIndex = tempoIndex; | |
270 r.phaseIndex = phase; | |
271 | |
272 r_vec.push_back(r); | |
273 } | |
274 r_mat.push_back(r_vec); | |
275 } | |
276 //history.push_back(r_mat); | |
277 | |
278 //printHistory(); - defunct as using pathHistory instead | |
279 //printBestPath(); | |
280 //printf("Global offset %i ph min off %i\n", globalTimeOffset, phaseMinimumOffset); | |
281 | |
282 //new method using Path class | |
283 p.currentRoute = r_mat; | |
284 | |
285 globalTimeOffset = p.phaseOffset; | |
286 | |
287 //store the settings for the matrix at this time step | |
288 //p.globalPhaseOffset = globalTimeOffset; | |
289 // p.tempoOffset = tempoMinimumOffset; | |
290 | |
291 setBestTempoAndPhase(p); | |
292 lastBeatPosition = eventBeatLocation; | |
293 printf(" error %i ", (int)(eventTime - getPhase(currentBestPhase, globalTimeOffset))); | |
294 p.phaseShiftApplied = recentPhaseShift;//this is what we did in the recent step | |
295 p.tempoShiftApplied = recentTempoShift; | |
296 //so is the shift by which current stored matrix and indices differ from the last path | |
297 | |
298 p.eventTimeObserved = eventTime; | |
299 p.costMatrix = logProbabilityMatrix; | |
300 | |
301 if (pathHistory.size() > 0){ | |
302 //then can calculate inter-onset interval | |
303 int ioi = eventTime - pathHistory[pathHistory.size()-1].eventTimeObserved; | |
304 basicInterOnsetInterval.push_back(ioi); | |
305 printf("ioi for time %i is %i\n", eventTime, ioi); | |
306 } | |
307 printf("New PATH offset is %i\n", p.phaseOffset); | |
308 pathHistory.push_back(p); | |
309 | |
310 //prints the complete cost matrix at every step | |
311 //printCostMatrix(p.currentRoute); | |
312 | |
313 | |
314 if (printHistory) | |
315 printPathHistory(); | |
316 | |
317 // printf(", SHIFT (%i, %i)\n", p.phaseShiftApplied, p.tempoShiftApplied); | |
318 | |
319 //loaded the new prob matrix to the main log one | |
320 //now looking to shift | |
321 | |
322 //change global offset to match new position | |
323 // printLogMatrix(); | |
324 | |
325 | |
326 previousLogMatrix = logProbabilityMatrix;//store previous matrix - settings are in pathHistory vector | |
327 | |
328 // printLogMatrix(); | |
329 | |
330 } | |
331 | |
332 | |
333 | |
334 void TimingAnalyser::printIOIdata(){ | |
335 for (int i = 0;i < basicInterOnsetInterval.size();i++){ | |
336 printf("IOI[%i] : %i\n", i, basicInterOnsetInterval[i]); | |
337 } | |
338 } | |
339 | |
340 | |
341 void TimingAnalyser::checkShiftMatrix(){ | |
342 | |
343 if (moveMatrixToOptimalCostPosition){ | |
344 int phaseShiftIndex = (int)(meanPhaseIndex + movementFactor*(currentBestPhase - meanPhaseIndex)); | |
345 int tempoShiftIndex = (int)(meanTempoIndex + movementFactor*(currentBestTempo - meanTempoIndex)); | |
346 printf("current best tempo %i, best phase %i, mean tempo %i, shift of %i\n", currentBestTempo, currentBestPhase, meanTempoIndex, tempoShiftIndex); | |
347 shiftMatrixToMatchBestPhase(phaseShiftIndex); | |
348 shiftMatrixToMatchBestTempo(tempoShiftIndex); | |
349 } | |
350 | |
351 } | |
352 | |
353 | |
354 | |
355 void TimingAnalyser::shiftMatrixToMatchBestPhase(const int& bestPhaseIndex){ | |
356 | |
357 // int bestPhaseIndex = pathHistory[pathHistory.size()-1].bestPhase; | |
358 printf("SHIFT:: BEST PHASE %i, ", bestPhaseIndex); | |
359 | |
360 int shift = bestPhaseIndex - meanPhaseIndex; | |
361 DoubleMatrix tmpMat = logProbabilityMatrix; | |
362 | |
363 for (int t = 0;t < tempoRange;t++){ | |
364 for (int p = 0;p < phaseRange;p++){ | |
365 int switchIndex = p + shift; | |
366 if (switchIndex < phaseRange && switchIndex >= 0){ | |
367 logProbabilityMatrix[t][p] = tmpMat[t][switchIndex]; | |
368 }else{ | |
369 logProbabilityMatrix[t][p] = INFINITY; | |
370 } | |
371 } | |
372 } | |
373 globalTimeOffset += shift * phaseScalar; | |
374 printf("new phase shift of %i and offset is %i \n", shift, globalTimeOffset); | |
375 recentPhaseShift = shift; | |
376 } | |
377 | |
378 void TimingAnalyser::shiftMatrixToMatchBestTempo(const int& bestTempoIndex){ | |
379 | |
380 // int bestPhaseIndex = pathHistory[pathHistory.size()-1].bestPhase; | |
381 printf("SHIFT:: BEST TEMPO %i, ", bestTempoIndex); | |
382 | |
383 int shift = bestTempoIndex - meanTempoIndex; | |
384 DoubleMatrix tmpMat = logProbabilityMatrix; | |
385 | |
386 for (int t = 0;t < tempoRange;t++){ | |
387 for (int p = 0;p < phaseRange;p++){ | |
388 int switchIndex = t + shift; | |
389 if (switchIndex < tempoRange && switchIndex >= 0){ | |
390 logProbabilityMatrix[t][p] = tmpMat[switchIndex][p]; | |
391 }else{ | |
392 logProbabilityMatrix[t][p] = INFINITY; | |
393 } | |
394 } | |
395 } | |
396 | |
397 tempoMinimumOffset += shift * tempoScalar; | |
398 printf("new tempo shift of %i and tempo offset is %i \n", shift, tempoMinimumOffset); | |
399 recentTempoShift = shift; | |
400 } | |
401 | |
402 | |
403 bool TimingAnalyser::checkPhaseRange(const int& phaseToCheck){ | |
404 | |
405 if (phaseToCheck < phaseRange && phaseToCheck >= 0) | |
406 return true; | |
407 else | |
408 return false; | |
409 } | |
410 | |
411 bool TimingAnalyser::checkTempoRange(const int& tempoToCheck){ | |
412 | |
413 if (tempoToCheck < tempoRange && tempoToCheck >= 0) | |
414 return true; | |
415 else | |
416 return false; | |
417 } | |
418 | |
419 double TimingAnalyser::phaseHopCost(const int& phaseHop){ | |
420 //printf("phase hop %i returns %f", phaseHop, phaseCost*abs(phaseHop)); | |
421 return phaseCost*abs(phaseHop); | |
422 } | |
423 | |
424 double TimingAnalyser::tempoHopCost(const int& tempoHop){ | |
425 return tempoCost*abs(tempoHop); | |
426 } | |
427 | |
428 double TimingAnalyser::getTempo(const int& tempoIndex){ | |
429 return (tempoMinimumOffset + tempoIndex*tempoScalar); | |
430 } | |
431 | |
432 double TimingAnalyser::getPhase(const int& phaseIndex){ | |
433 return globalTimeOffset + (phaseIndex*phaseScalar); | |
434 } | |
435 | |
436 double TimingAnalyser::getTempo(const int& tempoIndex, const int& tempoOffset){ | |
437 return ((tempoOffset + tempoIndex)*tempoScalar); | |
438 } | |
439 | |
440 double TimingAnalyser::getPhase(const int& phaseIndex, const int& phaseOffset){ | |
441 //phase offset for middle of matrix | |
442 return (phaseOffset + phaseIndex)*phaseScalar; | |
443 } | |
444 | |
445 int TimingAnalyser::getTempoIndex(const double& tempo){ | |
446 double index = tempo; | |
447 index -= tempoMinimumOffset; | |
448 index /= tempoScalar; | |
449 return (int)round(index); | |
450 } | |
451 | |
452 | |
453 int TimingAnalyser::getPhaseIndex(const double& location){ | |
454 double index = location; | |
455 index -= globalTimeOffset; | |
456 index -= phaseMinimumOffset; | |
457 index /= phaseScalar; | |
458 return (int)round(index); | |
459 } | |
460 | |
461 | |
462 double TimingAnalyser::getMinimumTransitionCost(const int& interval, const int& tempoIndex, const int& phaseIndex){ | |
463 | |
464 double minimumCost = 100000000.0;//very big | |
465 | |
466 //need to get the location of where we are now | |
467 int endLocation = 0;//getBeatLocation() | |
468 | |
469 // int zeroLocation = getBeatLocation(); | |
470 // getLocation(0, 0, beatPosition + interval); | |
471 int tempo = 0; | |
472 | |
473 // for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ | |
474 for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ | |
475 | |
476 //double tempoTransition = getTempoTransitionCost(tempoIndex - tempo); | |
477 //double phaseTransition = getPhaseTransitionCost(phaseindex - phase); | |
478 | |
479 | |
480 | |
481 } | |
482 // } | |
483 | |
484 return minimumCost; | |
485 } | |
486 | |
487 | |
488 double TimingAnalyser::getMaximum(){ | |
489 double maxVal = 1.0; | |
490 for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ | |
491 for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ | |
492 if (logProbabilityMatrix[tempo][phase] > maxVal && logProbabilityMatrix[tempo][phase] < INFINITY) | |
493 maxVal = logProbabilityMatrix[tempo][phase]; | |
494 } | |
495 } | |
496 return maxVal; | |
497 } | |
498 | |
499 void TimingAnalyser::drawCostMatrix(){ | |
500 double maximum = getMaximum(); | |
501 double width = ofGetWidth() / phaseRange; | |
502 double height = ofGetHeight() / tempoRange; | |
503 | |
504 for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ | |
505 for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ | |
506 | |
507 ofSetColor(0,0, 255.0*(maximum - logProbabilityMatrix[tempo][phase])/maximum ); | |
508 ofRect(phase*width, tempo*height, width, height); | |
509 ofSetColor(255,255,255); | |
510 | |
511 string infoStr = "T "+ofToString(getTempo(tempo, tempoMinimumOffset)); | |
512 infoStr += "\nP "+ofToString(phase)+" ("+ofToString(getPhase(phase, globalTimeOffset))+")"; | |
513 infoStr += "\n"+ofToString(logProbabilityMatrix[tempo][phase]); | |
514 | |
515 // ofDrawBitmapString(infoStr, phase*width + 10, tempo*height + 10); | |
516 } | |
517 } | |
518 | |
519 } | |
520 | |
521 | |
522 void TimingAnalyser::setBestTempoAndPhase(Path& newPath){ | |
523 | |
524 double bestCost = newPath.currentRoute[currentBestTempo][currentBestPhase].totalCost;// INFINITY; | |
525 for (int t = 0;t < tempoRange;t++){ | |
526 for (int p = 0;p < phaseRange;p++){ | |
527 if (newPath.currentRoute[t][p].totalCost < bestCost){ | |
528 bestCost = newPath.currentRoute[t][p].totalCost; | |
529 currentBestPhase = p; | |
530 currentBestTempo = t; | |
531 } | |
532 } | |
533 } | |
534 | |
535 newPath.bestTempo = currentBestTempo;// bestTempo; | |
536 newPath.bestPhase = currentBestPhase;// bestPhase; | |
537 | |
538 printf("BEST TEMPO %i, PHASE %i :: ", currentBestTempo, currentBestPhase); | |
539 string tString = "Tempo "+ofToString(getTempo(currentBestTempo, tempoMinimumOffset)); | |
540 tString += ", Phase "+ofToString(getPhase(currentBestPhase, globalTimeOffset)); | |
541 tString += ", BEST COST "+ofToString(bestCost); | |
542 //tstring += ", error "+ofToString() | |
543 printf("i.e. %s", tString.c_str()); | |
544 | |
545 } | |
546 | |
547 void TimingAnalyser::printPathHistory(){ | |
548 /* printf("tempo %i (%3.0f), phase %i (%3.0f)\n", pathHistory[i].bestTempo, | |
549 getTempo(pathHistory[i].bestTempo, pathHistory[i].tempoOffset), | |
550 pathHistory[i].bestPhase, | |
551 getPhase(pathHistory[i].bestPhase, pathHistory[i].globalPhaseOffset) | |
552 ); | |
553 */ | |
554 int tempo, phase; | |
555 | |
556 RouteMatrix* tmpRoute; | |
557 int pathIndex = pathHistory.size()-1; | |
558 if ( pathHistory.size() > 0){ | |
559 pathHistory[0].phaseShiftApplied = 0;//hack to fix non zero | |
560 tempo = pathHistory[pathHistory.size()-1].bestTempo; | |
561 phase = pathHistory[pathHistory.size()-1].bestPhase; | |
562 | |
563 printf("PATH BEST[%i] tempo %i (%3.0f), phase %i (%3.0f) at COST %3.3f preCOST %3.3f addCOST %3.3f\n", | |
564 pathIndex, | |
565 tempo, getTempo(tempo, pathHistory[pathHistory.size()-1].tempoOffset), | |
566 phase, getPhase(phase, pathHistory[pathHistory.size()-1].phaseOffset), | |
567 pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].totalCost, | |
568 pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].previousCost, | |
569 pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].addedCost | |
570 ); | |
571 }//end if | |
572 | |
573 | |
574 while (pathIndex >= 0 && pathIndex < pathHistory.size()){ | |
575 // printf("index %i, history size %i\n", pathIndex, pathHistory.size()); | |
576 tmpRoute = &(pathHistory[pathIndex].currentRoute); | |
577 int previousTempo = (*tmpRoute)[tempo][phase].previousTempoIndex; | |
578 int previousPhase = (*tmpRoute)[tempo][phase].previousPhaseIndex;// + pathHistory[pathIndex].phaseShiftApplied; | |
579 //above was error on 24/12 that created wrong results - it is already included! | |
580 | |
581 printf("PTH[%i](%i,%i)\total{%3.2f}\t(prevCost %3.2f (%3.2f, %3.2f, %3.2f)\t:: adddedCost %3.2f\t: hop (%i, %i)\tprevious (%i, %i) applied (%i, %i){%i, %i}, ", | |
582 pathIndex, | |
583 tempo, phase, | |
584 (*tmpRoute)[tempo][phase].totalCost, | |
585 (*tmpRoute)[tempo][phase].previousCost, | |
586 (*tmpRoute)[tempo][phase].preHopCost, | |
587 (*tmpRoute)[tempo][phase].tempoHopCost, | |
588 (*tmpRoute)[tempo][phase].phaseHopCost, | |
589 (*tmpRoute)[tempo][phase].addedCost, | |
590 (*tmpRoute)[tempo][phase].tempoHop, | |
591 (*tmpRoute)[tempo][phase].phaseHop, | |
592 previousTempo, previousPhase, | |
593 pathHistory[pathIndex].tempoShiftApplied, pathHistory[pathIndex].phaseShiftApplied, | |
594 pathHistory[pathIndex].tempoOffset, pathHistory[pathIndex].phaseOffset | |
595 | |
596 ); | |
597 | |
598 if (pathIndex > 0){ | |
599 printf("Tempo %3.0f Phase %3.0f (PRED %3.0f) @event %i (%3.0f)\n", | |
600 getTempo(previousTempo, pathHistory[pathIndex-1].tempoOffset), | |
601 getPhase(previousPhase, pathHistory[pathIndex-1].phaseOffset), | |
602 getPhase(previousPhase, pathHistory[pathIndex-1].phaseOffset) + getTempo(previousTempo, pathHistory[pathIndex-1].tempoOffset), | |
603 pathHistory[pathIndex].eventTimeObserved, | |
604 getPhase(phase, pathHistory[pathIndex].phaseOffset) | |
605 ); | |
606 } | |
607 | |
608 tempo = previousTempo; | |
609 phase = previousPhase; | |
610 | |
611 pathIndex--; | |
612 } | |
613 | |
614 | |
615 } | |
616 | |
617 | |
618 void TimingAnalyser::processPathHistory(){ | |
619 | |
620 printf("Process path history...\n"); | |
621 | |
622 timingData.clear(); | |
623 | |
624 maximumTempo = 0; | |
625 minimumTempo = INFINITY; | |
626 | |
627 minimumPhaseHop = 0; | |
628 maximumPhaseHop = 0; | |
629 | |
630 printf("\n"); | |
631 int tempo, phase; | |
632 | |
633 RouteMatrix* tmpRoute; | |
634 int pathIndex = pathHistory.size()-1; | |
635 int observedPhasePoint; | |
636 int observedTempo, observedEventTime; | |
637 int storedTempoHop = 0; | |
638 int storedTempo = 0; | |
639 | |
640 if ( pathHistory.size() > 0){ | |
641 pathHistory[0].phaseShiftApplied = 0;//hack to fix non zero | |
642 tempo = pathHistory[pathIndex].bestTempo; | |
643 phase = pathHistory[pathIndex].bestPhase; | |
644 observedPhasePoint = getPhase(phase, pathHistory[pathIndex].phaseOffset); | |
645 | |
646 } | |
647 | |
648 while (pathIndex >= 0){ | |
649 tmpRoute = &(pathHistory[pathIndex].currentRoute); | |
650 int previousTempo = (*tmpRoute)[tempo][phase].previousTempoIndex; | |
651 int previousPhase = (*tmpRoute)[tempo][phase].previousPhaseIndex; | |
652 IntVector v; | |
653 | |
654 observedTempo = storedTempo; | |
655 observedPhasePoint = (int)round(getPhase(phase, pathHistory[pathIndex].phaseOffset)); | |
656 observedEventTime = pathHistory[pathIndex].eventTimeObserved; | |
657 | |
658 if (observedTempo > maximumTempo) | |
659 maximumTempo = observedTempo; | |
660 | |
661 if (observedTempo < minimumTempo && observedTempo > 0) | |
662 minimumTempo = observedTempo; | |
663 | |
664 int phaseHop = (*tmpRoute)[tempo][phase].phaseHop; | |
665 | |
666 if (phaseHop < minimumPhaseHop) | |
667 minimumPhaseHop = phaseHop; | |
668 | |
669 if (phaseHop > maximumPhaseHop) | |
670 maximumPhaseHop = phaseHop; | |
671 | |
672 v.push_back(observedTempo);//timingdata[][0] | |
673 v.push_back(observedPhasePoint);//timingdata[][1] | |
674 v.push_back(observedEventTime);//timingdata[][2] | |
675 v.push_back(storedTempoHop); | |
676 v.push_back( (*tmpRoute)[tempo][phase].phaseHop);//timingData[][4] | |
677 v.push_back(observedEventTime - observedPhasePoint);//timingdata[][5] | |
678 | |
679 timingData.push_back(v); | |
680 | |
681 | |
682 printf("Index %i TEMPO %i, PHASE %i, EVENT %i HOP (%i, %i) error %i \n", | |
683 (int) timingData.size(), | |
684 observedTempo, observedPhasePoint, | |
685 observedEventTime, storedTempoHop, | |
686 (*tmpRoute)[tempo][phase].phaseHop, | |
687 (observedEventTime - observedPhasePoint)); | |
688 //checking this ned to align tempo, observed phase and observed events | |
689 | |
690 //N.B. MUST STORE THIS FROM FUTURE POINT | |
691 storedTempo = (int)round(getTempo(tempo, pathHistory[pathIndex].tempoOffset)); | |
692 storedTempoHop = (*tmpRoute)[tempo][phase].tempoHop; | |
693 | |
694 tempo = previousTempo; | |
695 phase = previousPhase; | |
696 | |
697 pathIndex--; | |
698 } | |
699 | |
700 reverse(timingData.begin(), timingData.end()); | |
701 | |
702 clearHistogram(); | |
703 | |
704 for (int i = 0;i < timingData.size();i++){ | |
705 printf("Rev index %i tempo %i, phase hop %i, error %i, beat location %i\n", i, | |
706 timingData[i][0], timingData[i][4], timingData[i][5], (int) beatPosition[i]); | |
707 | |
708 int error = (int) timingData[i][4] + timingData[i][5]; | |
709 | |
710 if (abs(error) < 30 && (int)beatPosition[i] - 1 < timingHistogram.size()) | |
711 timingHistogram[(int)beatPosition[i] - 1].push_back(error); | |
712 } | |
713 | |
714 printf("Maximum is %f and min %f hopMin %i hopMax %i\n", maximumTempo, minimumTempo, minimumPhaseHop, maximumPhaseHop); | |
715 minDrawTempo = minimumTempo + minimumPhaseHop - 4; | |
716 maxDrawTempo = maximumTempo + maximumPhaseHop + 4; | |
717 | |
718 getHistogramResults(); | |
719 | |
720 } | |
721 | |
722 void TimingAnalyser::clearHistogram(){ | |
723 | |
724 timingHistogram.clear(); | |
725 IntVector v; | |
726 for (int i = 0;i < 4;i++){ | |
727 v.clear(); | |
728 timingHistogram.push_back(v); | |
729 } | |
730 } | |
731 | |
732 | |
733 void TimingAnalyser::getHistogramResults(){ | |
734 DoubleVector results; | |
735 for (int i = 0;i < 4;i++){ | |
736 double total; | |
737 for (int k = 0; k < timingHistogram[i].size();k++){ | |
738 total += timingHistogram[i][k]; | |
739 } | |
740 total /= timingHistogram[i].size(); | |
741 results.push_back(total); | |
742 printf("Mean at beat %i is %.2f\n", i, results[i]); | |
743 } | |
744 } | |
745 | |
746 #pragma mark -drawTempoCurve | |
747 void TimingAnalyser::drawTempoCurve(){ | |
748 if (timingData.size() > 0){ | |
749 screenWidth = ofGetWidth(); | |
750 screenHeight = ofGetHeight(); | |
751 double height = screenHeight; | |
752 // int minDrawTempo = minimumTempo + minimumPhaseHop - 4; | |
753 // int maxDrawTempo = maximumTempo + maximumPhaseHop + 4; | |
754 | |
755 if (maximumTempo > 0) | |
756 height /= (maxDrawTempo - minDrawTempo); | |
757 | |
758 double bpmMaxTempo = msToBpm(minDrawTempo); | |
759 double bpmMinTempo = msToBpm(maxDrawTempo); | |
760 double bpmHeight = screenHeight / (bpmMaxTempo - bpmMinTempo); | |
761 | |
762 //int minHeightPixels = minHeight * height; | |
763 | |
764 ofBackground(255); | |
765 double width = ofGetWidth()/numberOfPointsPerPage; | |
766 | |
767 int lastHeightPoint = getHeightPoint(height * (timingData[0][0] - minDrawTempo) ); | |
768 int newHeightPoint; | |
769 | |
770 double error; | |
771 int Xpoint; | |
772 | |
773 //horizonal lines for tempo | |
774 ofSetColor(150); | |
775 if(!drawBPM){ | |
776 int horizontalTempo = minDrawTempo + 20 - minDrawTempo%20; | |
777 // while (horizontalTempo > minDrawTempo) | |
778 // horizontalTempo -= 20; | |
779 while (horizontalTempo < maxDrawTempo){ | |
780 ofSetColor(150); | |
781 ofLine(0, getHeightPoint(height*(horizontalTempo - minDrawTempo)), screenWidth, getHeightPoint(height*(horizontalTempo - minDrawTempo))); | |
782 ofSetColor(50); | |
783 ofDrawBitmapString(ofToString(horizontalTempo), 20, getHeightPoint(height*(horizontalTempo - minDrawTempo))); | |
784 // timesFont.drawString(ofToString(horizontalTempo), 20, getHeightPoint(height*(horizontalTempo - minDrawTempo)));//FONT | |
785 horizontalTempo += 20; | |
786 }//end while | |
787 | |
788 } else{ | |
789 int resolution = 2; | |
790 | |
791 if (maxDrawTempo - minDrawTempo > 150) | |
792 resolution = 4; | |
793 if (maxDrawTempo - minDrawTempo > 400) | |
794 resolution = 8; | |
795 | |
796 int horizontalTempo = (int)bpmMinTempo + resolution - ((int)bpmMinTempo % resolution);//mod ten above min | |
797 while (horizontalTempo < bpmMaxTempo) { | |
798 int tmp = getHeightPoint(bpmHeight * (horizontalTempo - bpmMinTempo)); | |
799 ofSetColor(150); | |
800 ofLine(0, tmp , screenWidth, tmp); | |
801 ofSetColor(50); | |
802 ofDrawBitmapString(ofToString(horizontalTempo), 20, tmp+2); | |
803 std::string number = ofToString(horizontalTempo); | |
804 // timesFont.drawString(number, 20, tmp+2);//FONT | |
805 horizontalTempo += resolution; | |
806 } | |
807 | |
808 } | |
809 | |
810 //vertical bars | |
811 int solidBarEvery = 4;//normally every four beats | |
812 | |
813 int counter = 0; | |
814 for (int i = 0;i < timingData.size();i++){ | |
815 ofSetColor(200); | |
816 bool drawLine = false; | |
817 | |
818 | |
819 //this useful for drawing on ISMIR paper | |
820 if (mozartTriplets){ | |
821 //stronger lines on the bars | |
822 solidBarEvery = 12;//- pollini triplets | |
823 | |
824 if ((i % solidBarEvery == 0)){// || beatPosition[i] == 0 ){ | |
825 ofSetColor(80); | |
826 drawLine = true; | |
827 counter = 0; | |
828 } | |
829 | |
830 //normal every three (eighth notes) | |
831 if (i % 3 == 0 && mozartTriplets){ | |
832 drawLine = true; | |
833 } | |
834 } | |
835 | |
836 | |
837 int beatsPerBar = 4;//set 3 for some beatles tracks | |
838 int mainBeat = 0; | |
839 | |
840 if ((int)i % beatsPerBar == mainBeat && !mozartTriplets){ | |
841 //was BeatPosoiton[i] - dodgy | |
842 drawLine = true; | |
843 } | |
844 /* | |
845 if (i == tempoVariationEndIndex){ | |
846 ofSetColor(200, 0,0); | |
847 drawLine = true; | |
848 } | |
849 */ | |
850 | |
851 if (drawLine){ | |
852 ofLine((i-startPoint) * width, 0, (i-startPoint) * width, ofGetHeight()); | |
853 } | |
854 } | |
855 | |
856 | |
857 for (int i = startPoint+1;i < min((int)timingData.size(), startPoint + numberOfPointsPerPage);i++){ | |
858 if (!drawIOIintervals){ | |
859 ofSetColor(0,0,0); | |
860 Xpoint = (i-startPoint) * width ; | |
861 if (!drawBPM) | |
862 newHeightPoint = getHeightPoint(height * (timingData[i][0] - minDrawTempo)); | |
863 else | |
864 newHeightPoint = getHeightPoint(bpmHeight * (msToBpm(timingData[i][0]) - bpmMinTempo)); | |
865 | |
866 ofLine((i-startPoint-1) * width, lastHeightPoint,Xpoint, newHeightPoint); | |
867 lastHeightPoint = newHeightPoint; | |
868 | |
869 error = timingData[i][2] - timingData[i][1]; | |
870 int phaseHop = timingData[i][4]; | |
871 | |
872 if (!blackAndWhite) | |
873 ofSetColor(255,0,0); | |
874 else | |
875 ofSetColor(155); | |
876 | |
877 if (drawExpressiveTimingData) | |
878 ofLine(Xpoint, newHeightPoint, Xpoint, newHeightPoint - (phaseHop * height)); | |
879 //line up from tempo to where we observe point | |
880 | |
881 if (!blackAndWhite) | |
882 ofSetColor(0,0, 155); | |
883 else | |
884 ofSetColor(60); | |
885 | |
886 if (drawExpressiveTimingData) | |
887 ofCircle(Xpoint, newHeightPoint - ((phaseHop + error) * height), 2); | |
888 // ofLine((i-startPoint) * width , screenHeight/2, (i-startPoint) * width , (screenHeight/2)*(1+(timingData[i][3]/60.0))); | |
889 | |
890 if (!blackAndWhite) | |
891 ofSetColor(0,0,255); | |
892 ofLine(((playingIndex)-startPoint) * width, 0, ((playingIndex)-startPoint) * width, screenHeight); | |
893 | |
894 }//if not draw IOI | |
895 | |
896 if (drawIOIintervals){ | |
897 ofSetColor(160,160,160); | |
898 ofLine((i-startPoint-1) * width, getHeightPoint(height * (basicInterOnsetInterval[i-1]- minDrawTempo)), | |
899 (i-startPoint) * width, getHeightPoint(height * (basicInterOnsetInterval[i]- minDrawTempo)) ); | |
900 } | |
901 // ofLine((i-startPoint) * width , screenHeight/2, (i-startPoint) * width , (screenHeight/2)*(1+(timingData[i][4]/60.0))); | |
902 | |
903 }//end for | |
904 | |
905 } | |
906 | |
907 } | |
908 | |
909 | |
910 void TimingAnalyser::widenDrawWindow(){ | |
911 maxDrawTempo += 2; | |
912 minDrawTempo -= 2; | |
913 } | |
914 | |
915 | |
916 | |
917 | |
918 void TimingAnalyser::narrowDrawWindow(){ | |
919 maxDrawTempo -= 2; | |
920 minDrawTempo += 2; | |
921 } | |
922 | |
923 void TimingAnalyser::moveDrawWindowUp(){ | |
924 maxDrawTempo += 2; | |
925 minDrawTempo += 2; | |
926 } | |
927 | |
928 void TimingAnalyser::moveDrawWindowDown(){ | |
929 maxDrawTempo -= 2; | |
930 minDrawTempo -= 2; | |
931 } | |
932 | |
933 int TimingAnalyser::getIndexAtMouseXposition(const int& Xpos){ | |
934 int numberPointsIn = (int)round(Xpos * numberOfPointsPerPage / ofGetWidth()); | |
935 | |
936 printf("number pts %i size %i , start %i no. in from left %i\n", | |
937 numberOfPointsPerPage, (int)timingData.size(), | |
938 startPoint, numberPointsIn); | |
939 | |
940 numberPointsIn += startPoint; | |
941 | |
942 printf("MOUSE X IS %i == %i\n", Xpos, numberPointsIn); | |
943 | |
944 return min((int)timingData.size(), numberPointsIn); | |
945 } | |
946 | |
947 int TimingAnalyser::getHeightPoint(float f){ | |
948 return (int)round(screenHeight - f); | |
949 } | |
950 | |
951 | |
952 | |
953 void TimingAnalyser::printMatrix(DoubleMatrix& logMatrix){ | |
954 for (int t = 0;t < logMatrix.size();t++){ | |
955 for (int p = 0;p < logMatrix[t].size();p++){ | |
956 printf("(%i,%i)= %2.1f ", t, p, logMatrix[t][p]); | |
957 } | |
958 printf("\n"); | |
959 } | |
960 | |
961 } | |
962 | |
963 void TimingAnalyser::printLogMatrix(){ | |
964 printf("\n"); | |
965 for (int p = 0;p < phaseRange;p++){ | |
966 printf("LOG M [%i] %2.2f, ", p, logProbabilityMatrix[0][p]); | |
967 } | |
968 printf("offset %i\n", globalTimeOffset); | |
969 } | |
970 | |
971 void TimingAnalyser::exportTimingData(){ | |
972 ofstream ofs(timingDataFilepath.c_str()); | |
973 // ofs << "output timng data size " << (int) timingData.size() << "IOI size " << (int)basicInterOnsetInterval.size() << endl; | |
974 | |
975 for (int i = 0;i < min((int)timingData.size(), (int) basicInterOnsetInterval.size());i++){ | |
976 for (int k = 0; k < 5;k++){ | |
977 ofs << timingData[i][k] << "\t"; | |
978 } | |
979 ofs << basicInterOnsetInterval[i] << "\t"; | |
980 ofs << endl; | |
981 } | |
982 | |
983 } | |
984 | |
985 void TimingAnalyser::importTimingData(std::string importFileName){ | |
986 ifstream ifs(importFileName.c_str()); | |
987 printf("IMPORT FILE %s\n", importFileName.c_str()); | |
988 timingData.clear(); | |
989 string value; | |
990 int count = 0; | |
991 //Notation n; | |
992 IntVector v; | |
993 while ( ifs.good() ) | |
994 { | |
995 getline ( ifs, value, '\n' ); // read a string until next enter command | |
996 // cout << "disp " << string( value, 0, value.length()-1 ) << endl; // display value removing the first and the last character from it | |
997 | |
998 //printf("size of line is %i\n", (int)value.size()); | |
999 v.clear(); | |
1000 | |
1001 if (value.size() > 0){ | |
1002 | |
1003 string::size_type start = value.find_first_not_of(" \t\v"); | |
1004 string part = value.substr(start, string::npos); | |
1005 string otherPart = value; | |
1006 printf("input line%i : '%s'\n", count, otherPart.c_str()); | |
1007 size_t found; | |
1008 found=part.find_first_of("\t\n"); | |
1009 size_t startC = 0; | |
1010 int r = 0; | |
1011 while (found!=string::npos){ | |
1012 string section = otherPart.substr(startC, found - startC); | |
1013 int my_int = atoi(section.c_str()); | |
1014 v.push_back(my_int); | |
1015 printf("timing[%i][%i] ", count, r, my_int); | |
1016 printf("section '%s'\n", section.c_str()); | |
1017 | |
1018 startC= otherPart.find_first_not_of("\t\n",found); | |
1019 found = otherPart.find_first_of("\t\n",found+1); | |
1020 r++; | |
1021 } | |
1022 timingData.push_back(v); | |
1023 }//end if > 0 | |
1024 | |
1025 count++; | |
1026 | |
1027 } | |
1028 | |
1029 | |
1030 basicInterOnsetInterval.clear(); | |
1031 | |
1032 maximumTempo = 0; | |
1033 minimumTempo = INFINITY; | |
1034 | |
1035 for (int i = 0;i < max(0, (int)timingData.size()-1);i++){ | |
1036 printf("TEMPO %i %i IOI %i\n", timingData[i][0], timingData[i][1], timingData[i][4]); | |
1037 | |
1038 basicInterOnsetInterval.push_back(timingData[i][5]); | |
1039 | |
1040 int observedTempo = timingData[i][0]; | |
1041 // printf("observed %i\n", observedTempo); | |
1042 | |
1043 if (observedTempo > maximumTempo) | |
1044 maximumTempo = observedTempo; | |
1045 | |
1046 if (observedTempo < minimumTempo && observedTempo > 0) | |
1047 minimumTempo = observedTempo; | |
1048 | |
1049 } | |
1050 | |
1051 | |
1052 printf("min t %f, Max t %f\n", minimumTempo, maximumTempo); | |
1053 } | |
1054 | |
1055 | |
1056 void TimingAnalyser::exportProcessedBeatTimes(const double& firstBeatTime){ | |
1057 ofstream ofs(processedBeatTimesFilepath.c_str()); | |
1058 | |
1059 for (int i = 0;i < min((int)timingData.size(), (int) basicInterOnsetInterval.size());i++){ | |
1060 double beatTime = (timingData[i][1] + firstBeatTime)/1000.0; | |
1061 printf("Beat %i : %f\n", i, beatTime); | |
1062 ofs << beatTime; | |
1063 ofs << endl; | |
1064 } | |
1065 } | |
1066 | |
1067 | |
1068 double TimingAnalyser::msToBpm(const double& ms){ | |
1069 return 60000./ms; | |
1070 } | |
1071 | |
1072 | |
1073 void TimingAnalyser::calculateTempoLimits(){ | |
1074 | |
1075 maximumTempo = 0; | |
1076 minimumTempo = INFINITY; | |
1077 | |
1078 for (int i = 0;i < max(0, (int)timingData.size()-1);i++){ | |
1079 | |
1080 int observedTempo = timingData[i][0]; | |
1081 | |
1082 if (observedTempo > maximumTempo) | |
1083 maximumTempo = observedTempo; | |
1084 | |
1085 if (observedTempo < minimumTempo && observedTempo > 0) | |
1086 minimumTempo = observedTempo; | |
1087 | |
1088 } | |
1089 | |
1090 tempoVariationStartIndex = min(4, (int)timingData.size()); | |
1091 tempoVariationEndIndex = max(0, (int)timingData.size() - 4); | |
1092 printf("VARIATION TO BE CALCULATED BETWEEN %i and %i\n", tempoVariationStartIndex, tempoVariationEndIndex); | |
1093 } | |
1094 | |
1095 double TimingAnalyser::calculateTempoVariation(){ | |
1096 if (timingData.size() > tempoVariationStartIndex && tempoVariationEndIndex + 1< timingData.size()){ | |
1097 double mean = 0; | |
1098 | |
1099 for (int i = tempoVariationStartIndex;i <= tempoVariationEndIndex;i++){ | |
1100 mean += timingData[i][0]; | |
1101 } | |
1102 mean /= (tempoVariationEndIndex - tempoVariationStartIndex); | |
1103 double variation = 0; | |
1104 double fluctuation = 0; | |
1105 int lastValue = timingData[tempoVariationStartIndex][0]; | |
1106 | |
1107 for (int i = tempoVariationStartIndex;i <= tempoVariationEndIndex;i++){ | |
1108 variation += (timingData[i][0] - mean)*(timingData[i][0] - mean); | |
1109 fluctuation += abs(timingData[i][0] - lastValue); | |
1110 lastValue = timingData[i][0]; | |
1111 } | |
1112 variation /= (tempoVariationEndIndex - tempoVariationStartIndex); | |
1113 variation = sqrt(variation); | |
1114 fluctuation /= (tempoVariationEndIndex - tempoVariationStartIndex); | |
1115 | |
1116 double slope = (double) timingData[tempoVariationStartIndex][0] / timingData[tempoVariationEndIndex][0]; | |
1117 printf("TEMPO STATS:\nMean: %.2f\nVariance %.2f \nSlope %.1f per cent\nAverage delta Tempo %.2f", | |
1118 mean, variation, (slope*100.0), fluctuation); | |
1119 } | |
1120 | |
1121 } | |
1122 | |
1123 | |
1124 void TimingAnalyser::zoomIn(){ | |
1125 numberOfPointsPerPage /= 2; | |
1126 } | |
1127 | |
1128 | |
1129 void TimingAnalyser::zoomOut(){ | |
1130 numberOfPointsPerPage *= 2; | |
1131 } | |
1132 | |
1133 | |
1134 /* | |
1135 double TimingAnalyser::getCost(const int& eventTime, const int& eventLocation, const int& tempoIndex, const int& phaseIndex){ | |
1136 | |
1137 double interval = eventLocation - lastBeatPosition; | |
1138 double newLocation = getPhase(phaseIndex) + interval*getTempo(tempoIndex); | |
1139 double phaseCost = fabs(newLocation - eventTime); | |
1140 | |
1141 return phaseCost; | |
1142 } | |
1143 */ |