annotate DrumTimingLoader_OF/PerformanceAnalyserSrc/TimingAnalyser.cpp @ 3:303edbbcf1bd tip

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