Mercurial > hg > midi-score-follower
view jnmr/midiEventHolder.cpp @ 36:5a1b0c6fa1fb
Added class to read in the csv Annotation file, then write out the respective difference between the performed piece as followed here, and the annotation of RWC by Ewert and Muller
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Thu, 15 Dec 2011 02:28:49 +0000 |
parents | 6cd3e0075adf |
children | 795a99987875 |
line wrap: on
line source
/* * midiEventHolder.cpp * midiCannamReader3 * * Created by Andrew on 19/07/2011. * Copyright 2011 QMUL. All rights reserved. * */ //Main file to look at here is newNoteEvent() - this calls everything else to update the Bayesian array #include "midiEventHolder.h" //#include <iostream> //#include <fstream> midiEventHolder::midiEventHolder(){ myNotation.readInSomeValues(); // recordedNoteOnIndex = 0; alignmentPosition = 0; useTempoPrior = false;//puts sine wave round tempo confidenceWeightingUsed = true; newOptimalMethod = true; matchWindowWidth = 16000;//window size for matching in ms interNoteRange = 1600;//preferred duration //so max here is really four likelihoodWidth = 100;//using 100 is good likelihoodToNoiseRatio = 0.20;//was 0.02 on 18/11/11, changing to give more weight to observations //was 0.08 on 11/12/11 but need more for tempo varn in rwc database bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05 bayesStruct.speedDecayWidth = 40; bayesStruct.speedDecayAmount = 10; //there is option to use MAP estinate or integral in beayesianarraystricture class runningInRealTime = true; bayesStruct.realTimeMode = &runningInRealTime; minimumMatchSpeed = 0.0; maximumMatchSpeed = 2.0; minimumTimeIntervalForTempoUpdate = 150; width = ofGetWidth(); height = ofGetHeight(); screenWidth= &width; screenHeight = &height; ticksPerScreen = 4000; tickLocation = 0; pulsesPerQuarternote = 240; noteArrayIndex = 0; noteMinimum = 30; noteMaximum = 96; speedPriorValue = 1.0; bayesStruct.resetSize(matchWindowWidth); bayesStruct.setPositionDistributionScalar(1); bayesStruct.resetSpeedSize(200); bayesStruct.setRelativeSpeedScalar(0.01); bayesStruct.relativeSpeedPrior.getMaximum(); //bayesStruct.simpleExample(); speedWindowWidthMillis = 1600;//4000 noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); intervalsToCheck.push_back(1); intervalsToCheck.push_back(2); //intervalsToCheck.push_back(3); intervalsToCheck.push_back(4); intervalsToCheck.push_back(6); intervalsToCheck.push_back(8); intervalsToCheck.push_back(16); drawPhaseMode = true; printf("lookup index %f value %f\n", bayesStruct.prior.getLookupIndex(100, 30., 10.0), bayesStruct.prior.gaussianLookupTable[(int)bayesStruct.prior.getLookupIndex(100, 30., 10.0)]); } void midiEventHolder::reset(){ //called when we start playing noteArrayIndex = 0; tickLocation = 0; startPlayingTime = getTimeNow(0);//ofGetElapsedTimeMillis(); bayesStruct.lastEventTime = getTimeNow(0);//ofGetElapsedTimeMillis(); numberOfScreensIn = 0; // recordedNoteOnIndex = 0; bayesStruct.setNewDistributionOffsets(0); bayesStruct.posterior.offset = 0; playedEventTimes.clear(); playedNoteOnMatrix.clear(); matchMatrix.clear(); bestMatchIndex = 0; recordedTotalNoteCounterByPitch.clear(); recordedTotalNoteCounterByPitch.assign(127,0); totalNoteCounterIndex = 0; interNoteIntervals.clear(); smoothIndex = 0; smoothPlayPosition = 0.0; // relativeSpeedForSmooth = 1.0; // storedSmoothPlayPosition = smoothPlayPosition; // lastSmoothUpdateTime = getTimeNow(0); printf("reset speed prior is %f\n", speedPriorValue); bayesStruct.resetSpeedToOne(); bayesStruct.setSpeedPrior(speedPriorValue); setMatchedNotesBackToFalse(); periodCounter = 0; for (int i = 0;i < periodValues.size();i++){ // printf("period at %f is %f\n", periodValues[i][2], periodValues[i][1]); } /* if (periodValues.size() > 0){ updatePeriodValue(0);// periodValues[0][2]; printf("Resetting period to %f , size is %i\n", period, (int)periodValues.size()); } */ //period = 500.0; } void midiEventHolder::setMatchedNotesBackToFalse(){ for (int i = 0;i < noteOnMatches.size();i++) noteOnMatches[i] = false; } void midiEventHolder::clearAllEvents(){ recordedNoteOnMatrix.clear(); matchesFound.clear(); noteOnMatches.clear(); recordedEventTimes.clear(); measureVector.clear(); //played events: playedEventTimes.clear(); playedNoteOnMatrix.clear(); matchMatrix.clear(); bestMatchFound.clear(); periodValues.clear(); beatPositions.clear(); recordedTotalNoteCounterByPitch.clear(); recordedTotalNoteCounterByPitch.assign(127, 0); totalNoteCounterIndex = 0; } void midiEventHolder::printNotes(){ printf("RECORDED MATRIX\n"); for (int i = 0;i < recordedNoteOnMatrix.size();i++){ printf("ticktime %i :: pitch %i @ millis %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]); } } double midiEventHolder::getEventTimeTicks(double millis){ return 0.0; //return (millis * pulsesPerQuarternote / period); } double midiEventHolder::getEventTimeMillis(double ticks){ return (period * ticks / (double) pulsesPerQuarternote); } void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){ // tempoSpeedString = ""; //MOVE INTO BAYESSTRUCT?? XXX //bayesStruct.copyPriorToPosterior(); //why was this here?? bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way //bayesStruct.copyPriorToPosterior(); //need to get new MAP position and set the offset of the arrays //currently bestEstimate is the approx for the new MAP position lastPlayedPitch = pitch; //add the new event to our played information matrix IntVector v; v.push_back(pitch); v.push_back(velocity); playedNoteOnMatrix.push_back(v); //would update the arrays at this point to show where out current location (phase) and tempo is. // double timeNow = ofGetElapsedTimeMillis() - startTime; double timeNow = timePlayed;// - startTime; recentNoteOnTime = timePlayed; // printf("Max time %f OF time %f \n", timePlayed, timeNow); playedEventTimes.push_back(timePlayed); // double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; double timeDifference = timePlayed - bayesStruct.lastEventTime; //printf("note %i played at %f and last event %f time difference %f and current best estmate %f\n", pitch, timePlayed, bayesStruct.lastEventTime, timeDifference, bayesStruct.bestEstimate); //addnoise to the tempo distribution //bayesStruct.decaySpeedDistribution(timeDifference); if (timeDifference > 50){ bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.); // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.); } // bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate; bayesStruct.updateBestEstimate(timeDifference); bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed); //updatePeriodValue(bayesStruct.lastBestEstimateUpdateTime); // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis timeString = "Pitch:"+ofToString(pitch); timeString += ", time now:"+ofToString(timeNow, 1); timeString += " TD "+ofToString(timeDifference, 1); timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0); timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0); // timeString += " Previous time" + ofToString(newMAPestimateTime,0); timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2); timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2); // newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); // timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0); //then we recalculate the window start based on MAP being central //then we do the matches on these and the likelihood on these. bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2))); // bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0); timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1); timeString += " error "+ofToString(minimumMatchError, 0); timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1); timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2); //be able to draw the prior in correct location relative to the midi notes //this calculates the cross update of all possible speeds and all possible positions bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); timeString += " notearrayindex "+ofToString(noteArrayIndex, 0); //when this is off teh screen there is a problem somehow XXX bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2));// bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); //trying to switch to prior bayesStruct.lastEventTime = timePlayed;//bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); //do the cross update to find current posterior for location // totalConfidence= 0; int numberOfMatchesFound = findLocalMatches(pitch); setMatchLikelihoods(numberOfMatchesFound); bayesStruct.calculatePosterior(); if (recordedEventTimes.size() > 0){ updateTempo(); //calcuateNewInterNoteIntervals(); } //storedSmoothPlayPosition = smoothPlayPosition; } void midiEventHolder::updateTempo(){ //having found matches we have matches for new note and matches for previous notes if (newOptimalMethod) findOptimumTempoPairsToCurrentBestMatch(); else if (!confidenceWeightingUsed) findLocalTempoPairs(); else findLocalTempoPairsWeightedForConfidence(); //bayesStruct.addGaussianNoiseToSpeedPosterior(10); } double midiEventHolder::getTimeNow(double eventTime){ double timeNow = eventTime; if (runningInRealTime) timeNow = ofGetElapsedTimeMillis(); return timeNow; } int midiEventHolder::findLocalMatches(int notePitch){ //here we find the matches to the new note within appropriate range matchString = ""; windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis // cout << "best estimate is " << bayesStruct.bestEstimate << endl; int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth); //matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime); return numberOfMatches; } void midiEventHolder::setMatchLikelihoods(int numberOfMatches){ //reset the offset to match the prior bayesStruct.likelihood.offset = bayesStruct.prior.offset; bayesStruct.likelihood.zero();//set to zero double quantity = likelihoodToNoiseRatio / numberOfMatches; for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); //this is the vent time since start of file if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){ // double confidenceMeasure = 0; // if (totalConfidence > 0) // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence; bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure }//end if } bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length); } int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ matchesFound.clear(); int startIndex = 0; if (recordedEventTimes.size() > 0){ //get to the right range of events to check in while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime) startIndex++; } IntVector v; DoubleVector d; double tmpError = 100000.;//v high error double minimumConfidence = 0; while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){ if (recordedNoteOnMatrix[startIndex][1] == notePitch){ matchesFound.push_back(startIndex); v.push_back(startIndex); //so startIndex is registered as a match double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]); if (eventConfidence > minimumConfidence){ minimumConfidence = eventConfidence; bestMatchIndex = startIndex; } d.push_back(eventConfidence); double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX); // recordedEventTimes[startIndex]); // matchString += "["+ofToString(startIndex)+"] = "+ofToString(confidence, 3)+" ."; if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){ //record the error between expected and observed times tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate); minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate; } } startIndex++; } // printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch); int size = matchesFound.size(); if (size > 0) noteOnMatches[bestMatchIndex] = true; v.insert(v.begin() , (int)size);//at beginning, we list how many matches there are that we have found d.insert(d.begin() , (double)size); //v.push_back(size); //d.push_back(size); //for (int i = 0;i < matchesFound.size()+1;i++){ // v.push_back(matchesFound[i]); // printf("match %i,[%i] is %i\n", startIndex, i, v[i]); //} matchMatrix.push_back(v); matchConfidence.push_back(d); //bringing in way to list only the best matches and use these in tempo process bestMatchFound.push_back(bestMatchIndex); // printf("BEST MATCH TO note %i, start time %i, endtime %i, time %i is recorded time %i, confidence %0.2f\n", notePitch, startTime, endTime, (int) recordedEventTimes[bestMatchIndex], minimumConfidence); return size; } bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){ for (int i = 0;i < matchesFound.size();i++){ if (matchesFound[i] == tmpIndex) return true; } return false; } void midiEventHolder::findLocalTempoPairs(){ int currentPlayedIndex = playedNoteOnMatrix.size()-1; // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); // printMatchesFound(); // printMatchMatrix(); // printf("possible notes \n"); bool needToUpdate = false; bayesStruct.setLikelihoodToConstant(); for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){ //iterate through the recently matched events - even dodgy matches included //size, index of match0, index of match1, .... int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1]; int previousIndex = currentPlayedIndex-1; while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; for (int k = 0;k < matchMatrix[previousIndex][0];k++){ int recordedPreviousIndex = matchMatrix[previousIndex][k+1]; double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; //we want the speed of the recording relative to that of the playing live double speedRatio = recordedTimeDifference / playedTimeDifference; if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate && speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ //adding in a prior that prefers 1 double priorWeighting = 1; if (useTempoPrior) priorWeighting = sin(speedRatio * PI/2); /* printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); printf("[%i] :: ", recordedPreviousIndex); printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); printf("update on speed ratio %f\n", speedRatio); */ // matchString += " speed: "+ofToString(speedRatio, 3); // commented for debug //bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match double amount = (1-bayesStruct.speedLikelihoodNoise)/10; amount *= priorWeighting; bayesStruct.updateTempoLikelihood(speedRatio, amount); // tempoSpeedString += ofToString(recordedPreviousIndex) + " "+ ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; needToUpdate = true; } // printf("\n"); } previousIndex--; }//end while previousindex countdown }//end for loop through possible current matches if (needToUpdate) bayesStruct.updateTempoDistribution(); //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){ bool needToUpdate = false; DoubleVector speedIntervalsFound; //adapted this to just use the best match for each note int currentPlayedIndex = playedNoteOnMatrix.size()-1; // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); // printMatchesFound(); // printMatchMatrix(); // printf("possible notes \n"); bayesStruct.setLikelihoodToConstant(); int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; //we only look at intervals between the current best match and other recent best matched notes //that is the difference in confidence method //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]); int previousIndex = currentPlayedIndex-1; //withing speedwindow i.e. 4 seconds while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; int recordedPreviousIndex = bestMatchFound[previousIndex]; double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; //we want the speed of the recording relative to that of the playing live double speedRatio = recordedTimeDifference / playedTimeDifference; if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){ /* printf("(%i)", previousIndex); printf("[%i] :: ", recordedPreviousIndex); // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); printf("update on speed ratio %f\n", speedRatio); */ // matchString += " speed: "+ofToString(speedRatio, 3); // commented for debug double priorWeighting = 1; if (useTempoPrior) priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed // double weighting = previousMatchConfidence * currentMatchConfidence ; double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9 speedIntervalsFound.push_back(speedRatio); // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex); // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; needToUpdate = true; } // printf("\n"); previousIndex--; }//end while previousindex countdown if (speedIntervalsFound.size() > 0){ double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size(); for (int i = 0;i < speedIntervalsFound.size();i++) bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount); } if (needToUpdate) bayesStruct.updateTempoDistribution(); //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } double midiEventHolder::getBestSpeedEstimate(const int& currentPlayedIndex, const int& equivalentRecordedIndex){ double estimate = 1.0; if (bestMatchIndex > 0){ double accordingToFileLengthEstimate = recordedEventTimes[equivalentRecordedIndex] - recordedEventTimes[0]; double playedEquivalent = (playedEventTimes[currentPlayedIndex] - playedEventTimes[0]); if (accordingToFileLengthEstimate > 0 && playedEquivalent > 0) accordingToFileLengthEstimate /= playedEquivalent; estimate = accordingToFileLengthEstimate; } return estimate; } void midiEventHolder::findOptimumTempoPairsToCurrentBestMatch(){ bool needToUpdate = false; DoubleVector speedIntervalsFound; double currentSpeedEstimate = bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate); int currentPlayedIndex = playedNoteOnMatrix.size()-1; bayesStruct.setLikelihoodToConstant(); int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; //we only look at intervals between the current best match and other recent best matched notes //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]); int previousIndex = currentPlayedIndex-1; //withing speedwindow i.e. 4 seconds while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; int recordedPreviousIndex = bestMatchFound[previousIndex]; double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; //we want the speed of the recording relative to that of the playing live double speedRatio = recordedTimeDifference / playedTimeDifference; //now check if this can be closer the observed value int checkRecordedCurrentIndex = recordedCurrentIndex; int checkRecordedPreviousIndex ;//= recordedCurrentIndex; int currentPlayedPitch = playedNoteOnMatrix[currentPlayedIndex][1]; int previousPlayedPitch = playedNoteOnMatrix[previousIndex][1]; double recordedTimeOfBestMatch = recordedEventTimes[recordedCurrentIndex]; //change this so we start first in window and go to end while (checkRecordedCurrentIndex >= 0 && recordedEventTimes[checkRecordedCurrentIndex] > recordedTimeOfBestMatch - matchWindowWidth){ checkRecordedCurrentIndex--; } double bestSpeedEstimate = getBestSpeedEstimate(currentPlayedIndex, bestMatchIndex); while (checkRecordedCurrentIndex < recordedEventTimes.size() && recordedEventTimes[checkRecordedCurrentIndex] < recordedTimeOfBestMatch + matchWindowWidth ){ if (recordedNoteOnMatrix[checkRecordedCurrentIndex][1] == currentPlayedPitch ){ checkRecordedPreviousIndex = checkRecordedCurrentIndex; double recordedTimeCurrent = recordedEventTimes[checkRecordedCurrentIndex] ; while (checkRecordedPreviousIndex >= 0 && recordedEventTimes[checkRecordedPreviousIndex] + maximumMatchSpeed*playedTimeDifference > recordedTimeCurrent ) { if (recordedNoteOnMatrix[checkRecordedPreviousIndex][1] == previousPlayedPitch){ //we have a candidate double speedToTest = recordedEventTimes[checkRecordedCurrentIndex] - recordedEventTimes[checkRecordedPreviousIndex]; speedToTest /= playedTimeDifference; if (abs(speedToTest-currentSpeedEstimate) < abs(speedRatio - currentSpeedEstimate) ){ speedRatio = speedToTest; } } checkRecordedPreviousIndex--; } } checkRecordedCurrentIndex++; } if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){ /* printf("(%i)", previousIndex); printf("[%i] :: ", recordedPreviousIndex); // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); printf("update on speed ratio %f\n", speedRatio); */ // matchString += " speed: "+ofToString(speedRatio, 3); // commented for debug double priorWeighting = 1; if (useTempoPrior) priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed // double weighting = previousMatchConfidence * currentMatchConfidence ; double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9 speedIntervalsFound.push_back(speedRatio); // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex); // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; needToUpdate = true; } // printf("\n"); previousIndex--; }//end while previousindex countdown if (speedIntervalsFound.size() > 0){ double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size(); for (int i = 0;i < speedIntervalsFound.size();i++) bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount); } if (needToUpdate) bayesStruct.updateTempoDistribution(); //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } void midiEventHolder::calcuateNewInterNoteIntervals(){ DoubleVector v; int currentPlayedIndex = playedNoteOnMatrix.size()-1; // int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; int previousIndex = currentPlayedIndex-1; //withing speedwindow i.e. 4 seconds while (previousIndex >= 0 && playedEventTimes[previousIndex] + interNoteRange > playedEventTimes[currentPlayedIndex]) { double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; checkForCorrectInterval(playedTimeDifference, &v); previousIndex--; } if (v.size() > 0) interNoteIntervals.push_back(v); //printf("\n"); } void midiEventHolder::checkForCorrectInterval(const double& playedTimeDifference, DoubleVector* v){ double intervalDuration = 0.0; for (int intervalIndex = 0;intervalIndex < 3;intervalIndex++){ //on;y check 1,2 and 4 double possibleDuration = playedTimeDifference / intervalsToCheck[intervalIndex]; if (possibleDuration >= 200 && possibleDuration < 400){ v->push_back(possibleDuration); // printf("int %f / %i :: %f ", playedTimeDifference, intervalsToCheck[intervalIndex], possibleDuration); } } } void midiEventHolder::updatePlayPosition(){ //timeDifference = ofGetElapsedTimeMillis() - startPlayingTime;//elpased //in actual fact if we are changing the speed of the play position //we will need to update this via the file //actually time since beginning of file i think double timeDifference = 0; if (runningInRealTime){ bayesStruct.updateBestEstimate(timeDifference); // bayesStruct.updateTmpBestEstimate(timeDifference); } if (smoothPlayPosition < bayesStruct.bestEstimate){ updateSmoothPositionTo(bayesStruct.bestEstimate); //smoothPlayPosition = bayesStruct.bestEstimate; } // playPositionInMillis = timeDifference;//based on updating from when we change period //this to be added //this is time diff in milliseconds //then we have double quarterNoteIntervals = (timeDifference / period); tickLocation = quarterNoteIntervals * pulsesPerQuarternote; updateNoteCounter(); } void midiEventHolder::updateSmoothPositionTo(const double& newPosition){ while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){ smoothIndex--; } while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){ smoothIndex++; } double playingTime = ofGetElapsedTimeMillis(); playingTime -= startPlayingTime; //now at the last one while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){ float annotationTime = 0; int annotationNote = 0; if (smoothIndex < myNotation.rwcAnnotations.size()){ annotationTime = myNotation.rwcAnnotations[smoothIndex].eventTime; annotationNote = myNotation.rwcAnnotations[smoothIndex].midiNote; } if ((*fileOutput).is_open()){ (*fileOutput) << fixed << beatPositions[smoothIndex] <<",\t" << recordedNoteOnMatrix[smoothIndex][1] << ",\t"; (*fileOutput) << playingTime ; float difference = playingTime - (annotationTime*1000.0); if ( recordedNoteOnMatrix[smoothIndex][1] == annotationNote){ (*fileOutput) << " corresponds to " << annotationTime; } (*fileOutput) << " \n"; printf("midi %i beat pos %f now at %f :: annotaion %i time %f diff \t%f ms\n", recordedNoteOnMatrix[smoothIndex][1], beatPositions[smoothIndex], playingTime, annotationNote, annotationTime, difference); } smoothIndex++; } smoothPlayPosition = newPosition; } void midiEventHolder::updatePeriodValue(const double& millis){ double tmp = period; /* while (periodCounter >= 0 && periodCounter < periodValues.size()-1 && periodValues[periodCounter][2] < millis){ periodCounter++; } while (periodCounter > 0 && periodValues[periodCounter][2] > millis){ periodCounter--; } */ //period = periodValues[periodCounter][1]; if (period != tmp){ printf("new period at %f of %f\n", millis, period); } } void midiEventHolder::updateNoteCounter(){ while (totalNoteCounterIndex < bestMatchIndex){ int tmpPitch = recordedNoteOnMatrix[totalNoteCounterIndex][1]; recordedTotalNoteCounterByPitch[tmpPitch] += 1; totalNoteCounterIndex++; } } void midiEventHolder::drawMidiFile(){ //draws midi file on scrolling screen int size = recordedNoteOnMatrix.size(); if (size > 0){ numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen); while (noteArrayIndex < recordedNoteOnMatrix.size()-1 && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] ) noteArrayIndex++; while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0]) noteArrayIndex--; //need to start where we currently are in file int maxNoteIndexToPrint = noteArrayIndex; int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) maxNoteIndexToPrint++; while (minNoteIndexToPrint > 0 && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size minNoteIndexToPrint--; for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){ ofSetColor(255,255,255); if (checkIfMatchedNote(tmpIndex)) ofSetColor(100,100,100);//0,0,255); else if(noteOnMatches[tmpIndex]){ ofSetColor(255,0,255);//dark grey } else{ ofSetColor(255,255,255);//255,255,255); } //ofSetColor(255,255,255); if (tmpIndex == bestMatchIndex) ofSetColor(255,0,0);//best recent match is in red // XXX replace ofgetwidth below //if (tmpIndex >= 0 && tmpIndex < size) int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen; int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); ofRect(xLocation,yLocation, duration, noteHeight); } int xLocation;// = getLocationFromTicks(tickLocation); // ofLine(xLocation, 0, xLocation, (*screenHeight)); //orange line at best estimate xLocation = getLocationFromMillis(bayesStruct.bestEstimate); ofSetColor(250,250,20);//250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate ofSetColor(0,250,0);//250,150, 250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); //lines where matching window start and end are ofSetColor(0);//0,100,255); xLocation = getLocationFromMillis(windowStartTime); ofLine(xLocation, 0, xLocation, (*screenHeight)); xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth); ofLine(xLocation, 0, xLocation, (*screenHeight)); int maxSize = recordedNoteOnMatrix[size-1][0]; int tmpIndex = 0; while (tmpIndex < measureVector.size() && measureVector[tmpIndex] < (numberOfScreensIn+1)*ticksPerScreen){ int measureLocation = measureVector[tmpIndex]; int xLocation = (float)(measureLocation - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; ofSetColor(155,155,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); tmpIndex++; } // ofDrawBitmapString(tempoSpeedString, 20, 20); /* string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint); indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize); ofDrawBitmapString(indexString, 20, 40); */ } //ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20); //ofDrawBitmapString(timeString, 20, 60); //last played piutch ofSetColor(0,200,0,50); int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); ofRect(0,yLocation, 100, noteHeight); } void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){ //using this to draw the live input //draws midi file on scrolling screen int size = midiFileToDraw.size(); if (size > 0){ numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen); while (noteArrayIndex < midiFileToDraw.size()-1 && tickLocation > midiFileToDraw[noteArrayIndex][0] ) noteArrayIndex++; while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < midiFileToDraw[noteArrayIndex][0]) noteArrayIndex--; //need to start where we currently are in file int maxNoteIndexToPrint = noteArrayIndex; int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above while (maxNoteIndexToPrint < midiFileToDraw.size() && midiFileToDraw[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) maxNoteIndexToPrint++; while (minNoteIndexToPrint > 0 && midiFileToDraw[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size minNoteIndexToPrint--; for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)midiFileToDraw.size());tmpIndex++){ ofSetColor(0,0,255, 200); int xLocation = (float)(midiFileToDraw[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; int duration = (float)(midiFileToDraw[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen; int yLocation = (*screenHeight) - ((midiFileToDraw[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); ofRect(xLocation,yLocation, duration, noteHeight); } } } void midiEventHolder::drawFile(){ drawMidiFile(); ofSetColor(0,0,255); ofDrawBitmapString("period"+ofToString(period, 2), ofGetWidth() - 180, 20); // bayesStruct.drawArrays(); // ofSetColor(200,200,0); // bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800); //need to draw arrays within correct timescope if (drawPhaseMode) bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen)); if (drawTempoMode) bayesStruct.drawTempoArrays(); ofSetColor(0, 0, 0); //ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); double confidence = bayesStruct.posterior.getValueAtMillis(mouseX); /* string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter); ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3); ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60); */ //drawInterNoteIntervals(); } void midiEventHolder::drawInterNoteIntervals(){ ofSetColor(0,0,150); int size = interNoteIntervals.size(); int numberToShow = min(100, size); double x ; for (int y = 1;y < numberToShow;y++){ for (int point = 0;point < interNoteIntervals[y].size();point++){ double interval = interNoteIntervals[size - y][point]; x = interval - 200; x *= (*screenWidth) / 200.0; } double h = (double)(y * (*screenHeight)) / numberToShow; ofCircle(x, h, 5); } } void midiEventHolder::printInterNoteIntervals(){ int size = interNoteIntervals.size(); int numberToShow = 20; double x ; for (int y = max(0, size - numberToShow);y < interNoteIntervals.size();y++){ for (int point = 0;point < interNoteIntervals[y].size();point++){ printf("[%i][%i] : %f", y, point, interNoteIntervals[y][point]); } printf("\n"); } } int midiEventHolder::getLocationFromTicks(double tickPosition){ return 0; // return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); //not used } int midiEventHolder::getLocationFromMillis(double millisPosition){ //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen); } void midiEventHolder::exampleCrossUpdate(){ bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200); } void midiEventHolder::setStartPlayingTimes(){ startPlayingTime = getTimeNow(0);//ofGetElapsedTimeMillis(); //startTime = startPlayingTime; /* bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis(); bayesStruct.bestEstimate = 0; bayesStruct.resetArrays(); bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); */ bayesStruct.setStartPlaying(); matchString = ""; } void midiEventHolder::printMatchMatrix(){ printf("match matrix:\n"); for (int i = 0;i < matchMatrix.size();i++){ for (int k = 0;k < matchMatrix[i].size();k++){ printf("%i , ", matchMatrix[i][k]); } printf("\n"); } } void midiEventHolder::printRecordedEvents(){ printf("Recorded Events:\n"); for (int i = 0;i < recordedNoteOnMatrix.size();i++){ for (int k = 0;k < recordedNoteOnMatrix[i].size();k++){ printf("[%i] = %i ,", i, recordedNoteOnMatrix[i][k]); } if (i < recordedEventTimes.size()) printf("time %f \n", recordedEventTimes[i]); else printf("\n"); } } void midiEventHolder::reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix){ double currentTime = -19999.; for (int i = 0;i < noteOnMatrix.size();i++){ int nextIndex = getIndexOfMinimumAboveTime(currentTime, noteOnMatrix); // cout << "index of min time " << currentTime << " is " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << endl; if (nextIndex >= 0 && nextIndex > i && noteOnMatrix[nextIndex][0] < noteOnMatrix[i][0] ){ //which it should be // cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time " << noteOnMatrix[i][0] << endl; noteOnMatrix[i].swap(noteOnMatrix[nextIndex]); // double tmp = beatPositions[i]; // beatPositions[i] = beatPositions[nextIndex]; // = tmp; swap (beatPositions[i], beatPositions[nextIndex]); currentTime = noteOnMatrix[i][0]; } } //printRecordedEvents(); } void midiEventHolder::doublecheckOrder(IntMatrix& noteOnMatrix){ for (int i = 0;i < noteOnMatrix.size();i++){ int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix); if (nextIndex > i){ noteOnMatrix[i].swap(noteOnMatrix[nextIndex]); swap (beatPositions[i], beatPositions[nextIndex]); } } } int midiEventHolder::getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix){ int returnIndex = index; int min = noteOnMatrix[index][0]; for (int i = index;i < noteOnMatrix.size();i++){ if (noteOnMatrix[i][0] < min){ returnIndex = i; min = noteOnMatrix[i][0]; } } return returnIndex; } int midiEventHolder::getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix){ int index = 0; double minimumTime = 100000000.; int bestIndex = -1; while (index < noteOnMatrix.size()){ if (noteOnMatrix[index][0] > time && noteOnMatrix[index][0] < minimumTime){ bestIndex = index; minimumTime = noteOnMatrix[index][0]; } index++; } return bestIndex; } void midiEventHolder::correctTiming(IntMatrix& noteOnMatrix){ if (noteOnMatrix.size() > 0 && noteOnMatrix[0][0] < 0) { int offset = noteOnMatrix[0][0]; for (int i = 0;i < noteOnMatrix.size();i++){ noteOnMatrix[i][0] -= offset; } } } void midiEventHolder::printNoteCounter(){ for (int i = 0;i < recordedTotalNoteCounterByPitch.size();i++){ printf("RECORDED TOTAL[%i] := %i", i, recordedTotalNoteCounterByPitch[i]); } } /* double timeDiff = 0;//timeDifference; if (runningInRealTime) timeDiff = ofGetElapsedTimeMillis() - lastSmoothUpdateTime; // bayesStruct.lastBestEstimateUpdateTime; //smoothPlayPosition = bayesStruct.bestEstimate + 100; //relativeSpeedForSmooth = 0.1; //bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate); // speedEstimate*2; smoothPlayPosition = storedSmoothPlayPosition + timeDiff * relativeSpeedForSmooth;// * bayesStruct.speedEstimate; storedSmoothPlayPosition = smoothPlayPosition; lastSmoothUpdateTime = getTimeNow(bayesStruct.lastBestEstimateUpdateTime); updateSmoothPlaySpeed(); //bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate) } void midiEventHolder::updateSmoothPlaySpeed(){ //project where current play pos will be in two seconds and aim for it. double timeToAimForMillis = 2000.0; //double timeDiff = ofGetElapsedTimeMillis() - bayesStruct.lastBestEstimateUpdateTime;//since the update need to get to where we are double projection = bayesStruct.bestEstimate + bayesStruct.speedEstimate*timeToAimForMillis;// double timeDifferenceFromSmooth = projection - smoothPlayPosition; relativeSpeedForSmooth = timeDifferenceFromSmooth / timeToAimForMillis; } */ /* void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){ bool needToUpdate = false; //adapted this to just use the best match for each note int currentPlayedIndex = playedNoteOnMatrix.size()-1; // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); // printMatchesFound(); // printMatchMatrix(); // printf("possible notes \n"); bayesStruct.setLikelihoodToConstant(); for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){ //iterate through the recently matched events - even dodgy matches included //size, index of match0, index of match1, .... int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1]; double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence int previousIndex = currentPlayedIndex-1; while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; // for (int k = 0;k < matchMatrix[previousIndex][0];k++) int recordedPreviousIndex = bestMatchFound[previousIndex];//matchMatrix[previousIndex][k+1]; //double previousMatchConfidence = matchConfidence[previousIndex][k+1]; double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; //we want the speed of the recording relative to that of the playing live double speedRatio = recordedTimeDifference / playedTimeDifference; if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); printf("[%i] :: ", recordedPreviousIndex); // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); printf("update on speed ratio %f\n", speedRatio); // matchString += " speed: "+ofToString(speedRatio, 3); // commented for debug double priorWeighting = 1; if (useTempoPrior) priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed // double weighting = previousMatchConfidence * currentMatchConfidence ; double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/10; bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match tempoSpeedString += ofToString(recordedPreviousIndex) + " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; needToUpdate = true; } // printf("\n"); previousIndex--; }//end while previousindex countdown }//end for loop through possible current matches if (needToUpdate) bayesStruct.updateTempoDistribution(); //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } */