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