andrew@1: /* andrew@1: * TimingAnalyser.cpp andrew@1: * performanceTimingAnalyser andrew@1: * andrew@1: * Created by Andrew on 17/12/2011. andrew@1: * Copyright 2011 QMUL. All rights reserved. andrew@1: * andrew@1: */ andrew@1: andrew@1: #include "TimingAnalyser.h" andrew@1: andrew@1: //FROM TestApp.cpp andrew@1: //change these to your preferred filepaths for exporting the data andrew@1: //timingDataFilepath = "/Users/andrew/outputFile.txt";//here as decoded tempo and phase andrew@1: //change this to your filepath for storing the final path as output andrew@1: //can then load it back in easily without reanalysing using this... andrew@1: // importFileFromStoredData(fileToLoad); andrew@1: //processBeatTimesFilepath = "//Users/andrew/processedBeats";//here as a list of beat times andrew@1: //this latter will be a smoothed version of the original andrew@1: andrew@1: //RESTRICT PHASE HOP POSSIBLE andrew@1: andrew@1: andrew@1: //Correct or DELETE this BeatPosition variable - what is it? Why used? andrew@1: andrew@1: andrew@1: TimingAnalyser::TimingAnalyser(){ andrew@1: andrew@1: moveMatrixToOptimalCostPosition = true; andrew@1: andrew@2: //resolution in ms andrew@2: tempoScalar = 1.0; andrew@2: phaseScalar = 1.0; andrew@1: andrew@1: phaseCost = 1000.4;//a phase jump is 1.5 (y-x) where y now becomes the predicted position andrew@1: tempoCost = 2.8;//a tempo jump of z msec per period is charged at 2z units andrew@1: andrew@1: drawIOIintervals = false; andrew@1: andrew@1: drawExpressiveTimingData = true; andrew@1: andrew@1: printHistory = false; andrew@1: mozartTriplets = false; andrew@1: andrew@1: movementFactor = 0.5; andrew@1: drawBPM = true; andrew@1: andrew@1: //COST VARIABLES - Assuming that a simple error is costing linear (t-x) where x is predicted time andrew@1: andrew@1: andrew@1: blackAndWhite = true; andrew@1: andrew@1: setTempoLimits(400); andrew@1: andrew@1: andrew@1: //index between which we look at the variation andrew@1: tempoVariationStartIndex = 4; andrew@1: andrew@1: andrew@1: DoubleVector v; andrew@1: v.assign(phaseRange, 0.0); andrew@1: logProbabilityMatrix.assign(tempoRange, v); andrew@1: previousLogMatrix = logProbabilityMatrix; andrew@1: andrew@1: //[tempo][phase] andrew@1: phaseMinimumOffset = -1 * phaseScalar*(phaseRange - 1)/2;//offset in millis andrew@1: globalTimeOffset = 0;//global offset in millis andrew@1: andrew@1: lastBeatPosition = 0; andrew@1: andrew@1: andrew@1: numberOfPointsPerPage = 80; andrew@1: startPoint = 0; andrew@1: andrew@1: // initialiseRoutes(); andrew@1: andrew@1: recentPhaseShift = 0; andrew@1: recentTempoShift = 0; andrew@1: andrew@1: /* meanGlobalTempo = 440; andrew@1: tempoMinimumOffset = meanGlobalTempo - (tempoRange-1)/2; andrew@1: meanTempoIndex = (tempoRange - 1)/2; andrew@1: meanTempo = tempoMinimumOffset + meanTempoIndex; andrew@1: */ andrew@1: meanPhaseIndex = (phaseRange - 1)/2; andrew@1: andrew@1: currentBestTempo = meanTempoIndex; andrew@1: currentBestPhase = meanPhaseIndex; andrew@1: andrew@1: printf("Mean tempo initialised at %i and mean index %i\n", meanTempo, meanTempoIndex); andrew@1: int minDrawTempo = minimumTempo + minimumPhaseHop - 4; andrew@1: int maxDrawTempo = maximumTempo + maximumPhaseHop + 4; andrew@1: andrew@1: ofTrueTypeFont::setGlobalDpi(72); andrew@1: timesFont.loadFont("TimesNewRoman.ttf", 18, true, true); andrew@1: timesFont.setLineHeight(18.0f); andrew@1: timesFont.setLetterSpacing(1.037); andrew@1: andrew@1: } andrew@1: andrew@1: void TimingAnalyser::initialiseRoutes(){ andrew@1: } andrew@1: andrew@1: void TimingAnalyser::clearData(){ andrew@1: timingData.clear(); andrew@1: basicInterOnsetInterval.clear(); andrew@1: beatPosition.clear(); andrew@1: } andrew@1: andrew@1: void TimingAnalyser::setTempoLimits(const int& newGlobalTempo){ andrew@1: andrew@1: meanGlobalTempo = newGlobalTempo; andrew@1: tempoMinimumOffset = meanGlobalTempo - (tempoScalar*(tempoRange-1)/2); andrew@1: meanTempoIndex = (tempoRange - 1)/2; andrew@1: meanTempo = tempoMinimumOffset + meanTempoIndex*tempoScalar; andrew@1: andrew@1: printf("Setting tempo to %i units i.e. %f ms\n", newGlobalTempo, getTempo(meanTempoIndex)); andrew@1: } andrew@1: andrew@1: andrew@1: double TimingAnalyser::getPhaseIndexFromEventTime(const double& eventTime){ andrew@1: return eventTime / phaseScalar; andrew@1: } andrew@1: andrew@1: double TimingAnalyser::getTempoInUnits(const double& tempoInMs){ andrew@1: return tempoInMs / tempoScalar; andrew@1: } andrew@1: andrew@1: //NEW UPDATE METHOD andrew@1: double TimingAnalyser::getBestMinimumCost(const int& newTempoInUnits, const int& newPhaseInUnits, Route& r){ andrew@1: //new method to check all points in last matrix andrew@1: //new phase is the phase point from zero in units andrew@1: //including any offsets etc andrew@1: andrew@1: double cost = 0; andrew@1: double bestCost = INFINITY; andrew@1: Path* lastPath; andrew@1: int minPhase = 0; andrew@1: int minTempo = 0; andrew@1: r.tempoHop = 0; andrew@1: r.phaseHop = 0; andrew@1: andrew@1: //int tempoHop, phaseHop; no need andrew@1: if (pathHistory.size() > 0) andrew@1: lastPath = &pathHistory[pathHistory.size()-1]; andrew@1: else{ andrew@1: // printf("Initiating first path...\n"); andrew@1: } andrew@1: andrew@1: for (int tempo = 0;tempo < tempoRange;tempo++){ andrew@1: andrew@1: for (int phase = 0;phase < phaseRange;phase++){ andrew@1: //change tempo andrew@1: cost = 0; andrew@1: int phasePoint = 0; andrew@1: andrew@1: if (pathHistory.size() > 0){ andrew@1: cost = (*lastPath).currentRoute[tempo][phase].totalCost; andrew@1: cost += tempoCost * abs(newTempoInUnits - (tempo + (*lastPath).tempoOffset)); andrew@1: andrew@1: //our point then projects forwards at the new tempo andrew@1: phasePoint = phase + (*lastPath).phaseOffset + newTempoInUnits; andrew@1: //phase cost is andrew@1: cost += phaseHopCost(newPhaseInUnits - phasePoint);//i.e. phaseCost * abs(newPhaseInUnits - phasePoint); andrew@1: }//else it's the first point and all previous cost is zero andrew@1: andrew@1: if (cost < bestCost){ andrew@1: bestCost = cost; andrew@1: minPhase = phase; andrew@1: minTempo = tempo; andrew@1: andrew@1: if (pathHistory.size() > 0){ andrew@1: r.tempoHop = newTempoInUnits - (tempo + (*lastPath).tempoOffset); andrew@1: r.phaseHop = newPhaseInUnits - phasePoint; andrew@1: } else{ andrew@1: r.tempoHop = 0; andrew@1: r.phaseHop = 0; andrew@1: } andrew@1: andrew@1: r.previousTempoIndex = tempo; andrew@1: r.previousPhaseIndex = phase; andrew@1: andrew@1: }//end if mew minimum andrew@1: } andrew@1: } andrew@1: andrew@1: /* printf("best cost for tempo-phase pair %i, %i from tempo %i and phase %i, hop %i, %i is %.2f\n", andrew@1: newTempoInUnits, newPhaseInUnits, andrew@1: minTempo, minPhase, andrew@1: r.tempoHop, r.phaseHop, bestCost); andrew@1: */ return bestCost; andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::printCostMatrix(const RouteMatrix& m){ andrew@1: printf("\n"); andrew@1: for (int i = 0; i< m.size();i++){ andrew@1: printf("Tempo %.1f (index %i)\n", getTempo(i), i); andrew@1: for (int k = 0;k < m[i].size();k++){ andrew@1: printf("%.1f (new %.1f + prev %.1f (%i,%i)), ", m[i][k].totalCost, andrew@1: m[i][k].addedCost,m[i][k].previousCost, andrew@1: m[i][k].previousTempoIndex, m[i][k].previousPhaseIndex ); andrew@1: } andrew@1: printf("\n"); andrew@1: } andrew@1: } andrew@1: andrew@2: void TimingAnalyser::updatePlayIndex(const double& seconds){ andrew@2: double millis = seconds * 1000.0; andrew@2: andrew@2: while (playingIndex < timingData.size() && getNoteTime(playingIndex) < millis) andrew@2: playingIndex++; andrew@2: andrew@2: while (playingIndex > 0 && getNoteTime(playingIndex) > millis) andrew@2: playingIndex--; andrew@2: andrew@2: if (playingIndex > startPoint + numberOfPointsPerPage) andrew@2: startPoint += numberOfPointsPerPage;//scrolling with play andrew@2: andrew@2: } andrew@2: andrew@2: double TimingAnalyser::getNoteTime(const int& index){ andrew@2: return offsetToFirstPoint + timingData[index][2];// andrew@2: } andrew@2: andrew@1: void TimingAnalyser::updateCostToPoint(const int& eventTime, const int& eventBeatLocation){ andrew@1: andrew@1: // previousLogMatrix = logProbabilityMatrix;//store previous matrix - settings are in pathHistory vector andrew@1: printf("\nTiming Analyser: update cost to %i, \n", eventTime); andrew@1: //event beat location %i is 1 so don't bother printing andrew@1: // printf("old phase range is %.1f to %.1f\n", getPhase(0), getPhase(phaseRange-1)); andrew@1: // printf("old tempo range is %.1f to %.1f\n", getTempo(0), getTempo(tempoRange-1)); andrew@1: andrew@1: int interval = 1; andrew@1: andrew@1: //setting the new path offset points andrew@1: RouteMatrix r_mat; andrew@1: Path* lastPath; andrew@1: andrew@1: Path p;//the new path point andrew@1: p.tempoOffset = tempoMinimumOffset;//for now keep it the same andrew@1: andrew@1: if (pathHistory.size() > 0){ andrew@1: lastPath = &pathHistory[pathHistory.size()-1]; andrew@1: int ioi = (int) getTempoInUnits(eventTime - (*lastPath).eventTimeObserved); andrew@1: p.tempoOffset = ioi - ((tempoRange-1)/2); andrew@1: tempoMinimumOffset = p.tempoOffset; andrew@1: printf("New time %i, last time %i diff %i: IOI is %i\n", andrew@1: eventTime, (*lastPath).eventTimeObserved, andrew@1: (eventTime - (*lastPath).eventTimeObserved), ioi); andrew@1: } andrew@1: andrew@1: //and in tempo units! andrew@1: p.phaseOffset = round(getPhaseIndexFromEventTime(eventTime)) + phaseMinimumOffset;//in units andrew@1: //abandoned - now using the offset too - dont need - (phaseRange/2) as in the get phase fn andrew@1: printf("NEW PHASE and tempo offsets %i and %i, \n", p.phaseOffset, p.tempoOffset); andrew@1: //end set offset pts andrew@1: andrew@1: for (int tempoIndex = 0;tempoIndex < logProbabilityMatrix.size();tempoIndex++){ andrew@1: RouteVector r_vec; andrew@1: andrew@1: for (int phase = 0;phase < logProbabilityMatrix[tempoIndex].size();phase++){ andrew@1: andrew@1: andrew@1: Route r; andrew@1: andrew@1: double bestCost = getBestMinimumCost(p.tempoOffset + tempoIndex, phase + p.phaseOffset, r); andrew@1: double newCost = fabs(getPhaseIndexFromEventTime(eventTime) - (p.phaseOffset + phase)); andrew@1: andrew@1: //this is the phase position that would lead to this current tempo and phase iwthout any hopping andrew@1: //the bestPreviousCost calculates the best oposition including hopping andrew@1: andrew@1: //then we compare the past cost andrew@1: andrew@1: r.previousCost = bestCost; andrew@1: andrew@1: //this is the best past cost that can get us to current location andrew@1: //then we need new cost andrew@1: andrew@1: r.addedCost = newCost; andrew@1: andrew@1: //r.globalPhaseOffset = globalTimeOffset; andrew@1: andrew@1: logProbabilityMatrix[tempoIndex][phase] = bestCost + newCost; andrew@1: r.totalCost = bestCost + newCost; andrew@1: andrew@1: //just to check we get this right! andrew@1: r.tempoIndex = tempoIndex; andrew@1: r.phaseIndex = phase; andrew@1: andrew@1: r_vec.push_back(r); andrew@1: } andrew@1: r_mat.push_back(r_vec); andrew@1: } andrew@1: //history.push_back(r_mat); andrew@1: andrew@1: //printHistory(); - defunct as using pathHistory instead andrew@1: //printBestPath(); andrew@1: //printf("Global offset %i ph min off %i\n", globalTimeOffset, phaseMinimumOffset); andrew@1: andrew@1: //new method using Path class andrew@1: p.currentRoute = r_mat; andrew@1: andrew@1: globalTimeOffset = p.phaseOffset; andrew@1: andrew@1: //store the settings for the matrix at this time step andrew@1: //p.globalPhaseOffset = globalTimeOffset; andrew@1: // p.tempoOffset = tempoMinimumOffset; andrew@1: andrew@1: setBestTempoAndPhase(p); andrew@1: lastBeatPosition = eventBeatLocation; andrew@1: printf(" error %i ", (int)(eventTime - getPhase(currentBestPhase, globalTimeOffset))); andrew@1: p.phaseShiftApplied = recentPhaseShift;//this is what we did in the recent step andrew@1: p.tempoShiftApplied = recentTempoShift; andrew@1: //so is the shift by which current stored matrix and indices differ from the last path andrew@1: andrew@1: p.eventTimeObserved = eventTime; andrew@1: p.costMatrix = logProbabilityMatrix; andrew@1: andrew@1: if (pathHistory.size() > 0){ andrew@1: //then can calculate inter-onset interval andrew@1: int ioi = eventTime - pathHistory[pathHistory.size()-1].eventTimeObserved; andrew@1: basicInterOnsetInterval.push_back(ioi); andrew@1: printf("ioi for time %i is %i\n", eventTime, ioi); andrew@1: } andrew@1: printf("New PATH offset is %i\n", p.phaseOffset); andrew@1: pathHistory.push_back(p); andrew@1: andrew@1: //prints the complete cost matrix at every step andrew@1: //printCostMatrix(p.currentRoute); andrew@1: andrew@1: andrew@1: if (printHistory) andrew@1: printPathHistory(); andrew@1: andrew@1: // printf(", SHIFT (%i, %i)\n", p.phaseShiftApplied, p.tempoShiftApplied); andrew@1: andrew@1: //loaded the new prob matrix to the main log one andrew@1: //now looking to shift andrew@1: andrew@1: //change global offset to match new position andrew@1: // printLogMatrix(); andrew@1: andrew@1: andrew@1: previousLogMatrix = logProbabilityMatrix;//store previous matrix - settings are in pathHistory vector andrew@1: andrew@1: // printLogMatrix(); andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: andrew@1: void TimingAnalyser::printIOIdata(){ andrew@1: for (int i = 0;i < basicInterOnsetInterval.size();i++){ andrew@1: printf("IOI[%i] : %i\n", i, basicInterOnsetInterval[i]); andrew@1: } andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::checkShiftMatrix(){ andrew@1: andrew@1: if (moveMatrixToOptimalCostPosition){ andrew@1: int phaseShiftIndex = (int)(meanPhaseIndex + movementFactor*(currentBestPhase - meanPhaseIndex)); andrew@1: int tempoShiftIndex = (int)(meanTempoIndex + movementFactor*(currentBestTempo - meanTempoIndex)); andrew@1: printf("current best tempo %i, best phase %i, mean tempo %i, shift of %i\n", currentBestTempo, currentBestPhase, meanTempoIndex, tempoShiftIndex); andrew@1: shiftMatrixToMatchBestPhase(phaseShiftIndex); andrew@1: shiftMatrixToMatchBestTempo(tempoShiftIndex); andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: andrew@1: void TimingAnalyser::shiftMatrixToMatchBestPhase(const int& bestPhaseIndex){ andrew@1: andrew@1: // int bestPhaseIndex = pathHistory[pathHistory.size()-1].bestPhase; andrew@1: printf("SHIFT:: BEST PHASE %i, ", bestPhaseIndex); andrew@1: andrew@1: int shift = bestPhaseIndex - meanPhaseIndex; andrew@1: DoubleMatrix tmpMat = logProbabilityMatrix; andrew@1: andrew@1: for (int t = 0;t < tempoRange;t++){ andrew@1: for (int p = 0;p < phaseRange;p++){ andrew@1: int switchIndex = p + shift; andrew@1: if (switchIndex < phaseRange && switchIndex >= 0){ andrew@1: logProbabilityMatrix[t][p] = tmpMat[t][switchIndex]; andrew@1: }else{ andrew@1: logProbabilityMatrix[t][p] = INFINITY; andrew@1: } andrew@1: } andrew@1: } andrew@1: globalTimeOffset += shift * phaseScalar; andrew@1: printf("new phase shift of %i and offset is %i \n", shift, globalTimeOffset); andrew@1: recentPhaseShift = shift; andrew@1: } andrew@1: andrew@1: void TimingAnalyser::shiftMatrixToMatchBestTempo(const int& bestTempoIndex){ andrew@1: andrew@1: // int bestPhaseIndex = pathHistory[pathHistory.size()-1].bestPhase; andrew@1: printf("SHIFT:: BEST TEMPO %i, ", bestTempoIndex); andrew@1: andrew@1: int shift = bestTempoIndex - meanTempoIndex; andrew@1: DoubleMatrix tmpMat = logProbabilityMatrix; andrew@1: andrew@1: for (int t = 0;t < tempoRange;t++){ andrew@1: for (int p = 0;p < phaseRange;p++){ andrew@1: int switchIndex = t + shift; andrew@1: if (switchIndex < tempoRange && switchIndex >= 0){ andrew@1: logProbabilityMatrix[t][p] = tmpMat[switchIndex][p]; andrew@1: }else{ andrew@1: logProbabilityMatrix[t][p] = INFINITY; andrew@1: } andrew@1: } andrew@1: } andrew@1: andrew@1: tempoMinimumOffset += shift * tempoScalar; andrew@1: printf("new tempo shift of %i and tempo offset is %i \n", shift, tempoMinimumOffset); andrew@1: recentTempoShift = shift; andrew@1: } andrew@1: andrew@1: andrew@1: bool TimingAnalyser::checkPhaseRange(const int& phaseToCheck){ andrew@1: andrew@1: if (phaseToCheck < phaseRange && phaseToCheck >= 0) andrew@1: return true; andrew@1: else andrew@1: return false; andrew@1: } andrew@1: andrew@1: bool TimingAnalyser::checkTempoRange(const int& tempoToCheck){ andrew@1: andrew@1: if (tempoToCheck < tempoRange && tempoToCheck >= 0) andrew@1: return true; andrew@1: else andrew@1: return false; andrew@1: } andrew@1: andrew@1: double TimingAnalyser::phaseHopCost(const int& phaseHop){ andrew@1: //printf("phase hop %i returns %f", phaseHop, phaseCost*abs(phaseHop)); andrew@1: return phaseCost*abs(phaseHop); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::tempoHopCost(const int& tempoHop){ andrew@1: return tempoCost*abs(tempoHop); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::getTempo(const int& tempoIndex){ andrew@1: return (tempoMinimumOffset + tempoIndex*tempoScalar); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::getPhase(const int& phaseIndex){ andrew@1: return globalTimeOffset + (phaseIndex*phaseScalar); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::getTempo(const int& tempoIndex, const int& tempoOffset){ andrew@1: return ((tempoOffset + tempoIndex)*tempoScalar); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::getPhase(const int& phaseIndex, const int& phaseOffset){ andrew@1: //phase offset for middle of matrix andrew@1: return (phaseOffset + phaseIndex)*phaseScalar; andrew@1: } andrew@1: andrew@1: int TimingAnalyser::getTempoIndex(const double& tempo){ andrew@1: double index = tempo; andrew@1: index -= tempoMinimumOffset; andrew@1: index /= tempoScalar; andrew@1: return (int)round(index); andrew@1: } andrew@1: andrew@1: andrew@1: int TimingAnalyser::getPhaseIndex(const double& location){ andrew@1: double index = location; andrew@1: index -= globalTimeOffset; andrew@1: index -= phaseMinimumOffset; andrew@1: index /= phaseScalar; andrew@1: return (int)round(index); andrew@1: } andrew@1: andrew@1: andrew@1: double TimingAnalyser::getMinimumTransitionCost(const int& interval, const int& tempoIndex, const int& phaseIndex){ andrew@1: andrew@1: double minimumCost = 100000000.0;//very big andrew@1: andrew@1: //need to get the location of where we are now andrew@1: int endLocation = 0;//getBeatLocation() andrew@1: andrew@1: // int zeroLocation = getBeatLocation(); andrew@1: // getLocation(0, 0, beatPosition + interval); andrew@1: int tempo = 0; andrew@1: andrew@1: // for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ andrew@1: for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ andrew@1: andrew@1: //double tempoTransition = getTempoTransitionCost(tempoIndex - tempo); andrew@1: //double phaseTransition = getPhaseTransitionCost(phaseindex - phase); andrew@1: andrew@1: andrew@1: andrew@1: } andrew@1: // } andrew@1: andrew@1: return minimumCost; andrew@1: } andrew@1: andrew@1: andrew@1: double TimingAnalyser::getMaximum(){ andrew@1: double maxVal = 1.0; andrew@1: for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ andrew@1: for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ andrew@1: if (logProbabilityMatrix[tempo][phase] > maxVal && logProbabilityMatrix[tempo][phase] < INFINITY) andrew@1: maxVal = logProbabilityMatrix[tempo][phase]; andrew@1: } andrew@1: } andrew@1: return maxVal; andrew@1: } andrew@1: andrew@1: void TimingAnalyser::drawCostMatrix(){ andrew@1: double maximum = getMaximum(); andrew@1: double width = ofGetWidth() / phaseRange; andrew@1: double height = ofGetHeight() / tempoRange; andrew@1: andrew@1: for (int tempo = 0;tempo < logProbabilityMatrix.size();tempo++){ andrew@1: for (int phase = 0;phase < logProbabilityMatrix[tempo].size();phase++){ andrew@1: andrew@1: ofSetColor(0,0, 255.0*(maximum - logProbabilityMatrix[tempo][phase])/maximum ); andrew@1: ofRect(phase*width, tempo*height, width, height); andrew@1: ofSetColor(255,255,255); andrew@1: andrew@1: string infoStr = "T "+ofToString(getTempo(tempo, tempoMinimumOffset)); andrew@1: infoStr += "\nP "+ofToString(phase)+" ("+ofToString(getPhase(phase, globalTimeOffset))+")"; andrew@1: infoStr += "\n"+ofToString(logProbabilityMatrix[tempo][phase]); andrew@1: andrew@1: // ofDrawBitmapString(infoStr, phase*width + 10, tempo*height + 10); andrew@1: } andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::setBestTempoAndPhase(Path& newPath){ andrew@1: andrew@1: double bestCost = newPath.currentRoute[currentBestTempo][currentBestPhase].totalCost;// INFINITY; andrew@1: for (int t = 0;t < tempoRange;t++){ andrew@1: for (int p = 0;p < phaseRange;p++){ andrew@1: if (newPath.currentRoute[t][p].totalCost < bestCost){ andrew@1: bestCost = newPath.currentRoute[t][p].totalCost; andrew@1: currentBestPhase = p; andrew@1: currentBestTempo = t; andrew@1: } andrew@1: } andrew@1: } andrew@1: andrew@1: newPath.bestTempo = currentBestTempo;// bestTempo; andrew@1: newPath.bestPhase = currentBestPhase;// bestPhase; andrew@1: andrew@1: printf("BEST TEMPO %i, PHASE %i :: ", currentBestTempo, currentBestPhase); andrew@1: string tString = "Tempo "+ofToString(getTempo(currentBestTempo, tempoMinimumOffset)); andrew@1: tString += ", Phase "+ofToString(getPhase(currentBestPhase, globalTimeOffset)); andrew@1: tString += ", BEST COST "+ofToString(bestCost); andrew@1: //tstring += ", error "+ofToString() andrew@1: printf("i.e. %s", tString.c_str()); andrew@1: andrew@1: } andrew@1: andrew@1: void TimingAnalyser::printPathHistory(){ andrew@1: /* printf("tempo %i (%3.0f), phase %i (%3.0f)\n", pathHistory[i].bestTempo, andrew@1: getTempo(pathHistory[i].bestTempo, pathHistory[i].tempoOffset), andrew@1: pathHistory[i].bestPhase, andrew@1: getPhase(pathHistory[i].bestPhase, pathHistory[i].globalPhaseOffset) andrew@1: ); andrew@1: */ andrew@1: int tempo, phase; andrew@1: andrew@1: RouteMatrix* tmpRoute; andrew@1: int pathIndex = pathHistory.size()-1; andrew@1: if ( pathHistory.size() > 0){ andrew@1: pathHistory[0].phaseShiftApplied = 0;//hack to fix non zero andrew@1: tempo = pathHistory[pathHistory.size()-1].bestTempo; andrew@1: phase = pathHistory[pathHistory.size()-1].bestPhase; andrew@1: andrew@1: 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: pathIndex, andrew@1: tempo, getTempo(tempo, pathHistory[pathHistory.size()-1].tempoOffset), andrew@1: phase, getPhase(phase, pathHistory[pathHistory.size()-1].phaseOffset), andrew@1: pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].totalCost, andrew@1: pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].previousCost, andrew@1: pathHistory[pathHistory.size()-1].currentRoute[tempo][phase].addedCost andrew@1: ); andrew@1: }//end if andrew@1: andrew@1: andrew@1: while (pathIndex >= 0 && pathIndex < pathHistory.size()){ andrew@1: // printf("index %i, history size %i\n", pathIndex, pathHistory.size()); andrew@1: tmpRoute = &(pathHistory[pathIndex].currentRoute); andrew@1: int previousTempo = (*tmpRoute)[tempo][phase].previousTempoIndex; andrew@1: int previousPhase = (*tmpRoute)[tempo][phase].previousPhaseIndex;// + pathHistory[pathIndex].phaseShiftApplied; andrew@1: //above was error on 24/12 that created wrong results - it is already included! andrew@1: andrew@1: 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: pathIndex, andrew@1: tempo, phase, andrew@1: (*tmpRoute)[tempo][phase].totalCost, andrew@1: (*tmpRoute)[tempo][phase].previousCost, andrew@1: (*tmpRoute)[tempo][phase].preHopCost, andrew@1: (*tmpRoute)[tempo][phase].tempoHopCost, andrew@1: (*tmpRoute)[tempo][phase].phaseHopCost, andrew@1: (*tmpRoute)[tempo][phase].addedCost, andrew@1: (*tmpRoute)[tempo][phase].tempoHop, andrew@1: (*tmpRoute)[tempo][phase].phaseHop, andrew@1: previousTempo, previousPhase, andrew@1: pathHistory[pathIndex].tempoShiftApplied, pathHistory[pathIndex].phaseShiftApplied, andrew@1: pathHistory[pathIndex].tempoOffset, pathHistory[pathIndex].phaseOffset andrew@1: andrew@1: ); andrew@1: andrew@1: if (pathIndex > 0){ andrew@1: printf("Tempo %3.0f Phase %3.0f (PRED %3.0f) @event %i (%3.0f)\n", andrew@1: getTempo(previousTempo, pathHistory[pathIndex-1].tempoOffset), andrew@1: getPhase(previousPhase, pathHistory[pathIndex-1].phaseOffset), andrew@1: getPhase(previousPhase, pathHistory[pathIndex-1].phaseOffset) + getTempo(previousTempo, pathHistory[pathIndex-1].tempoOffset), andrew@1: pathHistory[pathIndex].eventTimeObserved, andrew@1: getPhase(phase, pathHistory[pathIndex].phaseOffset) andrew@1: ); andrew@1: } andrew@1: andrew@1: tempo = previousTempo; andrew@1: phase = previousPhase; andrew@1: andrew@1: pathIndex--; andrew@1: } andrew@1: andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::processPathHistory(){ andrew@1: andrew@1: printf("Process path history...\n"); andrew@1: andrew@1: timingData.clear(); andrew@1: andrew@1: maximumTempo = 0; andrew@1: minimumTempo = INFINITY; andrew@1: andrew@1: minimumPhaseHop = 0; andrew@1: maximumPhaseHop = 0; andrew@1: andrew@1: printf("\n"); andrew@1: int tempo, phase; andrew@1: andrew@1: RouteMatrix* tmpRoute; andrew@1: int pathIndex = pathHistory.size()-1; andrew@1: int observedPhasePoint; andrew@1: int observedTempo, observedEventTime; andrew@1: int storedTempoHop = 0; andrew@1: int storedTempo = 0; andrew@1: andrew@1: if ( pathHistory.size() > 0){ andrew@1: pathHistory[0].phaseShiftApplied = 0;//hack to fix non zero andrew@1: tempo = pathHistory[pathIndex].bestTempo; andrew@1: phase = pathHistory[pathIndex].bestPhase; andrew@1: observedPhasePoint = getPhase(phase, pathHistory[pathIndex].phaseOffset); andrew@1: andrew@1: } andrew@1: andrew@1: while (pathIndex >= 0){ andrew@1: tmpRoute = &(pathHistory[pathIndex].currentRoute); andrew@1: int previousTempo = (*tmpRoute)[tempo][phase].previousTempoIndex; andrew@1: int previousPhase = (*tmpRoute)[tempo][phase].previousPhaseIndex; andrew@1: IntVector v; andrew@1: andrew@1: observedTempo = storedTempo; andrew@1: observedPhasePoint = (int)round(getPhase(phase, pathHistory[pathIndex].phaseOffset)); andrew@1: observedEventTime = pathHistory[pathIndex].eventTimeObserved; andrew@1: andrew@1: if (observedTempo > maximumTempo) andrew@1: maximumTempo = observedTempo; andrew@1: andrew@1: if (observedTempo < minimumTempo && observedTempo > 0) andrew@1: minimumTempo = observedTempo; andrew@1: andrew@1: int phaseHop = (*tmpRoute)[tempo][phase].phaseHop; andrew@1: andrew@1: if (phaseHop < minimumPhaseHop) andrew@1: minimumPhaseHop = phaseHop; andrew@1: andrew@1: if (phaseHop > maximumPhaseHop) andrew@1: maximumPhaseHop = phaseHop; andrew@1: andrew@1: v.push_back(observedTempo);//timingdata[][0] andrew@1: v.push_back(observedPhasePoint);//timingdata[][1] andrew@1: v.push_back(observedEventTime);//timingdata[][2] andrew@1: v.push_back(storedTempoHop); andrew@1: v.push_back( (*tmpRoute)[tempo][phase].phaseHop);//timingData[][4] andrew@1: v.push_back(observedEventTime - observedPhasePoint);//timingdata[][5] andrew@1: andrew@1: timingData.push_back(v); andrew@1: andrew@1: andrew@1: printf("Index %i TEMPO %i, PHASE %i, EVENT %i HOP (%i, %i) error %i \n", andrew@1: (int) timingData.size(), andrew@1: observedTempo, observedPhasePoint, andrew@1: observedEventTime, storedTempoHop, andrew@1: (*tmpRoute)[tempo][phase].phaseHop, andrew@1: (observedEventTime - observedPhasePoint)); andrew@1: //checking this ned to align tempo, observed phase and observed events andrew@1: andrew@1: //N.B. MUST STORE THIS FROM FUTURE POINT andrew@1: storedTempo = (int)round(getTempo(tempo, pathHistory[pathIndex].tempoOffset)); andrew@1: storedTempoHop = (*tmpRoute)[tempo][phase].tempoHop; andrew@1: andrew@1: tempo = previousTempo; andrew@1: phase = previousPhase; andrew@1: andrew@1: pathIndex--; andrew@1: } andrew@1: andrew@1: reverse(timingData.begin(), timingData.end()); andrew@1: andrew@1: clearHistogram(); andrew@1: andrew@1: for (int i = 0;i < timingData.size();i++){ andrew@1: printf("Rev index %i tempo %i, phase hop %i, error %i, beat location %i\n", i, andrew@1: timingData[i][0], timingData[i][4], timingData[i][5], (int) beatPosition[i]); andrew@1: andrew@1: int error = (int) timingData[i][4] + timingData[i][5]; andrew@1: andrew@1: if (abs(error) < 30 && (int)beatPosition[i] - 1 < timingHistogram.size()) andrew@1: timingHistogram[(int)beatPosition[i] - 1].push_back(error); andrew@1: } andrew@1: andrew@1: printf("Maximum is %f and min %f hopMin %i hopMax %i\n", maximumTempo, minimumTempo, minimumPhaseHop, maximumPhaseHop); andrew@1: minDrawTempo = minimumTempo + minimumPhaseHop - 4; andrew@1: maxDrawTempo = maximumTempo + maximumPhaseHop + 4; andrew@1: andrew@1: getHistogramResults(); andrew@1: andrew@1: } andrew@1: andrew@1: void TimingAnalyser::clearHistogram(){ andrew@1: andrew@1: timingHistogram.clear(); andrew@1: IntVector v; andrew@1: for (int i = 0;i < 4;i++){ andrew@1: v.clear(); andrew@1: timingHistogram.push_back(v); andrew@1: } andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::getHistogramResults(){ andrew@1: DoubleVector results; andrew@1: for (int i = 0;i < 4;i++){ andrew@1: double total; andrew@1: for (int k = 0; k < timingHistogram[i].size();k++){ andrew@1: total += timingHistogram[i][k]; andrew@1: } andrew@1: total /= timingHistogram[i].size(); andrew@1: results.push_back(total); andrew@1: printf("Mean at beat %i is %.2f\n", i, results[i]); andrew@1: } andrew@1: } andrew@1: andrew@1: #pragma mark -drawTempoCurve andrew@1: void TimingAnalyser::drawTempoCurve(){ andrew@1: if (timingData.size() > 0){ andrew@1: screenWidth = ofGetWidth(); andrew@1: screenHeight = ofGetHeight(); andrew@1: double height = screenHeight; andrew@1: // int minDrawTempo = minimumTempo + minimumPhaseHop - 4; andrew@1: // int maxDrawTempo = maximumTempo + maximumPhaseHop + 4; andrew@1: andrew@1: if (maximumTempo > 0) andrew@1: height /= (maxDrawTempo - minDrawTempo); andrew@1: andrew@1: double bpmMaxTempo = msToBpm(minDrawTempo); andrew@1: double bpmMinTempo = msToBpm(maxDrawTempo); andrew@1: double bpmHeight = screenHeight / (bpmMaxTempo - bpmMinTempo); andrew@1: andrew@1: //int minHeightPixels = minHeight * height; andrew@1: andrew@1: ofBackground(255); andrew@1: double width = ofGetWidth()/numberOfPointsPerPage; andrew@1: andrew@1: int lastHeightPoint = getHeightPoint(height * (timingData[0][0] - minDrawTempo) ); andrew@1: int newHeightPoint; andrew@1: andrew@1: double error; andrew@1: int Xpoint; andrew@1: andrew@1: //horizonal lines for tempo andrew@1: ofSetColor(150); andrew@1: if(!drawBPM){ andrew@1: int horizontalTempo = minDrawTempo + 20 - minDrawTempo%20; andrew@1: // while (horizontalTempo > minDrawTempo) andrew@1: // horizontalTempo -= 20; andrew@1: while (horizontalTempo < maxDrawTempo){ andrew@1: ofSetColor(150); andrew@1: ofLine(0, getHeightPoint(height*(horizontalTempo - minDrawTempo)), screenWidth, getHeightPoint(height*(horizontalTempo - minDrawTempo))); andrew@1: ofSetColor(50); andrew@1: ofDrawBitmapString(ofToString(horizontalTempo), 20, getHeightPoint(height*(horizontalTempo - minDrawTempo))); andrew@1: // timesFont.drawString(ofToString(horizontalTempo), 20, getHeightPoint(height*(horizontalTempo - minDrawTempo)));//FONT andrew@1: horizontalTempo += 20; andrew@1: }//end while andrew@1: andrew@1: } else{ andrew@1: int resolution = 2; andrew@1: andrew@1: if (maxDrawTempo - minDrawTempo > 150) andrew@1: resolution = 4; andrew@1: if (maxDrawTempo - minDrawTempo > 400) andrew@1: resolution = 8; andrew@1: andrew@1: int horizontalTempo = (int)bpmMinTempo + resolution - ((int)bpmMinTempo % resolution);//mod ten above min andrew@1: while (horizontalTempo < bpmMaxTempo) { andrew@1: int tmp = getHeightPoint(bpmHeight * (horizontalTempo - bpmMinTempo)); andrew@1: ofSetColor(150); andrew@1: ofLine(0, tmp , screenWidth, tmp); andrew@1: ofSetColor(50); andrew@1: ofDrawBitmapString(ofToString(horizontalTempo), 20, tmp+2); andrew@1: std::string number = ofToString(horizontalTempo); andrew@1: // timesFont.drawString(number, 20, tmp+2);//FONT andrew@1: horizontalTempo += resolution; andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: //vertical bars andrew@1: int solidBarEvery = 4;//normally every four beats andrew@1: andrew@1: int counter = 0; andrew@1: for (int i = 0;i < timingData.size();i++){ andrew@1: ofSetColor(200); andrew@1: bool drawLine = false; andrew@1: andrew@1: andrew@1: //this useful for drawing on ISMIR paper andrew@1: if (mozartTriplets){ andrew@1: //stronger lines on the bars andrew@1: solidBarEvery = 12;//- pollini triplets andrew@1: andrew@1: if ((i % solidBarEvery == 0)){// || beatPosition[i] == 0 ){ andrew@1: ofSetColor(80); andrew@1: drawLine = true; andrew@1: counter = 0; andrew@1: } andrew@1: andrew@1: //normal every three (eighth notes) andrew@1: if (i % 3 == 0 && mozartTriplets){ andrew@1: drawLine = true; andrew@1: } andrew@1: } andrew@1: andrew@1: andrew@1: int beatsPerBar = 4;//set 3 for some beatles tracks andrew@1: int mainBeat = 0; andrew@1: andrew@1: if ((int)i % beatsPerBar == mainBeat && !mozartTriplets){ andrew@1: //was BeatPosoiton[i] - dodgy andrew@1: drawLine = true; andrew@1: } andrew@1: /* andrew@1: if (i == tempoVariationEndIndex){ andrew@1: ofSetColor(200, 0,0); andrew@1: drawLine = true; andrew@1: } andrew@1: */ andrew@1: andrew@1: if (drawLine){ andrew@1: ofLine((i-startPoint) * width, 0, (i-startPoint) * width, ofGetHeight()); andrew@1: } andrew@1: } andrew@1: andrew@1: andrew@1: for (int i = startPoint+1;i < min((int)timingData.size(), startPoint + numberOfPointsPerPage);i++){ andrew@1: if (!drawIOIintervals){ andrew@1: ofSetColor(0,0,0); andrew@1: Xpoint = (i-startPoint) * width ; andrew@1: if (!drawBPM) andrew@1: newHeightPoint = getHeightPoint(height * (timingData[i][0] - minDrawTempo)); andrew@1: else andrew@1: newHeightPoint = getHeightPoint(bpmHeight * (msToBpm(timingData[i][0]) - bpmMinTempo)); andrew@1: andrew@1: ofLine((i-startPoint-1) * width, lastHeightPoint,Xpoint, newHeightPoint); andrew@1: lastHeightPoint = newHeightPoint; andrew@1: andrew@1: error = timingData[i][2] - timingData[i][1]; andrew@1: int phaseHop = timingData[i][4]; andrew@1: andrew@1: if (!blackAndWhite) andrew@1: ofSetColor(255,0,0); andrew@1: else andrew@1: ofSetColor(155); andrew@1: andrew@1: if (drawExpressiveTimingData) andrew@1: ofLine(Xpoint, newHeightPoint, Xpoint, newHeightPoint - (phaseHop * height)); andrew@1: //line up from tempo to where we observe point andrew@1: andrew@1: if (!blackAndWhite) andrew@1: ofSetColor(0,0, 155); andrew@1: else andrew@1: ofSetColor(60); andrew@1: andrew@1: if (drawExpressiveTimingData) andrew@1: ofCircle(Xpoint, newHeightPoint - ((phaseHop + error) * height), 2); andrew@1: // ofLine((i-startPoint) * width , screenHeight/2, (i-startPoint) * width , (screenHeight/2)*(1+(timingData[i][3]/60.0))); andrew@1: andrew@2: //if (!blackAndWhite) andrew@2: ofSetColor(0,0,255); andrew@1: ofLine(((playingIndex)-startPoint) * width, 0, ((playingIndex)-startPoint) * width, screenHeight); andrew@1: andrew@1: }//if not draw IOI andrew@1: andrew@1: if (drawIOIintervals){ andrew@1: ofSetColor(160,160,160); andrew@1: ofLine((i-startPoint-1) * width, getHeightPoint(height * (basicInterOnsetInterval[i-1]- minDrawTempo)), andrew@1: (i-startPoint) * width, getHeightPoint(height * (basicInterOnsetInterval[i]- minDrawTempo)) ); andrew@1: } andrew@1: // ofLine((i-startPoint) * width , screenHeight/2, (i-startPoint) * width , (screenHeight/2)*(1+(timingData[i][4]/60.0))); andrew@1: andrew@1: }//end for andrew@1: andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@2: static const int moveAmount = 2; andrew@1: andrew@1: void TimingAnalyser::widenDrawWindow(){ andrew@2: maxDrawTempo += moveAmount; andrew@2: minDrawTempo -= moveAmount; andrew@1: } andrew@1: andrew@1: void TimingAnalyser::narrowDrawWindow(){ andrew@2: maxDrawTempo -= moveAmount; andrew@2: minDrawTempo += moveAmount; andrew@1: } andrew@1: andrew@1: void TimingAnalyser::moveDrawWindowUp(){ andrew@2: maxDrawTempo += moveAmount; andrew@2: minDrawTempo += moveAmount; andrew@1: } andrew@1: andrew@1: void TimingAnalyser::moveDrawWindowDown(){ andrew@2: maxDrawTempo -= moveAmount; andrew@2: minDrawTempo -= moveAmount; andrew@1: } andrew@1: andrew@1: int TimingAnalyser::getIndexAtMouseXposition(const int& Xpos){ andrew@1: int numberPointsIn = (int)round(Xpos * numberOfPointsPerPage / ofGetWidth()); andrew@1: andrew@1: printf("number pts %i size %i , start %i no. in from left %i\n", andrew@1: numberOfPointsPerPage, (int)timingData.size(), andrew@1: startPoint, numberPointsIn); andrew@1: andrew@1: numberPointsIn += startPoint; andrew@1: andrew@1: printf("MOUSE X IS %i == %i\n", Xpos, numberPointsIn); andrew@1: andrew@1: return min((int)timingData.size(), numberPointsIn); andrew@1: } andrew@1: andrew@1: int TimingAnalyser::getHeightPoint(float f){ andrew@1: return (int)round(screenHeight - f); andrew@1: } andrew@1: andrew@1: andrew@1: andrew@1: void TimingAnalyser::printMatrix(DoubleMatrix& logMatrix){ andrew@1: for (int t = 0;t < logMatrix.size();t++){ andrew@1: for (int p = 0;p < logMatrix[t].size();p++){ andrew@1: printf("(%i,%i)= %2.1f ", t, p, logMatrix[t][p]); andrew@1: } andrew@1: printf("\n"); andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: void TimingAnalyser::printLogMatrix(){ andrew@1: printf("\n"); andrew@1: for (int p = 0;p < phaseRange;p++){ andrew@1: printf("LOG M [%i] %2.2f, ", p, logProbabilityMatrix[0][p]); andrew@1: } andrew@1: printf("offset %i\n", globalTimeOffset); andrew@1: } andrew@1: andrew@1: void TimingAnalyser::exportTimingData(){ andrew@1: ofstream ofs(timingDataFilepath.c_str()); andrew@1: // ofs << "output timng data size " << (int) timingData.size() << "IOI size " << (int)basicInterOnsetInterval.size() << endl; andrew@1: andrew@1: for (int i = 0;i < min((int)timingData.size(), (int) basicInterOnsetInterval.size());i++){ andrew@1: for (int k = 0; k < 5;k++){ andrew@1: ofs << timingData[i][k] << "\t"; andrew@1: } andrew@1: ofs << basicInterOnsetInterval[i] << "\t"; andrew@1: ofs << endl; andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: void TimingAnalyser::importTimingData(std::string importFileName){ andrew@1: ifstream ifs(importFileName.c_str()); andrew@1: printf("IMPORT FILE %s\n", importFileName.c_str()); andrew@1: timingData.clear(); andrew@1: string value; andrew@1: int count = 0; andrew@1: //Notation n; andrew@1: IntVector v; andrew@1: while ( ifs.good() ) andrew@1: { andrew@1: getline ( ifs, value, '\n' ); // read a string until next enter command andrew@1: // cout << "disp " << string( value, 0, value.length()-1 ) << endl; // display value removing the first and the last character from it andrew@1: andrew@1: //printf("size of line is %i\n", (int)value.size()); andrew@1: v.clear(); andrew@1: andrew@1: if (value.size() > 0){ andrew@1: andrew@1: string::size_type start = value.find_first_not_of(" \t\v"); andrew@1: string part = value.substr(start, string::npos); andrew@1: string otherPart = value; andrew@1: printf("input line%i : '%s'\n", count, otherPart.c_str()); andrew@1: size_t found; andrew@1: found=part.find_first_of("\t\n"); andrew@1: size_t startC = 0; andrew@1: int r = 0; andrew@1: while (found!=string::npos){ andrew@1: string section = otherPart.substr(startC, found - startC); andrew@1: int my_int = atoi(section.c_str()); andrew@1: v.push_back(my_int); andrew@1: printf("timing[%i][%i] ", count, r, my_int); andrew@1: printf("section '%s'\n", section.c_str()); andrew@1: andrew@1: startC= otherPart.find_first_not_of("\t\n",found); andrew@1: found = otherPart.find_first_of("\t\n",found+1); andrew@1: r++; andrew@1: } andrew@1: timingData.push_back(v); andrew@1: }//end if > 0 andrew@1: andrew@1: count++; andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: basicInterOnsetInterval.clear(); andrew@1: andrew@1: maximumTempo = 0; andrew@1: minimumTempo = INFINITY; andrew@1: andrew@1: for (int i = 0;i < max(0, (int)timingData.size()-1);i++){ andrew@1: printf("TEMPO %i %i IOI %i\n", timingData[i][0], timingData[i][1], timingData[i][4]); andrew@1: andrew@1: basicInterOnsetInterval.push_back(timingData[i][5]); andrew@1: andrew@1: int observedTempo = timingData[i][0]; andrew@1: // printf("observed %i\n", observedTempo); andrew@1: andrew@1: if (observedTempo > maximumTempo) andrew@1: maximumTempo = observedTempo; andrew@1: andrew@1: if (observedTempo < minimumTempo && observedTempo > 0) andrew@1: minimumTempo = observedTempo; andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: printf("min t %f, Max t %f\n", minimumTempo, maximumTempo); andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::exportProcessedBeatTimes(const double& firstBeatTime){ andrew@1: ofstream ofs(processedBeatTimesFilepath.c_str()); andrew@1: andrew@1: for (int i = 0;i < min((int)timingData.size(), (int) basicInterOnsetInterval.size());i++){ andrew@1: double beatTime = (timingData[i][1] + firstBeatTime)/1000.0; andrew@1: printf("Beat %i : %f\n", i, beatTime); andrew@1: ofs << beatTime; andrew@1: ofs << endl; andrew@1: } andrew@1: } andrew@1: andrew@1: andrew@1: double TimingAnalyser::msToBpm(const double& ms){ andrew@1: return 60000./ms; andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::calculateTempoLimits(){ andrew@1: andrew@1: maximumTempo = 0; andrew@1: minimumTempo = INFINITY; andrew@1: andrew@1: for (int i = 0;i < max(0, (int)timingData.size()-1);i++){ andrew@1: andrew@1: int observedTempo = timingData[i][0]; andrew@1: andrew@1: if (observedTempo > maximumTempo) andrew@1: maximumTempo = observedTempo; andrew@1: andrew@1: if (observedTempo < minimumTempo && observedTempo > 0) andrew@1: minimumTempo = observedTempo; andrew@1: andrew@1: } andrew@1: andrew@1: tempoVariationStartIndex = min(4, (int)timingData.size()); andrew@1: tempoVariationEndIndex = max(0, (int)timingData.size() - 4); andrew@1: printf("VARIATION TO BE CALCULATED BETWEEN %i and %i\n", tempoVariationStartIndex, tempoVariationEndIndex); andrew@1: } andrew@1: andrew@1: double TimingAnalyser::calculateTempoVariation(){ andrew@1: if (timingData.size() > tempoVariationStartIndex && tempoVariationEndIndex + 1< timingData.size()){ andrew@1: double mean = 0; andrew@1: andrew@1: for (int i = tempoVariationStartIndex;i <= tempoVariationEndIndex;i++){ andrew@1: mean += timingData[i][0]; andrew@1: } andrew@1: mean /= (tempoVariationEndIndex - tempoVariationStartIndex); andrew@1: double variation = 0; andrew@1: double fluctuation = 0; andrew@1: int lastValue = timingData[tempoVariationStartIndex][0]; andrew@1: andrew@1: for (int i = tempoVariationStartIndex;i <= tempoVariationEndIndex;i++){ andrew@1: variation += (timingData[i][0] - mean)*(timingData[i][0] - mean); andrew@1: fluctuation += abs(timingData[i][0] - lastValue); andrew@1: lastValue = timingData[i][0]; andrew@1: } andrew@1: variation /= (tempoVariationEndIndex - tempoVariationStartIndex); andrew@1: variation = sqrt(variation); andrew@1: fluctuation /= (tempoVariationEndIndex - tempoVariationStartIndex); andrew@1: andrew@1: double slope = (double) timingData[tempoVariationStartIndex][0] / timingData[tempoVariationEndIndex][0]; andrew@1: printf("TEMPO STATS:\nMean: %.2f\nVariance %.2f \nSlope %.1f per cent\nAverage delta Tempo %.2f", andrew@1: mean, variation, (slope*100.0), fluctuation); andrew@1: } andrew@1: andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::zoomIn(){ andrew@1: numberOfPointsPerPage /= 2; andrew@1: } andrew@1: andrew@1: andrew@1: void TimingAnalyser::zoomOut(){ andrew@1: numberOfPointsPerPage *= 2; andrew@1: } andrew@1: andrew@1: andrew@1: /* andrew@1: double TimingAnalyser::getCost(const int& eventTime, const int& eventLocation, const int& tempoIndex, const int& phaseIndex){ andrew@1: andrew@1: double interval = eventLocation - lastBeatPosition; andrew@1: double newLocation = getPhase(phaseIndex) + interval*getTempo(tempoIndex); andrew@1: double phaseCost = fabs(newLocation - eventTime); andrew@1: andrew@1: return phaseCost; andrew@1: } andrew@1: */