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