Mercurial > hg > midi-score-follower
view src/midiEventHolder.cpp @ 52:13194a9dca77 tip
Added exporting of image and text data
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Tue, 17 Jul 2012 22:13:10 +0100 |
parents | 5a11b19906c7 |
children |
line wrap: on
line source
/* * midiEventHolder.cpp * midiCannamReader3 * * Created by Andrew on 19/07/2011. * Copyright 2011 QMUL. All rights reserved. * */ #include "midiEventHolder.h" midiEventHolder::midiEventHolder(){ // recordedNoteOnIndex = 0; useTempoPrior = false;//puts sine wave round tempo confidenceWeightingUsed = true; //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; likelihoodWidth = 100;//using 100 is good likelihoodToNoiseRatio = 0.08;//was 0.02 on 18/11/11, changing to give more weight to observations bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05 bayesStruct.speedDecayWidth = 20; bayesStruct.speedDecayAmount = 10; speedPriorValue = 1.0; matchWindowWidth = 12000;//window size for matching in ms bayesStruct.resetSize(matchWindowWidth); bayesStruct.setPositionDistributionScalar(1); bayesStruct.resetSpeedSize(200); bayesStruct.setRelativeSpeedScalar(0.01); bayesStruct.relativeSpeedPrior.getMaximum(); //bayesStruct.simpleExample(); speedWindowWidthMillis = 4000; speedPriorValue = 1.0; noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); 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; lastPeriodUpdateTime = 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; bayesStruct.resetSpeedToOne(); bayesStruct.setSpeedPrior(speedPriorValue); setMatchedNotesBackToFalse(); } 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(); //played events: playedEventTimes.clear(); playedNoteOnMatrix.clear(); matchMatrix.clear(); bestMatchFound.clear(); } 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 (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 //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 / 100.); // bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.); } bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate; bayesStruct.updateBestEstimate(timeDifference); bayesStruct.lastBestEstimateUpdateTime = getTimeNow(timePlayed); // 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(); //having found matches we have matches for new note and matches for previous notes 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)); } /* 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)); } */ void midiEventHolder::updatePlayPosition(){ //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) timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime;//elpased - lastperiodupdatetime //this is time diff in milliseconds //then we have double quarterNoteIntervals = (timeDifference / period); tickLocation = quarterNoteIntervals * pulsesPerQuarternote; playPositionInMillis = timeDifference;//based on updating from when we change period //this to be added if (runningInRealTime) bayesStruct.updateBestEstimate(timeDifference); } 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(80,80,80);//250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate); ofSetColor(150,150,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]; // 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); } void midiEventHolder::drawFile(){ drawMidiFile(); // 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); */ } int midiEventHolder::getLocationFromTicks(double tickPosition){ return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); } 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(){ lastPeriodUpdateTime = getTimeNow(0);//ofGetElapsedTimeMillis(); startTime = lastPeriodUpdateTime; /* 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]); 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]); } } } 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; } } }