andrew@33: /* andrew@33: * midiEventHolder.cpp andrew@33: * midiCannamReader3 andrew@33: * andrew@33: * Created by Andrew on 19/07/2011. andrew@33: * Copyright 2011 QMUL. All rights reserved. andrew@33: * andrew@33: */ andrew@33: andrew@33: andrew@33: //Main file to look at here is newNoteEvent() - this calls everything else to update the Bayesian array andrew@33: andrew@46: //Relative speed is RECORDED / PLAYED andrew@46: //so for timedifference t andrew@46: //this is t/scalar in terms of position units of played time andrew@46: //and by relative speed r, r*t/scalar andrew@46: andrew@46: andrew@33: #include "midiEventHolder.h" andrew@36: andrew@37: #include andrew@37: #include andrew@42: #include andrew@33: andrew@52: #pragma mark -initialise andrew@52: andrew@52: int matchedColor = 0xAAAAAA; andrew@52: int bestMatchedColor = 0xFF0000; andrew@52: andrew@33: midiEventHolder::midiEventHolder(){ andrew@36: andrew@49: timeProjectionToMeet = 600;//ms in future they will intersect bet predicted and causal play position andrew@49: andrew@47: double scalarForPositionVectors = 10; andrew@36: andrew@33: // recordedNoteOnIndex = 0; andrew@34: alignmentPosition = 0; andrew@33: andrew@33: useTempoPrior = false;//puts sine wave round tempo andrew@33: confidenceWeightingUsed = true; andrew@33: newOptimalMethod = true; andrew@52: printInfo = false; andrew@33: andrew@50: matchWindowWidth = 20000;//window size for matching in ms andrew@33: interNoteRange = 1600;//preferred duration andrew@33: //so max here is really four andrew@33: andrew@33: likelihoodWidth = 100;//using 100 is good andrew@52: likelihoodToNoiseRatio = 0.80;//was 0.02 on 18/11/11, changing to give more weight to observations andrew@33: //was 0.08 on 11/12/11 but need more for tempo varn in rwc database andrew@52: //0.2 on main tests of andrew@33: andrew@50: bayesStruct.speedLikelihoodNoise = 0.2;//changed from 0.1, was 0.05 andrew@33: bayesStruct.speedDecayWidth = 40; andrew@33: bayesStruct.speedDecayAmount = 10; andrew@33: andrew@40: drawTempoMode = false; andrew@33: //there is option to use MAP estinate or integral in beayesianarraystricture class andrew@33: andrew@33: runningInRealTime = true; andrew@33: bayesStruct.realTimeMode = &runningInRealTime; andrew@33: andrew@33: minimumMatchSpeed = 0.0; andrew@33: maximumMatchSpeed = 2.0; andrew@33: minimumTimeIntervalForTempoUpdate = 150; andrew@33: andrew@33: width = ofGetWidth(); andrew@33: height = ofGetHeight(); andrew@33: screenWidth= &width; andrew@33: screenHeight = &height; andrew@33: andrew@33: ticksPerScreen = 4000; andrew@33: tickLocation = 0; andrew@33: pulsesPerQuarternote = 240; andrew@33: noteArrayIndex = 0; andrew@33: noteMinimum = 30; andrew@33: noteMaximum = 96; andrew@33: andrew@33: speedPriorValue = 1.0; andrew@33: andrew@46: int tmpArraySize = (int)(matchWindowWidth/scalarForPositionVectors); andrew@46: bayesStruct.resetSize(tmpArraySize); andrew@46: bayesStruct.setPositionDistributionScalar(scalarForPositionVectors); andrew@46: printf("ARRAY SIZE IS %i\n", tmpArraySize); andrew@33: andrew@33: bayesStruct.resetSpeedSize(200); andrew@33: bayesStruct.setRelativeSpeedScalar(0.01); andrew@33: bayesStruct.relativeSpeedPrior.getMaximum(); andrew@33: //bayesStruct.simpleExample(); andrew@33: andrew@33: speedWindowWidthMillis = 1600;//4000 andrew@34: andrew@33: noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); andrew@33: andrew@33: intervalsToCheck.push_back(1); andrew@33: intervalsToCheck.push_back(2); andrew@33: //intervalsToCheck.push_back(3); andrew@33: intervalsToCheck.push_back(4); andrew@33: intervalsToCheck.push_back(6); andrew@33: intervalsToCheck.push_back(8); andrew@33: intervalsToCheck.push_back(16); andrew@33: andrew@33: drawPhaseMode = true; andrew@52: saveImage = false; andrew@33: andrew@33: 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)]); andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::reset(){ andrew@33: //called when we start playing andrew@33: andrew@33: noteArrayIndex = 0; andrew@33: tickLocation = 0; andrew@34: startPlayingTime = getTimeNow(0);//ofGetElapsedTimeMillis(); andrew@33: bayesStruct.lastEventTime = getTimeNow(0);//ofGetElapsedTimeMillis(); andrew@33: numberOfScreensIn = 0; andrew@33: // recordedNoteOnIndex = 0; andrew@33: bayesStruct.setNewDistributionOffsets(0); andrew@33: bayesStruct.posterior.offset = 0; andrew@33: andrew@33: playedEventTimes.clear(); andrew@33: playedNoteOnMatrix.clear(); andrew@33: matchMatrix.clear(); andrew@33: bestMatchIndex = 0; andrew@33: andrew@33: recordedTotalNoteCounterByPitch.clear(); andrew@33: recordedTotalNoteCounterByPitch.assign(127,0); andrew@33: totalNoteCounterIndex = 0; andrew@34: andrew@33: interNoteIntervals.clear(); andrew@33: andrew@50: outputIndex = 0; andrew@34: smoothPlayPosition = 0.0; andrew@48: causalPlayPosition = 0; andrew@48: lastCausalUpdateTime = getTimeNow(0); andrew@48: andrew@34: // relativeSpeedForSmooth = 1.0; andrew@34: // storedSmoothPlayPosition = smoothPlayPosition; andrew@34: // lastSmoothUpdateTime = getTimeNow(0); andrew@34: andrew@34: printf("reset speed prior is %f\n", speedPriorValue); andrew@46: // bayesStruct.resetSpeedToOne(); andrew@33: bayesStruct.setSpeedPrior(speedPriorValue); andrew@33: setMatchedNotesBackToFalse(); andrew@34: andrew@46: // periodCounter = 0; andrew@46: // for (int i = 0;i < periodValues.size();i++){ andrew@34: // printf("period at %f is %f\n", periodValues[i][2], periodValues[i][1]); andrew@46: // } andrew@34: /* if (periodValues.size() > 0){ andrew@34: updatePeriodValue(0);// periodValues[0][2]; andrew@34: printf("Resetting period to %f , size is %i\n", period, (int)periodValues.size()); andrew@34: } andrew@34: */ andrew@34: //period = 500.0; andrew@33: } andrew@33: andrew@52: void midiEventHolder::clearAllEvents(){ andrew@52: recordedNoteOnMatrix.clear(); andrew@52: matchesFound.clear(); andrew@52: noteOnMatches.clear(); andrew@52: recordedEventTimes.clear(); andrew@52: measureVector.clear(); andrew@52: //played events: andrew@52: playedEventTimes.clear(); andrew@52: playedNoteOnMatrix.clear(); andrew@52: matchMatrix.clear(); andrew@52: bestMatchFound.clear(); andrew@52: periodValues.clear(); andrew@52: andrew@52: beatPositions.clear(); andrew@52: andrew@52: recordedTotalNoteCounterByPitch.clear(); andrew@52: recordedTotalNoteCounterByPitch.assign(127, 0); andrew@52: totalNoteCounterIndex = 0; andrew@52: } andrew@52: andrew@50: void midiEventHolder::testSpeedPriorSetting(){ andrew@50: if (speedPriorValue > 2){ andrew@50: bayesStruct.resetSpeedSize(speedPriorValue * 200); andrew@50: bayesStruct.setRelativeSpeedScalar(0.01); andrew@50: bayesStruct.relativeSpeedPrior.getMaximum(); andrew@50: printf("SPEED SIZE EXCEEDS MAXIMUM!!! RESETTING TO SIXE %i\n", (int)(speedPriorValue * 200)); andrew@50: } andrew@50: else{ andrew@50: bayesStruct.resetSpeedSize(200); andrew@50: bayesStruct.setRelativeSpeedScalar(0.01); andrew@50: bayesStruct.relativeSpeedPrior.getMaximum(); andrew@50: } andrew@50: andrew@50: } andrew@50: andrew@33: void midiEventHolder::setMatchedNotesBackToFalse(){ andrew@33: for (int i = 0;i < noteOnMatches.size();i++) andrew@33: noteOnMatches[i] = false; andrew@33: } andrew@33: andrew@52: andrew@33: andrew@33: void midiEventHolder::printNotes(){ andrew@33: printf("RECORDED MATRIX\n"); andrew@33: for (int i = 0;i < recordedNoteOnMatrix.size();i++){ andrew@33: printf("ticktime %i :: pitch %i @ millis %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]); andrew@33: } andrew@33: } andrew@33: andrew@33: andrew@52: #pragma mark -New Observed Event andrew@33: andrew@33: andrew@33: void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){ andrew@33: // tempoSpeedString = ""; andrew@46: andrew@33: //MOVE INTO BAYESSTRUCT?? XXX andrew@33: //bayesStruct.copyPriorToPosterior(); andrew@33: //why was this here?? andrew@33: bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way andrew@33: //bayesStruct.copyPriorToPosterior(); andrew@33: //need to get new MAP position and set the offset of the arrays andrew@33: //currently bestEstimate is the approx for the new MAP position andrew@33: andrew@33: lastPlayedPitch = pitch; andrew@33: //add the new event to our played information matrix andrew@33: IntVector v; andrew@33: v.push_back(pitch); andrew@33: v.push_back(velocity); andrew@33: playedNoteOnMatrix.push_back(v); andrew@33: andrew@33: andrew@33: //would update the arrays at this point to show where out current location (phase) and tempo is. andrew@33: // double timeNow = ofGetElapsedTimeMillis() - startTime; andrew@33: double timeNow = timePlayed;// - startTime; andrew@33: recentNoteOnTime = timePlayed; andrew@33: andrew@33: // printf("Max time %f OF time %f \n", timePlayed, timeNow); andrew@33: andrew@33: playedEventTimes.push_back(timePlayed); andrew@33: andrew@33: // double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; andrew@33: double timeDifference = timePlayed - bayesStruct.lastEventTime; andrew@33: andrew@33: //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); andrew@33: andrew@33: //addnoise to the tempo distribution andrew@33: //bayesStruct.decaySpeedDistribution(timeDifference); andrew@33: andrew@33: if (timeDifference > 50){ andrew@33: bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.); andrew@33: // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.); andrew@33: } andrew@33: andrew@34: // bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate; andrew@33: bayesStruct.updateBestEstimate(timeDifference); andrew@34: andrew@33: bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed); andrew@34: //updatePeriodValue(bayesStruct.lastBestEstimateUpdateTime); andrew@34: andrew@33: // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); andrew@33: //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis andrew@33: andrew@33: timeString = "Pitch:"+ofToString(pitch); andrew@33: timeString += ", time now:"+ofToString(timeNow, 1); andrew@33: timeString += " TD "+ofToString(timeDifference, 1); andrew@33: timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0); andrew@33: timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0); andrew@33: // timeString += " Previous time" + ofToString(newMAPestimateTime,0); andrew@33: timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 2); andrew@33: timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2); andrew@33: andrew@33: // newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); andrew@33: // timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0); andrew@33: andrew@33: //then we recalculate the window start based on MAP being central andrew@33: //then we do the matches on these and the likelihood on these. andrew@33: andrew@46: bayesStruct.setNewDistributionOffsets(max(bayesStruct.posterior.offset, bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2))); andrew@46: //bayesStruct.setNewDistributionOffsets(max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); andrew@33: andrew@33: timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0); andrew@33: timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1); andrew@33: timeString += " error "+ofToString(minimumMatchError, 0); andrew@33: timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.integratedEstimate, 1); andrew@33: timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.integratedEstimate), 2); andrew@33: andrew@33: andrew@33: //be able to draw the prior in correct location relative to the midi notes andrew@33: //this calculates the cross update of all possible speeds and all possible positions andrew@33: bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); andrew@33: andrew@33: andrew@33: timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); andrew@33: timeString += " notearrayindex "+ofToString(noteArrayIndex, 0); andrew@33: //when this is off teh screen there is a problem somehow XXX andrew@33: andrew@46: bayesStruct.posterior.offset = bayesStruct.prior.offset; andrew@46: //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)); andrew@33: andrew@33: //trying to switch to prior andrew@33: andrew@33: andrew@33: bayesStruct.lastEventTime = timePlayed;//bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); andrew@33: andrew@33: //do the cross update to find current posterior for location andrew@33: // totalConfidence= 0; andrew@33: int numberOfMatchesFound = findLocalMatches(pitch); andrew@33: setMatchLikelihoods(numberOfMatchesFound); andrew@33: bayesStruct.calculatePosterior(); andrew@33: andrew@33: if (recordedEventTimes.size() > 0){ andrew@33: updateTempo(); andrew@33: //calcuateNewInterNoteIntervals(); andrew@33: } andrew@34: andrew@46: andrew@34: //storedSmoothPlayPosition = smoothPlayPosition; andrew@33: andrew@33: } andrew@33: andrew@52: double midiEventHolder::getEventTimeTicks(double millis){ andrew@52: return 0.0; andrew@52: //return (millis * pulsesPerQuarternote / period); andrew@52: } andrew@52: andrew@52: double midiEventHolder::getEventTimeMillis(double ticks){ andrew@52: return (period * ticks / (double) pulsesPerQuarternote); andrew@52: } andrew@52: andrew@52: andrew@52: andrew@52: double midiEventHolder::getTimeNow(double eventTime){ andrew@52: double timeNow = eventTime; andrew@52: if (runningInRealTime) andrew@52: timeNow = ofGetElapsedTimeMillis(); andrew@52: return timeNow; andrew@52: } andrew@52: andrew@52: #pragma mark -Tempo Update andrew@52: andrew@33: void midiEventHolder::updateTempo(){ andrew@33: //having found matches we have matches for new note and matches for previous notes andrew@50: if (newOptimalMethod)//now true andrew@33: findOptimumTempoPairsToCurrentBestMatch(); andrew@33: else if (!confidenceWeightingUsed) andrew@33: findLocalTempoPairs(); andrew@33: else andrew@33: findLocalTempoPairsWeightedForConfidence(); andrew@33: andrew@33: //bayesStruct.addGaussianNoiseToSpeedPosterior(10); andrew@33: } andrew@33: andrew@33: int midiEventHolder::findLocalMatches(int notePitch){ andrew@33: andrew@33: //here we find the matches to the new note within appropriate range andrew@33: andrew@33: matchString = ""; andrew@33: andrew@33: windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis andrew@33: // cout << "best estimate is " << bayesStruct.bestEstimate << endl; andrew@33: int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth); andrew@33: andrew@33: andrew@33: //matchString += " pitch: "+ofToString(notePitch)+" matches "+ofToString(numberOfMatches)+" win start "+ofToString(windowStartTime); andrew@33: andrew@33: return numberOfMatches; andrew@33: andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: void midiEventHolder::setMatchLikelihoods(int numberOfMatches){ andrew@33: //reset the offset to match the prior andrew@33: bayesStruct.likelihood.offset = bayesStruct.prior.offset; andrew@33: bayesStruct.likelihood.zero();//set to zero andrew@33: andrew@33: double quantity = likelihoodToNoiseRatio / numberOfMatches; andrew@33: andrew@33: for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ andrew@33: // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); andrew@33: //this is the vent time since start of file andrew@46: if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize*bayesStruct.likelihood.scalar){ andrew@33: // double confidenceMeasure = 0; andrew@33: // if (totalConfidence > 0) andrew@33: // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence; andrew@44: andrew@44: //bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure andrew@44: bayesStruct.likelihood.addGaussianShapeFromRealTime(recordedEventTimes[matchesFound[i]], likelihoodWidth, quantity);//* confidenceMeasure andrew@33: }//end if andrew@33: } andrew@33: bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length); andrew@33: } andrew@33: andrew@33: int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ andrew@33: andrew@33: matchesFound.clear(); andrew@33: int startIndex = 0; andrew@33: andrew@33: if (recordedEventTimes.size() > 0){ andrew@33: andrew@33: //get to the right range of events to check in andrew@50: //OPTIMIZE! andrew@33: while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime) andrew@33: startIndex++; andrew@33: andrew@33: } andrew@33: andrew@33: IntVector v; andrew@33: DoubleVector d; andrew@33: double tmpError = 100000.;//v high error andrew@33: andrew@33: double minimumConfidence = 0; andrew@33: while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){ andrew@33: if (recordedNoteOnMatrix[startIndex][1] == notePitch){ andrew@33: andrew@33: matchesFound.push_back(startIndex); andrew@33: v.push_back(startIndex); andrew@33: //so startIndex is registered as a match andrew@33: andrew@33: double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]); andrew@33: if (eventConfidence > minimumConfidence){ andrew@33: minimumConfidence = eventConfidence; andrew@50: bestMatchIndex = startIndex;//could change this to minimumMatchError below andrew@33: } andrew@33: d.push_back(eventConfidence); andrew@33: andrew@33: double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX); andrew@33: // recordedEventTimes[startIndex]); andrew@33: // matchString += "["+ofToString(startIndex)+"] = "+ofToString(confidence, 3)+" ."; andrew@33: andrew@33: if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){ andrew@33: //record the error between expected and observed times andrew@33: tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate); andrew@33: minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate; andrew@50: // bestMatchIndex = startIndex; andrew@33: } andrew@33: andrew@33: } andrew@33: startIndex++; andrew@33: } andrew@33: andrew@33: andrew@33: // printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch); andrew@33: int size = matchesFound.size(); andrew@33: if (size > 0) andrew@33: noteOnMatches[bestMatchIndex] = true; andrew@33: andrew@33: v.insert(v.begin() , (int)size);//at beginning, we list how many matches there are that we have found andrew@33: d.insert(d.begin() , (double)size); andrew@33: andrew@33: //v.push_back(size); andrew@33: //d.push_back(size); andrew@33: //for (int i = 0;i < matchesFound.size()+1;i++){ andrew@33: // v.push_back(matchesFound[i]); andrew@33: // printf("match %i,[%i] is %i\n", startIndex, i, v[i]); andrew@33: //} andrew@33: andrew@33: andrew@33: matchMatrix.push_back(v); andrew@33: matchConfidence.push_back(d); andrew@33: andrew@33: //bringing in way to list only the best matches and use these in tempo process andrew@33: bestMatchFound.push_back(bestMatchIndex); andrew@33: andrew@33: // 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); andrew@33: andrew@33: return size; andrew@33: } andrew@33: andrew@33: bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){ andrew@33: for (int i = 0;i < matchesFound.size();i++){ andrew@33: if (matchesFound[i] == tmpIndex) andrew@33: return true; andrew@33: } andrew@33: return false; andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::findLocalTempoPairs(){ andrew@33: andrew@33: int currentPlayedIndex = playedNoteOnMatrix.size()-1; andrew@33: // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); andrew@33: // printMatchesFound(); andrew@33: // printMatchMatrix(); andrew@33: // printf("possible notes \n"); andrew@33: bool needToUpdate = false; andrew@33: bayesStruct.setLikelihoodToConstant(); andrew@33: andrew@33: andrew@33: for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){ andrew@33: //iterate through the recently matched events - even dodgy matches included andrew@33: //size, index of match0, index of match1, .... andrew@33: andrew@33: andrew@33: int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1]; andrew@33: andrew@33: int previousIndex = currentPlayedIndex-1; andrew@33: andrew@33: andrew@33: while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { andrew@33: double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; andrew@33: andrew@33: for (int k = 0;k < matchMatrix[previousIndex][0];k++){ andrew@33: andrew@33: int recordedPreviousIndex = matchMatrix[previousIndex][k+1]; andrew@33: andrew@33: double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; andrew@33: andrew@33: andrew@33: //we want the speed of the recording relative to that of the playing live andrew@33: andrew@33: double speedRatio = recordedTimeDifference / playedTimeDifference; andrew@33: if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate && andrew@33: speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ andrew@33: andrew@33: //adding in a prior that prefers 1 andrew@33: double priorWeighting = 1; andrew@33: if (useTempoPrior) andrew@33: priorWeighting = sin(speedRatio * PI/2); andrew@33: andrew@33: andrew@33: andrew@33: /* andrew@33: printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); andrew@33: printf("[%i] :: ", recordedPreviousIndex); andrew@33: printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); andrew@33: printf("update on speed ratio %f\n", speedRatio); andrew@33: */ andrew@33: // matchString += " speed: "+ofToString(speedRatio, 3); andrew@33: // commented for debug andrew@33: andrew@33: //bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match andrew@33: double amount = (1-bayesStruct.speedLikelihoodNoise)/10; andrew@33: amount *= priorWeighting; andrew@33: bayesStruct.updateTempoLikelihood(speedRatio, amount); andrew@33: // tempoSpeedString += ofToString(recordedPreviousIndex) + " "+ ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; andrew@33: needToUpdate = true; andrew@33: } andrew@33: // printf("\n"); andrew@33: } andrew@33: andrew@33: previousIndex--; andrew@33: }//end while previousindex countdown andrew@33: }//end for loop through possible current matches andrew@33: andrew@33: if (needToUpdate) andrew@33: bayesStruct.updateTempoDistribution(); andrew@33: andrew@33: //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); andrew@33: } andrew@33: andrew@33: andrew@33: void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){ andrew@33: bool needToUpdate = false; andrew@33: andrew@33: DoubleVector speedIntervalsFound; andrew@33: andrew@33: //adapted this to just use the best match for each note andrew@33: andrew@33: int currentPlayedIndex = playedNoteOnMatrix.size()-1; andrew@33: // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); andrew@33: // printMatchesFound(); andrew@33: // printMatchMatrix(); andrew@33: // printf("possible notes \n"); andrew@33: andrew@33: bayesStruct.setLikelihoodToConstant(); andrew@33: andrew@33: int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; andrew@33: //we only look at intervals between the current best match and other recent best matched notes andrew@33: //that is the difference in confidence method andrew@33: andrew@33: andrew@33: //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]); andrew@33: andrew@33: int previousIndex = currentPlayedIndex-1; andrew@33: andrew@33: //withing speedwindow i.e. 4 seconds andrew@33: while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { andrew@33: double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; andrew@33: andrew@33: int recordedPreviousIndex = bestMatchFound[previousIndex]; andrew@33: andrew@33: double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; andrew@33: andrew@33: andrew@33: //we want the speed of the recording relative to that of the playing live andrew@33: andrew@33: double speedRatio = recordedTimeDifference / playedTimeDifference; andrew@33: if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate andrew@33: && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){ andrew@33: andrew@33: /* printf("(%i)", previousIndex); andrew@33: printf("[%i] :: ", recordedPreviousIndex); andrew@33: // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); andrew@33: printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); andrew@33: printf("update on speed ratio %f\n", speedRatio); andrew@33: */ andrew@33: // matchString += " speed: "+ofToString(speedRatio, 3); andrew@33: // commented for debug andrew@33: andrew@33: andrew@33: double priorWeighting = 1; andrew@33: andrew@33: if (useTempoPrior) andrew@33: priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed andrew@33: andrew@33: andrew@33: // double weighting = previousMatchConfidence * currentMatchConfidence ; andrew@33: double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9 andrew@33: andrew@33: speedIntervalsFound.push_back(speedRatio); andrew@33: // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match andrew@33: andrew@33: // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex); andrew@33: // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; andrew@33: andrew@33: needToUpdate = true; andrew@33: } andrew@33: // printf("\n"); andrew@33: andrew@33: andrew@33: previousIndex--; andrew@33: }//end while previousindex countdown andrew@33: andrew@33: if (speedIntervalsFound.size() > 0){ andrew@33: double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size(); andrew@33: for (int i = 0;i < speedIntervalsFound.size();i++) andrew@33: bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount); andrew@33: } andrew@33: andrew@33: andrew@33: if (needToUpdate) andrew@33: bayesStruct.updateTempoDistribution(); andrew@33: //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); andrew@33: } andrew@33: andrew@33: double midiEventHolder::getBestSpeedEstimate(const int& currentPlayedIndex, const int& equivalentRecordedIndex){ andrew@33: double estimate = 1.0; andrew@33: if (bestMatchIndex > 0){ andrew@33: double accordingToFileLengthEstimate = recordedEventTimes[equivalentRecordedIndex] - recordedEventTimes[0]; andrew@33: double playedEquivalent = (playedEventTimes[currentPlayedIndex] - playedEventTimes[0]); andrew@33: if (accordingToFileLengthEstimate > 0 && playedEquivalent > 0) andrew@33: accordingToFileLengthEstimate /= playedEquivalent; andrew@33: estimate = accordingToFileLengthEstimate; andrew@33: } andrew@33: return estimate; andrew@33: } andrew@33: andrew@33: void midiEventHolder::findOptimumTempoPairsToCurrentBestMatch(){ andrew@33: bool needToUpdate = false; andrew@33: andrew@33: DoubleVector speedIntervalsFound; andrew@33: andrew@33: double currentSpeedEstimate = bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate); andrew@33: andrew@33: int currentPlayedIndex = playedNoteOnMatrix.size()-1; andrew@33: andrew@33: bayesStruct.setLikelihoodToConstant(); andrew@33: andrew@33: int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; andrew@33: //we only look at intervals between the current best match and other recent best matched notes andrew@33: andrew@33: //printf("BEST MATCH FOUND for index %i is %i ", currentPlayedIndex, bestMatchFound[currentPlayedIndex]); andrew@33: andrew@33: int previousIndex = currentPlayedIndex-1; andrew@33: andrew@33: //withing speedwindow i.e. 4 seconds andrew@33: while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { andrew@33: andrew@33: double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; andrew@33: andrew@33: int recordedPreviousIndex = bestMatchFound[previousIndex]; andrew@33: andrew@33: double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; andrew@33: andrew@33: //we want the speed of the recording relative to that of the playing live andrew@33: double speedRatio = recordedTimeDifference / playedTimeDifference; andrew@33: andrew@33: //now check if this can be closer the observed value andrew@33: int checkRecordedCurrentIndex = recordedCurrentIndex; andrew@33: int checkRecordedPreviousIndex ;//= recordedCurrentIndex; andrew@33: int currentPlayedPitch = playedNoteOnMatrix[currentPlayedIndex][1]; andrew@33: int previousPlayedPitch = playedNoteOnMatrix[previousIndex][1]; andrew@33: andrew@33: double recordedTimeOfBestMatch = recordedEventTimes[recordedCurrentIndex]; andrew@33: andrew@33: //change this so we start first in window and go to end andrew@33: andrew@33: while (checkRecordedCurrentIndex >= 0 && recordedEventTimes[checkRecordedCurrentIndex] > recordedTimeOfBestMatch - matchWindowWidth){ andrew@33: andrew@33: checkRecordedCurrentIndex--; andrew@33: } andrew@33: andrew@33: double bestSpeedEstimate = getBestSpeedEstimate(currentPlayedIndex, bestMatchIndex); andrew@33: andrew@33: while (checkRecordedCurrentIndex < recordedEventTimes.size() && recordedEventTimes[checkRecordedCurrentIndex] < recordedTimeOfBestMatch + matchWindowWidth ){ andrew@33: if (recordedNoteOnMatrix[checkRecordedCurrentIndex][1] == currentPlayedPitch ){ andrew@33: checkRecordedPreviousIndex = checkRecordedCurrentIndex; andrew@33: double recordedTimeCurrent = recordedEventTimes[checkRecordedCurrentIndex] ; andrew@33: while (checkRecordedPreviousIndex >= 0 && recordedEventTimes[checkRecordedPreviousIndex] + maximumMatchSpeed*playedTimeDifference > recordedTimeCurrent ) { andrew@33: if (recordedNoteOnMatrix[checkRecordedPreviousIndex][1] == previousPlayedPitch){ andrew@33: //we have a candidate andrew@33: double speedToTest = recordedEventTimes[checkRecordedCurrentIndex] - recordedEventTimes[checkRecordedPreviousIndex]; andrew@33: speedToTest /= playedTimeDifference; andrew@33: if (abs(speedToTest-currentSpeedEstimate) < abs(speedRatio - currentSpeedEstimate) ){ andrew@33: speedRatio = speedToTest; andrew@33: } andrew@33: } andrew@33: checkRecordedPreviousIndex--; andrew@33: } andrew@33: } andrew@33: checkRecordedCurrentIndex++; andrew@33: } andrew@33: andrew@33: andrew@33: if (recordedTimeDifference > minimumTimeIntervalForTempoUpdate andrew@33: && speedRatio < maximumMatchSpeed && speedRatio > minimumMatchSpeed){ andrew@33: andrew@46: /* printf("(%i)", previousIndex); andrew@33: printf("[%i] :: ", recordedPreviousIndex); andrew@33: // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); andrew@33: printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); andrew@33: printf("update on speed ratio %f\n", speedRatio); andrew@46: */ andrew@33: // matchString += " speed: "+ofToString(speedRatio, 3); andrew@33: // commented for debug andrew@33: andrew@33: andrew@33: double priorWeighting = 1; andrew@33: andrew@33: if (useTempoPrior) andrew@33: priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed andrew@33: andrew@33: andrew@33: // double weighting = previousMatchConfidence * currentMatchConfidence ; andrew@33: double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/16;//was 9 andrew@33: andrew@33: speedIntervalsFound.push_back(speedRatio); andrew@33: // bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match andrew@33: andrew@33: // tempoSpeedString += ofToString(recordedCurrentIndex) + " :: " + ofToString(recordedPreviousIndex); andrew@33: // tempoSpeedString += " " + ofToString(recordedTimeDifference)+ " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; andrew@33: andrew@33: needToUpdate = true; andrew@33: } andrew@33: // printf("\n"); andrew@33: andrew@33: andrew@33: previousIndex--; andrew@33: }//end while previousindex countdown andrew@33: andrew@33: if (speedIntervalsFound.size() > 0){ andrew@33: double amount = (1 - bayesStruct.speedLikelihoodNoise) / speedIntervalsFound.size(); andrew@33: for (int i = 0;i < speedIntervalsFound.size();i++) andrew@33: bayesStruct.updateTempoLikelihood(speedIntervalsFound[i], amount); andrew@33: } andrew@33: andrew@33: andrew@33: if (needToUpdate) andrew@33: bayesStruct.updateTempoDistribution(); andrew@46: andrew@33: //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); andrew@33: } andrew@33: andrew@33: andrew@33: void midiEventHolder::calcuateNewInterNoteIntervals(){ andrew@33: DoubleVector v; andrew@33: andrew@33: int currentPlayedIndex = playedNoteOnMatrix.size()-1; andrew@33: // int recordedCurrentIndex = bestMatchFound[currentPlayedIndex]; andrew@33: int previousIndex = currentPlayedIndex-1; andrew@33: andrew@33: //withing speedwindow i.e. 4 seconds andrew@33: while (previousIndex >= 0 && playedEventTimes[previousIndex] + interNoteRange > playedEventTimes[currentPlayedIndex]) { andrew@33: andrew@33: double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; andrew@33: andrew@33: checkForCorrectInterval(playedTimeDifference, &v); andrew@33: andrew@33: previousIndex--; andrew@33: } andrew@33: andrew@33: if (v.size() > 0) andrew@33: interNoteIntervals.push_back(v); andrew@33: //printf("\n"); andrew@33: } andrew@33: andrew@33: void midiEventHolder::checkForCorrectInterval(const double& playedTimeDifference, DoubleVector* v){ andrew@33: double intervalDuration = 0.0; andrew@33: andrew@33: for (int intervalIndex = 0;intervalIndex < 3;intervalIndex++){ andrew@33: //on;y check 1,2 and 4 andrew@33: double possibleDuration = playedTimeDifference / intervalsToCheck[intervalIndex]; andrew@33: if (possibleDuration >= 200 && possibleDuration < 400){ andrew@33: v->push_back(possibleDuration); andrew@33: // printf("int %f / %i :: %f ", playedTimeDifference, intervalsToCheck[intervalIndex], possibleDuration); andrew@33: } andrew@33: } andrew@33: } andrew@33: andrew@52: #pragma mark -Position Update andrew@33: andrew@33: void midiEventHolder::updatePlayPosition(){ andrew@34: //timeDifference = ofGetElapsedTimeMillis() - startPlayingTime;//elpased andrew@33: andrew@33: //in actual fact if we are changing the speed of the play position andrew@33: //we will need to update this via the file andrew@33: andrew@33: //actually time since beginning of file i think andrew@33: andrew@33: double timeDifference = 0; andrew@34: andrew@34: if (runningInRealTime){ andrew@34: andrew@48: bayesStruct.updateBestEstimate(0);//was timedifference andrew@34: // bayesStruct.updateTmpBestEstimate(timeDifference); andrew@34: } andrew@34: andrew@49: //did just update smooth to current if it was less andrew@35: andrew@35: if (smoothPlayPosition < bayesStruct.bestEstimate){ andrew@50: // updateOutputPositionTo(bayesStruct.bestEstimate); andrew@50: smoothPlayPosition = bayesStruct.bestEstimate; andrew@35: } andrew@34: andrew@50: updateOutputPositionTo(causalPlayPosition); //need it outputting before the update andrew@50: andrew@50: updateCausalPlayPosition(getTimeNow(bayesStruct.lastBestEstimateUpdateTime)); andrew@50: andrew@49: andrew@49: andrew@50: //can choose to output either the smooth position (i.e. forwards) andrew@50: //or causal play position which aims toward our current smooth position in near future andrew@48: andrew@50: andrew@50: andrew@50: /* andrew@49: //now we try updating it to a causal path that tries to match into the future andrew@49: if (smoothPlayPosition < causalPlayPosition){ andrew@49: updateSmoothPositionTo(causalPlayPosition); andrew@49: } andrew@49: */ andrew@49: andrew@34: // playPositionInMillis = timeDifference;//based on updating from when we change period andrew@34: //this to be added andrew@34: andrew@33: andrew@33: //this is time diff in milliseconds andrew@33: //then we have andrew@33: double quarterNoteIntervals = (timeDifference / period); andrew@33: tickLocation = quarterNoteIntervals * pulsesPerQuarternote; andrew@33: andrew@33: updateNoteCounter(); andrew@33: andrew@33: } andrew@33: andrew@50: void midiEventHolder::updateOutputPositionTo(const double& newPosition){ andrew@42: //smooth play position was where we last outputted notes from. andrew@42: //checking index is there to make sense. andrew@50: // double checkPosition = smoothPlayPosition; andrew@50: double checkPosition = lastUpdatePosition; andrew@50: andrew@50: andrew@50: while (outputIndex > 0 && recordedEventTimes[outputIndex] > checkPosition){ andrew@50: outputIndex--; andrew@50: // printf("going backewards, smooth time %f, ", recordedEventTimes[outputIndex]); andrew@35: } andrew@50: while (outputIndex < recordedEventTimes.size()-1 && recordedEventTimes[outputIndex] < checkPosition){ andrew@50: outputIndex++; andrew@50: // printf("outputting smooth forwards time %f\n ", recordedEventTimes[outputIndex], checkPosition); andrew@35: } andrew@35: andrew@50: // printf("last output position %f, new position %f\n", checkPosition, newPosition); andrew@50: // printf("causal pos %.0f, smooth pos %.0f, best est %.0f\n", causalPlayPosition, smoothPlayPosition, bayesStruct.bestEstimate); andrew@50: andrew@50: outputPosition = recordedEventTimes[outputIndex]; andrew@35: andrew@35: double playingTime = ofGetElapsedTimeMillis(); andrew@35: playingTime -= startPlayingTime; andrew@35: //now at the last one andrew@35: andrew@50: float smoothLocation = beatPositions[outputIndex]; andrew@50: int currentNote = recordedNoteOnMatrix[outputIndex][1]; andrew@36: andrew@50: while (outputIndex < recordedEventTimes.size() && recordedEventTimes[outputIndex] < newPosition){ andrew@36: float annotationTime = 0; andrew@38: float annotationLocation = 0; andrew@42: int annotationTick = 0; andrew@36: int annotationNote = 0; andrew@39: float difference = 10000;//very big andrew@50: //float currentLocationDifference = 1.0; andrew@50: andrew@50: double amountSinceLastUpdate = 0.0;//between 0 and 1, the exact position of this event since last update andrew@50: if (newPosition > lastUpdatePosition){ andrew@50: amountSinceLastUpdate = (recordedEventTimes[outputIndex] - lastUpdatePosition)/(newPosition - lastUpdatePosition); andrew@50: } andrew@50: andrew@39: float range = 1.0; andrew@50: if (outputIndex < myNotation.rwcAnnotations.size()){ andrew@39: //add in test here to find closest matching note andrew@39: andrew@42: andrew@50: annotationTime = myNotation.rwcAnnotations[outputIndex].eventTime; andrew@50: annotationNote = myNotation.rwcAnnotations[outputIndex].midiNote; andrew@50: annotationLocation = myNotation.rwcAnnotations[outputIndex].beatLocation; andrew@42: annotationTick = round(annotationLocation*480.0); andrew@42: }else{ andrew@42: printf("No annotaion size %i\n", (int)myNotation.rwcAnnotations.size()); andrew@36: } andrew@36: andrew@50: double exactPlayingTime = amountSinceLastUpdate*playingTime + ((1 - amountSinceLastUpdate)*lastUpdatePlayingTime); andrew@39: difference = playingTime - (annotationTime*1000.0); andrew@50: double exactDifference = exactPlayingTime - (annotationTime*1000.0); andrew@50: /* andrew@50: //NO LONGER NEEDED ALLO andrew@50: if ((*fileOutput).is_open()){ andrew@50: (*fileOutput) << fixed << beatPositions[outputIndex] <<",\t" << recordedNoteOnMatrix[outputIndex][1] << ",\t"; andrew@36: (*fileOutput) << playingTime ; andrew@37: andrew@50: if ( recordedNoteOnMatrix[outputIndex][1] == annotationNote){ andrew@36: (*fileOutput) << " corresponds to " << annotationTime; andrew@36: } andrew@36: (*fileOutput) << " \n"; andrew@48: andrew@37: } andrew@50: */ andrew@42: andrew@50: //useful printing stuff andrew@50: // printf("playing time %.1f, annotation time %.1f, diff %.1f\n", playingTime, (annotationTime*1000.0), difference); andrew@50: andrew@50: // printf("last posn %.1f, amount since %.2f \n" lastUpdatePosition, amountSinceLastUpdate); andrew@50: andrew@50: // printf("annotations:Diff %f rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n", andrew@50: // difference, recordedNoteOnMatrix[outputIndex][0], annotationTick, recordedNoteOnMatrix[outputIndex][1], andrew@50: // beatPositions[outputIndex], playingTime, andrew@50: // annotationNote, annotationLocation, annotationTime, difference); andrew@50: andrew@50: // we use exact difference as it more accurately predicts where we scheduled the note andrew@50: // printf("diff %.1f, exact diff %.1f\n", difference, exactDifference); andrew@50: andrew@50: andrew@50: //assert(annotationNote == recordedNoteOnMatrix[outputIndex][1]); andrew@50: assert(annotationTick == recordedNoteOnMatrix[outputIndex][0]); andrew@42: andrew@49: smoothDifference = difference; andrew@42: andrew@37: if ((*differenceOutput).is_open()){ andrew@50: (*differenceOutput) << beatPositions[outputIndex] << "," << exactDifference << "," << playingTime << "," << (annotationTime*1000.0) << annotationNote << difference << "\n"; andrew@42: // printf("midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n", andrew@50: // recordedNoteOnMatrix[outputIndex][1], andrew@50: // beatPositions[outputIndex], playingTime, andrew@42: // annotationNote, annotationLocation, annotationTime, difference); andrew@42: }else{ andrew@42: printf("file not open\n"); andrew@35: } andrew@35: andrew@50: outputIndex++; andrew@35: } andrew@35: andrew@50: lastUpdatePosition = newPosition; andrew@50: lastUpdatePlayingTime = playingTime; andrew@35: } andrew@35: andrew@48: void midiEventHolder::updateCausalPlayPosition(const double& timeNow){ andrew@48: //projected position andrew@49: andrew@50: //first update the speed andrew@50: updateCausalSpeed(); andrew@50: andrew@50: causalPlayPosition += causalSpeed * (timeNow - lastCausalUpdateTime); andrew@50: lastCausalUpdateTime = timeNow; andrew@50: andrew@50: } andrew@50: andrew@50: void midiEventHolder::updateCausalSpeed(){ andrew@48: double difference = bayesStruct.bestEstimate - causalPlayPosition; andrew@48: causalSpeed = bayesStruct.speedEstimate; andrew@48: causalSpeed += (difference/timeProjectionToMeet); andrew@48: andrew@48: if (causalSpeed < 0) andrew@48: causalSpeed = 0; andrew@50: andrew@48: } andrew@50: andrew@46: /* andrew@34: void midiEventHolder::updatePeriodValue(const double& millis){ andrew@34: andrew@34: double tmp = period; andrew@46: andrew@46: // while (periodCounter >= 0 && periodCounter < periodValues.size()-1 && periodValues[periodCounter][2] < millis){ andrew@46: // periodCounter++; andrew@46: // } andrew@46: // while (periodCounter > 0 && periodValues[periodCounter][2] > millis){ andrew@46: // periodCounter--; andrew@46: // } andrew@46: // andrew@34: //period = periodValues[periodCounter][1]; andrew@34: andrew@34: if (period != tmp){ andrew@34: printf("new period at %f of %f\n", millis, period); andrew@34: } andrew@34: } andrew@46: */ andrew@34: andrew@33: void midiEventHolder::updateNoteCounter(){ andrew@33: while (totalNoteCounterIndex < bestMatchIndex){ andrew@33: int tmpPitch = recordedNoteOnMatrix[totalNoteCounterIndex][1]; andrew@33: recordedTotalNoteCounterByPitch[tmpPitch] += 1; andrew@33: totalNoteCounterIndex++; andrew@33: } andrew@33: } andrew@33: andrew@52: #pragma mark -Drawing andrew@33: andrew@33: void midiEventHolder::drawMidiFile(){ andrew@46: //ofBackground(80,80,80); andrew@33: andrew@33: //draws midi file on scrolling screen andrew@33: int size = recordedNoteOnMatrix.size(); andrew@33: if (size > 0){ andrew@33: andrew@33: numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in andrew@33: andrew@33: // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down andrew@33: timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen); andrew@33: andrew@33: while (noteArrayIndex < recordedNoteOnMatrix.size()-1 && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] ) andrew@33: noteArrayIndex++; andrew@33: andrew@33: andrew@33: while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0]) andrew@33: noteArrayIndex--; andrew@33: andrew@33: //need to start where we currently are in file andrew@33: int maxNoteIndexToPrint = noteArrayIndex; andrew@33: int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above andrew@33: andrew@33: while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) andrew@33: maxNoteIndexToPrint++; andrew@33: andrew@33: while (minNoteIndexToPrint > 0 && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size andrew@33: minNoteIndexToPrint--; andrew@33: andrew@33: for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){ andrew@33: andrew@33: ofSetColor(255,255,255); andrew@33: if (checkIfMatchedNote(tmpIndex)) andrew@33: ofSetColor(100,100,100);//0,0,255); andrew@52: else if(noteOnMatches[tmpIndex] && !saveImage){ andrew@52: ofSetHexColor(matchedColor);//pink andrew@33: } andrew@33: else{ andrew@33: ofSetColor(255,255,255);//255,255,255); andrew@33: } andrew@33: andrew@33: //ofSetColor(255,255,255); andrew@52: if (tmpIndex == bestMatchIndex && !saveImage) andrew@52: ofSetHexColor(bestMatchedColor);//best recent match is in red andrew@33: andrew@33: // XXX replace ofgetwidth below andrew@33: //if (tmpIndex >= 0 && tmpIndex < size) andrew@33: int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; andrew@33: int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen; andrew@33: andrew@33: andrew@33: int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); andrew@33: ofRect(xLocation,yLocation, duration, noteHeight); andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: int xLocation;// = getLocationFromTicks(tickLocation); andrew@33: // ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: andrew@33: //orange line at best estimate andrew@33: xLocation = getLocationFromMillis(bayesStruct.bestEstimate); andrew@34: ofSetColor(250,250,20);//250,100,0); andrew@52: if (!saveImage) andrew@33: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: andrew@50: andrew@50: /* andrew@50: //cyan blue - smooth position andrew@34: xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate andrew@50: ofSetColor(0,250,250);//250,150, 250,100,0); andrew@50: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@50: */ andrew@50: //bright green is the causal play position andrew@48: xLocation = getLocationFromMillis(causalPlayPosition);//bayesStruct.tmpBestEstimate andrew@48: ofSetColor(0,250,0);//250,150, 250,100,0); andrew@52: if (!saveImage) andrew@52: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: andrew@33: //lines where matching window start and end are andrew@33: ofSetColor(0);//0,100,255); andrew@33: xLocation = getLocationFromMillis(windowStartTime); andrew@33: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth); andrew@33: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: andrew@33: andrew@33: int maxSize = recordedNoteOnMatrix[size-1][0]; andrew@33: andrew@33: int tmpIndex = 0; andrew@33: while (tmpIndex < measureVector.size() && measureVector[tmpIndex] < (numberOfScreensIn+1)*ticksPerScreen){ andrew@33: int measureLocation = measureVector[tmpIndex]; andrew@33: int xLocation = (float)(measureLocation - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; andrew@52: ofSetColor(155,155,155); andrew@33: ofLine(xLocation, 0, xLocation, (*screenHeight)); andrew@33: tmpIndex++; andrew@33: } andrew@33: andrew@33: andrew@33: // ofDrawBitmapString(tempoSpeedString, 20, 20); andrew@33: /* string indexString = "num screens in "+ofToString(numberOfScreensIn)+"; min index to print "+ofToString(minNoteIndexToPrint)+", max index to print "+ofToString(maxNoteIndexToPrint); andrew@33: indexString += " size "+ofToString(size)+" tick loc "+ofToString(tickLocation)+" max size "+ofToString(maxSize); andrew@33: ofDrawBitmapString(indexString, 20, 40); andrew@33: */ andrew@33: } andrew@33: andrew@33: //ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20); andrew@52: andrew@52: if (printInfo){ andrew@46: ofSetColor(255,255,255); andrew@46: ofDrawBitmapString(timeString, 20, 60); andrew@50: string diffString = "diff "+ofToString(smoothDifference); andrew@50: diffString += "\ncausal posn: "+ofToString(causalPlayPosition, 0); andrew@50: diffString += "\nsmooth posn: "+ofToString(smoothPlayPosition, 0); andrew@50: diffString += "\noutput posn: "+ofToString(outputPosition, 0); andrew@50: diffString += "\nbest est: "+ofToString(bayesStruct.bestEstimate, 0); andrew@50: diffString += "\nlast best est: "+ofToString(bayesStruct.lastBestEstimateUpdateTime, 0); andrew@33: andrew@50: ofDrawBitmapString(diffString, 20, 140); andrew@52: } andrew@50: andrew@50: //last played pitch andrew@52: andrew@33: ofSetColor(0,200,0,50); andrew@33: int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); andrew@52: if (!saveImage) andrew@52: ofRect(0,yLocation, 100, noteHeight); andrew@33: andrew@33: andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::drawMidiFile(IntMatrix& midiFileToDraw){ andrew@33: andrew@33: //using this to draw the live input andrew@33: andrew@33: //draws midi file on scrolling screen andrew@33: int size = midiFileToDraw.size(); andrew@33: if (size > 0){ andrew@33: andrew@33: numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in andrew@33: andrew@33: // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down andrew@33: timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen); andrew@33: andrew@33: while (noteArrayIndex < midiFileToDraw.size()-1 && tickLocation > midiFileToDraw[noteArrayIndex][0] ) andrew@33: noteArrayIndex++; andrew@33: andrew@33: andrew@33: while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < midiFileToDraw[noteArrayIndex][0]) andrew@33: noteArrayIndex--; andrew@33: andrew@33: //need to start where we currently are in file andrew@33: int maxNoteIndexToPrint = noteArrayIndex; andrew@33: int minNoteIndexToPrint = min(size-1,noteArrayIndex);//not needed as changed above andrew@33: andrew@33: while (maxNoteIndexToPrint < midiFileToDraw.size() && midiFileToDraw[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) andrew@33: maxNoteIndexToPrint++; andrew@33: andrew@33: while (minNoteIndexToPrint > 0 && midiFileToDraw[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen)//&& minNoteIndexToPrint < size andrew@33: minNoteIndexToPrint--; andrew@33: andrew@33: for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)midiFileToDraw.size());tmpIndex++){ andrew@33: andrew@33: ofSetColor(0,0,255, 200); andrew@33: andrew@33: int xLocation = (float)(midiFileToDraw[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; andrew@33: int duration = (float)(midiFileToDraw[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen; andrew@33: andrew@33: andrew@33: int yLocation = (*screenHeight) - ((midiFileToDraw[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); andrew@33: ofRect(xLocation,yLocation, duration, noteHeight); andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::drawFile(){ andrew@52: drawMidiFile(); andrew@33: andrew@52: if (saveImage){ andrew@52: std::string file = "/Users/andrew/Documents/work/programming/of_preRelease_v007_osx/apps/myOpenFrameworks007/JNMR_MidiFollower/bin/data/FilesOut/cleanMidiLayout.png"; andrew@52: saveImageFile(file); andrew@52: } andrew@52: andrew@52: andrew@52: if (printInfo){ andrew@34: ofSetColor(0,0,255); andrew@34: ofDrawBitmapString("period"+ofToString(period, 2), ofGetWidth() - 180, 20); andrew@52: } andrew@33: andrew@33: // bayesStruct.drawArrays(); andrew@33: andrew@33: // ofSetColor(200,200,0); andrew@33: // bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800); andrew@33: andrew@33: //need to draw arrays within correct timescope andrew@33: if (drawPhaseMode) andrew@52: bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen)); andrew@33: andrew@33: if (drawTempoMode) andrew@40: bayesStruct.drawTempoArrays(); andrew@33: andrew@52: if (saveImage){ andrew@52: std::string file = "/Users/andrew/Documents/work/programming/of_preRelease_v007_osx/apps/myOpenFrameworks007/JNMR_MidiFollower/bin/data/FilesOut/distbnMidiLayout.png"; andrew@52: saveImageFile(file); andrew@52: saveImage = false; andrew@52: } andrew@33: andrew@33: ofSetColor(0, 0, 0); andrew@33: //ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); andrew@33: andrew@33: double confidence = bayesStruct.posterior.getValueAtMillis(mouseX); andrew@33: /* andrew@33: string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; andrew@33: ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); andrew@33: andrew@33: string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter); andrew@33: ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); andrew@33: andrew@33: string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3); andrew@33: ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60); andrew@33: */ andrew@33: andrew@33: //drawInterNoteIntervals(); andrew@33: andrew@33: } andrew@33: andrew@52: andrew@52: andrew@52: andrew@52: andrew@33: void midiEventHolder::drawInterNoteIntervals(){ andrew@33: andrew@33: ofSetColor(0,0,150); andrew@33: int size = interNoteIntervals.size(); andrew@33: int numberToShow = min(100, size); andrew@33: double x ; andrew@33: for (int y = 1;y < numberToShow;y++){ andrew@33: for (int point = 0;point < interNoteIntervals[y].size();point++){ andrew@33: double interval = interNoteIntervals[size - y][point]; andrew@33: x = interval - 200; andrew@33: x *= (*screenWidth) / 200.0; andrew@33: } andrew@33: double h = (double)(y * (*screenHeight)) / numberToShow; andrew@33: ofCircle(x, h, 5); andrew@33: } andrew@33: andrew@33: } andrew@33: andrew@52: #pragma mark -saveDistributionsAsTextFile andrew@52: andrew@52: void midiEventHolder::writeAllDistributions(){ andrew@52: std::string file = "/Users/andrew/Documents/work/programming/of_preRelease_v007_osx/apps/myOpenFrameworks007/JNMR_MidiFollower/bin/data/FilesOut/priorDistbnOut.txt"; andrew@52: writeDistribution(bayesStruct.prior, file); andrew@52: file = "/Users/andrew/Documents/work/programming/of_preRelease_v007_osx/apps/myOpenFrameworks007/JNMR_MidiFollower/bin/data/FilesOut/likelihoodDistbnOut.txt"; andrew@52: writeDistribution(bayesStruct.likelihood, file); andrew@52: file = "/Users/andrew/Documents/work/programming/of_preRelease_v007_osx/apps/myOpenFrameworks007/JNMR_MidiFollower/bin/data/FilesOut/posteriorDistbnOut.txt"; andrew@52: writeDistribution(bayesStruct.posterior, file); andrew@52: andrew@52: saveImage = true; andrew@52: andrew@52: } andrew@52: andrew@52: void midiEventHolder::saveImageFile(std::string file){ andrew@52: img.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); andrew@52: img.saveImage(file); andrew@52: } andrew@52: andrew@52: andrew@52: void midiEventHolder::writeDistribution(DynamicVector& distribution, std::string file){ andrew@52: andrew@52: dataWriter.openFile(file); andrew@52: andrew@52: double startTimeMillis = timeOffsetForScreen; andrew@52: double endTimeMillis = timeOffsetForScreen + getEventTimeMillis(ticksPerScreen); andrew@52: andrew@52: int startArrayIndex = 0; andrew@52: andrew@52: if (distribution.getIndexInRealTerms(distribution.arraySize-1) > startTimeMillis){ andrew@52: //i.e. the array is on the page andrew@52: andrew@52: while (distribution.getIndexInRealTerms(startArrayIndex) < startTimeMillis){ andrew@52: startArrayIndex++; andrew@52: } andrew@52: } andrew@52: andrew@52: int endArrayIndex = distribution.arraySize-1; andrew@52: //could find constraints here andrew@52: if (distribution.getIndexInRealTerms(distribution.arraySize-1) > endTimeMillis) andrew@52: endArrayIndex = (floor)((endTimeMillis - distribution.offset)/distribution.scalar); andrew@52: andrew@52: andrew@52: andrew@52: for (int i = startArrayIndex;i <= endArrayIndex;i++){ andrew@52: dataWriter.writeValue(distribution.getIndexInRealTerms(i), distribution.array[i]); andrew@52: } andrew@52: dataWriter.closeFile(); andrew@52: andrew@52: andrew@52: } andrew@52: andrew@33: andrew@33: void midiEventHolder::printInterNoteIntervals(){ andrew@33: andrew@33: int size = interNoteIntervals.size(); andrew@33: int numberToShow = 20; andrew@33: double x ; andrew@33: for (int y = max(0, size - numberToShow);y < interNoteIntervals.size();y++){ andrew@33: for (int point = 0;point < interNoteIntervals[y].size();point++){ andrew@33: printf("[%i][%i] : %f", y, point, interNoteIntervals[y][point]); andrew@33: } andrew@33: printf("\n"); andrew@33: } andrew@33: andrew@33: } andrew@33: andrew@46: //int midiEventHolder::getLocationFromTicks(double tickPosition){ andrew@46: // return 0; andrew@34: // return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); andrew@34: //not used andrew@46: //} andrew@33: andrew@33: int midiEventHolder::getLocationFromMillis(double millisPosition){ andrew@33: //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen andrew@33: return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen); andrew@33: } andrew@33: andrew@46: /* andrew@33: void midiEventHolder::exampleCrossUpdate(){ andrew@33: andrew@33: bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200); andrew@33: andrew@33: } andrew@46: */ andrew@33: andrew@33: void midiEventHolder::setStartPlayingTimes(){ andrew@34: startPlayingTime = getTimeNow(0);//ofGetElapsedTimeMillis(); andrew@34: //startTime = startPlayingTime; andrew@42: printf("starting playing at time %f\n", startPlayingTime); andrew@33: /* andrew@33: bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis(); andrew@33: bayesStruct.bestEstimate = 0; andrew@33: bayesStruct.resetArrays(); andrew@33: bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); andrew@33: */ andrew@33: bayesStruct.setStartPlaying(); andrew@33: matchString = ""; andrew@33: } andrew@33: andrew@33: andrew@33: void midiEventHolder::printMatchMatrix(){ andrew@33: printf("match matrix:\n"); andrew@33: for (int i = 0;i < matchMatrix.size();i++){ andrew@33: for (int k = 0;k < matchMatrix[i].size();k++){ andrew@33: printf("%i , ", matchMatrix[i][k]); andrew@33: } andrew@33: printf("\n"); andrew@33: } andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::printRecordedEvents(){ andrew@33: printf("Recorded Events:\n"); andrew@33: for (int i = 0;i < recordedNoteOnMatrix.size();i++){ andrew@33: for (int k = 0;k < recordedNoteOnMatrix[i].size();k++){ andrew@33: printf("[%i] = %i ,", i, recordedNoteOnMatrix[i][k]); andrew@33: } andrew@33: if (i < recordedEventTimes.size()) andrew@33: printf("time %f \n", recordedEventTimes[i]); andrew@33: else andrew@33: printf("\n"); andrew@33: } andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::reorderMatrixFromNoteTimes(IntMatrix& noteOnMatrix){ andrew@33: double currentTime = -19999.; andrew@33: for (int i = 0;i < noteOnMatrix.size();i++){ andrew@33: int nextIndex = getIndexOfMinimumAboveTime(currentTime, noteOnMatrix); andrew@33: // cout << "index of min time " << currentTime << " is " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << endl; andrew@33: andrew@33: if (nextIndex >= 0 && nextIndex > i && noteOnMatrix[nextIndex][0] < noteOnMatrix[i][0] ){ andrew@33: //which it should be andrew@33: // cout << " index " << nextIndex << " at time " << noteOnMatrix[nextIndex][0] << " swaps with inex " << i << " at time " << noteOnMatrix[i][0] << endl; andrew@33: noteOnMatrix[i].swap(noteOnMatrix[nextIndex]); andrew@35: // double tmp = beatPositions[i]; andrew@35: // beatPositions[i] = beatPositions[nextIndex]; andrew@35: // = tmp; andrew@35: andrew@35: swap (beatPositions[i], beatPositions[nextIndex]); andrew@35: andrew@35: andrew@33: currentTime = noteOnMatrix[i][0]; andrew@33: } andrew@33: andrew@33: } andrew@33: //printRecordedEvents(); andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::doublecheckOrder(IntMatrix& noteOnMatrix){ andrew@33: andrew@33: for (int i = 0;i < noteOnMatrix.size();i++){ andrew@33: int nextIndex = getIndexOfMinimumAboveIndex(i, noteOnMatrix); andrew@33: if (nextIndex > i){ andrew@33: noteOnMatrix[i].swap(noteOnMatrix[nextIndex]); andrew@35: swap (beatPositions[i], beatPositions[nextIndex]); andrew@35: andrew@33: } andrew@33: } andrew@33: } andrew@33: andrew@33: int midiEventHolder::getIndexOfMinimumAboveIndex(const int& index, IntMatrix& noteOnMatrix){ andrew@33: int returnIndex = index; andrew@33: int min = noteOnMatrix[index][0]; andrew@33: for (int i = index;i < noteOnMatrix.size();i++){ andrew@33: if (noteOnMatrix[i][0] < min){ andrew@33: returnIndex = i; andrew@33: min = noteOnMatrix[i][0]; andrew@33: } andrew@33: } andrew@33: return returnIndex; andrew@33: } andrew@33: andrew@33: andrew@33: int midiEventHolder::getIndexOfMinimumAboveTime(const double& time, IntMatrix& noteOnMatrix){ andrew@33: int index = 0; andrew@33: double minimumTime = 100000000.; andrew@33: int bestIndex = -1; andrew@33: while (index < noteOnMatrix.size()){ andrew@33: andrew@33: if (noteOnMatrix[index][0] > time && noteOnMatrix[index][0] < minimumTime){ andrew@33: bestIndex = index; andrew@33: minimumTime = noteOnMatrix[index][0]; andrew@33: } andrew@33: index++; andrew@33: } andrew@33: return bestIndex; andrew@33: } andrew@33: andrew@33: andrew@33: andrew@33: andrew@33: void midiEventHolder::correctTiming(IntMatrix& noteOnMatrix){ andrew@33: andrew@33: if (noteOnMatrix.size() > 0 && noteOnMatrix[0][0] < 0) { andrew@33: int offset = noteOnMatrix[0][0]; andrew@33: for (int i = 0;i < noteOnMatrix.size();i++){ andrew@33: noteOnMatrix[i][0] -= offset; andrew@33: } andrew@33: } andrew@33: andrew@33: } andrew@33: andrew@33: andrew@33: void midiEventHolder::printNoteCounter(){ andrew@33: for (int i = 0;i < recordedTotalNoteCounterByPitch.size();i++){ andrew@33: printf("RECORDED TOTAL[%i] := %i", i, recordedTotalNoteCounterByPitch[i]); andrew@33: } andrew@34: } andrew@34: andrew@34: /* double timeDiff = 0;//timeDifference; andrew@34: if (runningInRealTime) andrew@34: timeDiff = ofGetElapsedTimeMillis() - lastSmoothUpdateTime; andrew@34: // bayesStruct.lastBestEstimateUpdateTime; andrew@34: andrew@34: //smoothPlayPosition = bayesStruct.bestEstimate + 100; andrew@34: //relativeSpeedForSmooth = 0.1; andrew@34: //bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate); andrew@34: // speedEstimate*2; andrew@34: andrew@34: smoothPlayPosition = storedSmoothPlayPosition + timeDiff * relativeSpeedForSmooth;// * bayesStruct.speedEstimate; andrew@34: storedSmoothPlayPosition = smoothPlayPosition; andrew@34: lastSmoothUpdateTime = getTimeNow(bayesStruct.lastBestEstimateUpdateTime); andrew@34: updateSmoothPlaySpeed(); andrew@34: //bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate) andrew@34: andrew@34: } andrew@34: andrew@34: void midiEventHolder::updateSmoothPlaySpeed(){ andrew@34: //project where current play pos will be in two seconds and aim for it. andrew@34: double timeToAimForMillis = 2000.0; andrew@34: //double timeDiff = ofGetElapsedTimeMillis() - bayesStruct.lastBestEstimateUpdateTime;//since the update need to get to where we are andrew@34: double projection = bayesStruct.bestEstimate + bayesStruct.speedEstimate*timeToAimForMillis;// andrew@34: double timeDifferenceFromSmooth = projection - smoothPlayPosition; andrew@34: relativeSpeedForSmooth = timeDifferenceFromSmooth / timeToAimForMillis; andrew@34: andrew@34: } andrew@34: */ andrew@35: andrew@35: andrew@35: /* andrew@35: void midiEventHolder::findLocalTempoPairsWeightedForConfidence(){ andrew@35: bool needToUpdate = false; andrew@35: andrew@35: //adapted this to just use the best match for each note andrew@35: andrew@35: int currentPlayedIndex = playedNoteOnMatrix.size()-1; andrew@35: // printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); andrew@35: // printMatchesFound(); andrew@35: // printMatchMatrix(); andrew@35: // printf("possible notes \n"); andrew@35: andrew@35: bayesStruct.setLikelihoodToConstant(); andrew@35: andrew@35: for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){ andrew@35: andrew@35: //iterate through the recently matched events - even dodgy matches included andrew@35: //size, index of match0, index of match1, .... andrew@35: int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1]; andrew@35: andrew@35: double currentMatchConfidence = matchConfidence[currentPlayedIndex][i+1];//new confidence andrew@35: andrew@35: int previousIndex = currentPlayedIndex-1; andrew@35: andrew@35: while (previousIndex >= 0 && playedEventTimes[previousIndex] + speedWindowWidthMillis > playedEventTimes[currentPlayedIndex]) { andrew@35: double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; andrew@35: andrew@35: // for (int k = 0;k < matchMatrix[previousIndex][0];k++) andrew@35: int recordedPreviousIndex = bestMatchFound[previousIndex];//matchMatrix[previousIndex][k+1]; andrew@35: andrew@35: //double previousMatchConfidence = matchConfidence[previousIndex][k+1]; andrew@35: andrew@35: andrew@35: double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; andrew@35: andrew@35: andrew@35: //we want the speed of the recording relative to that of the playing live andrew@35: andrew@35: double speedRatio = recordedTimeDifference / playedTimeDifference; andrew@35: if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ andrew@35: andrew@35: printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); andrew@35: printf("[%i] :: ", recordedPreviousIndex); andrew@35: // printf(" conf %f & %f ", currentMatchConfidence, previousMatchConfidence); andrew@35: printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); andrew@35: printf("update on speed ratio %f\n", speedRatio); andrew@35: andrew@35: // matchString += " speed: "+ofToString(speedRatio, 3); andrew@35: // commented for debug andrew@35: andrew@35: andrew@35: double priorWeighting = 1; andrew@35: andrew@35: if (useTempoPrior) andrew@35: priorWeighting = sin(speedRatio * PI/2);//adding in a prior that prefers 1.0 speed andrew@35: andrew@35: andrew@35: // double weighting = previousMatchConfidence * currentMatchConfidence ; andrew@35: double amount = (1-bayesStruct.speedLikelihoodNoise)*priorWeighting/10; andrew@35: bayesStruct.updateTempoLikelihood(speedRatio, amount);//second paramter is confidence in the match andrew@35: tempoSpeedString += ofToString(recordedPreviousIndex) + " " + ofToString(speedRatio, 2) + " "+ofToString(amount, 2) += " \n"; andrew@35: andrew@35: needToUpdate = true; andrew@35: } andrew@35: // printf("\n"); andrew@35: andrew@35: andrew@35: previousIndex--; andrew@35: }//end while previousindex countdown andrew@35: }//end for loop through possible current matches andrew@35: andrew@35: if (needToUpdate) andrew@35: bayesStruct.updateTempoDistribution(); andrew@35: //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); andrew@35: } andrew@35: */ andrew@35: andrew@42: /* andrew@42: JUNK SMOOTH StuffHex andrew@42: /* andrew@50: int testIndex = outputIndex; andrew@42: while (testIndex >= 0 && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){ andrew@42: andrew@42: if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){ andrew@42: if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){ andrew@42: currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation); andrew@42: difference = playingTime - (myNotation.rwcAnnotations[testIndex].eventTime*1000.0); andrew@42: annotationNote = myNotation.rwcAnnotations[testIndex].midiNote; andrew@42: annotationLocation = myNotation.rwcAnnotations[testIndex].beatLocation; andrew@42: annotationTime = myNotation.rwcAnnotations[testIndex].eventTime; andrew@42: } andrew@42: } andrew@42: testIndex--; andrew@42: } andrew@42: andrew@50: testIndex = outputIndex; andrew@42: while (testIndex >= 0 && testIndex < myNotation.rwcAnnotations.size() && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){ andrew@42: andrew@42: if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){ andrew@42: if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){ andrew@42: currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation); andrew@42: difference = playingTime - (myNotation.rwcAnnotations[testIndex].eventTime*1000.0); andrew@42: annotationNote = myNotation.rwcAnnotations[testIndex].midiNote; andrew@42: annotationLocation = myNotation.rwcAnnotations[testIndex].beatLocation; andrew@42: annotationTime = myNotation.rwcAnnotations[testIndex].eventTime; andrew@42: } andrew@42: } andrew@42: testIndex++; andrew@42: } andrew@42: */