andrew@0: /* andrew@0: * BayesDrumTracker.cpp andrew@0: * bayesianTempoInitialiser5 andrew@0: * andrew@0: * Created by Andrew on 14/07/2011. andrew@0: * Copyright 2011 QMUL. All rights reserved. andrew@0: * andrew@0: */ andrew@0: andrew@0: #include "BayesDrumTracker.h" andrew@0: #define OUTPORT 12346 andrew@0: #define HOST "localhost" andrew@0: andrew@0: andrew@0: //beatCorrection process indicates how the phase is changing from max andrew@0: andrew@0: andrew@0: BayesDrumTracker::BayesDrumTracker(){ andrew@0: andrew@0: initialiseTracker(); andrew@0: sender.setup( HOST, OUTPORT ); andrew@0: } andrew@0: andrew@0: andrew@0: BayesDrumTracker::~BayesDrumTracker(){} andrew@0: andrew@0: void BayesDrumTracker::initialiseTracker(){ andrew@0: andrew@0: beatDistribution.initialiseArray(); andrew@0: tempoDistribution.initialiseArray(); andrew@0: beatTimes.lastBeatTime = 0; andrew@0: correctionFactor = 0.5; andrew@0: andrew@0: tempoDistribution.likelihoodStdDev = ARRAY_SIZE / 32; andrew@0: // tempoDistribution.likelihoodNoise = 0.96; andrew@0: tempoDistribution.likelihoodNoise = 0.7; andrew@0: tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1);//wide andrew@0: andrew@0: beatDistribution.likelihoodStdDev = ARRAY_SIZE / 32; andrew@0: beatDistribution.likelihoodNoise = 0.56; andrew@0: beatDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1); andrew@0: andrew@0: andrew@0: tempoMinimum = 180; andrew@0: tempoMaximum = 400; andrew@0: posteriorMaximum = 0.1; andrew@0: andrew@0: adaptiveStandardDeviationMode = false; andrew@0: setDistributionOnStartTempo = true; andrew@0: andrew@0: setBeatToNowTime = ofGetElapsedTimeMillis(); andrew@0: recentClickTime = ofGetElapsedTimeMillis(); andrew@0: andrew@0: resetParameters(); andrew@0: //check what we can delete above SINCE RESET CALLED andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::resetParameters(){ andrew@0: andrew@0: beatTimes.startIndex = 0; andrew@0: beatTimes.lastBeatTime = 0; andrew@0: maxPhase = 0; andrew@0: posteriorMaximum = 0.1; andrew@0: andrew@0: accompanimentStarted = false; andrew@0: andrew@0: tempoDistribution.likelihoodNoise = 0.8; andrew@0: tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/2);//wide andrew@0: andrew@0: beatDistribution.initialiseArray(); andrew@0: tempoDistribution.initialiseArray(); andrew@0: andrew@0: tempoDistribution.calculateStandardDeviation(); andrew@0: beatDistribution.calculateStandardDeviation(); andrew@0: andrew@0: tempoStdDev = tempoDistribution.standardDeviation; andrew@0: andrew@0: beatTimes.resetBeatTimeArray(); andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: andrew@0: void BayesDrumTracker::decayDistributions(){ andrew@0: andrew@0: if (accompanimentStarted){ andrew@0: tempoDistribution.decayPosteriorWithGaussianNoise (); andrew@0: beatDistribution.decayPosteriorWithGaussianNoise(); andrew@0: } andrew@0: else{ andrew@0: if (tempoStdDev < 0.8 && beatDistribution.standardDeviation < 5) andrew@0: accompanimentStarted = true; andrew@0: andrew@0: } andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::setBeatDistribution(int beatPosition){ andrew@0: switch (beatPosition){ andrew@0: //early sixteenth is that the beat is a sixteenth earlier andrew@0: case 0: andrew@0: case 1: andrew@0: case 11: andrew@0: //i.e. these zones are interpreted as "on the beat" andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0; andrew@0: beatDistribution.lateSixteenthNoteProportion = 0; andrew@0: break; andrew@0: //10 and 2 were here andrew@0: andrew@0: case 2: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 andrew@0: //i.e. a 25% chance it is early sixteenth - 75% that the beat actually lies here andrew@0: beatDistribution.lateSixteenthNoteProportion = 0; andrew@0: break; andrew@0: andrew@0: case 3: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0.3;//was 0.4 in Bayesian8 //half chance it is early andrew@0: beatDistribution.lateSixteenthNoteProportion = 0; andrew@0: break; andrew@0: andrew@0: case 5: andrew@0: case 6: andrew@0: case 7: andrew@0: beatDistribution.eighthNoteProportion = 0.3;//i.e. nearly half a chance we are on the 8th note andrew@0: beatDistribution.earlySixteenthNoteProportion = 0; andrew@0: beatDistribution.lateSixteenthNoteProportion = 0; andrew@0: break; andrew@0: andrew@0: case 4: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 andrew@0: beatDistribution.lateSixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 andrew@0: //chsanged to 0.2 and 0.1 then back andrew@0: break; andrew@0: andrew@0: case 8: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 andrew@0: beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 andrew@0: break; andrew@0: andrew@0: case 9: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0; andrew@0: beatDistribution.lateSixteenthNoteProportion = 0.35;//was 0.4 in Bayesian8 andrew@0: break; andrew@0: andrew@0: case 10: andrew@0: beatDistribution.eighthNoteProportion = 0; andrew@0: beatDistribution.earlySixteenthNoteProportion = 0; andrew@0: beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.2 in Bayesian8 andrew@0: break; andrew@0: andrew@0: } andrew@0: andrew@0: } andrew@0: andrew@0: void BayesDrumTracker::newKickError(const float& error, const double& cpuEventTime, const string& onsetTypeString){ andrew@0: andrew@0: onsetType = onsetTypeString; andrew@0: cpuBeatTime = cpuEventTime; andrew@0: kickError = error; andrew@0: andrew@0: //printf("beat errror %f time %f\n", kickError, cpuBeatTime); andrew@0: andrew@0: while (kickError > 0.5){ andrew@0: kickError -= 1; andrew@0: } andrew@0: andrew@0: if (paused != true){ andrew@0: updateTempoProcess(cpuBeatTime, onsetType); andrew@0: //this also cross updates the distributions andrew@0: beatTimes.beatMapTimeDifferences[beatTimes.beatSegment] = kickError*beatTimes.tatum; andrew@0: }//end if paused andrew@0: andrew@0: andrew@0: andrew@0: if (onsetType == "kick"){ andrew@0: if (accompanimentStarted) andrew@0: beatDistribution.likelihoodNoise = 0.5; andrew@0: else andrew@0: beatDistribution.likelihoodNoise = 0.5; andrew@0: // printf("kick %f ", cpuBeatTime); andrew@0: } andrew@0: else{ andrew@0: //snare andrew@0: if (accompanimentStarted) andrew@0: beatDistribution.likelihoodNoise = 0.7; andrew@0: else andrew@0: beatDistribution.likelihoodNoise = 0.85; andrew@0: // printf("snare %f ", cpuBeatTime); andrew@0: } andrew@0: andrew@0: andrew@0: setBeatDistribution(beatTimes.beatSegment%12); andrew@0: andrew@0: if (kickError <= 0.5 && kickError >= -0.5) andrew@0: { andrew@0: float beatStandardDeviation; andrew@0: if (adaptiveStandardDeviationMode) andrew@0: beatStandardDeviation = min((double)beatDistribution.likelihoodStdDev, beatDistribution.standardDeviation); andrew@0: else andrew@0: beatStandardDeviation = beatDistribution.likelihoodStdDev; andrew@0: andrew@0: andrew@0: beatDistribution.resetPrior(); andrew@0: beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(kickError*ARRAY_SIZE), beatStandardDeviation); andrew@0: beatDistribution.calculatePosterior(); andrew@0: beatDistribution.renormalisePosterior(); andrew@0: andrew@0: sendMaxPhase(); andrew@0: andrew@0: beatDistribution.calculateStandardDeviation(); andrew@0: andrew@0: }//end if error < 0.5 andrew@0: andrew@0: andrew@0: andrew@0: if (beatTimes.beatSegment % 12 == 6){ andrew@0: kickString = "Kick "; andrew@0: kickString += ofToString(kickError); andrew@0: kickString += " ERROR "; andrew@0: kickString += ofToString(kickError, 2); andrew@0: kickString += " at time diff "; andrew@0: kickString += ofToString(cpuBeatTime - beatTimes.lastClickTime, 2); andrew@0: kickString += " index "; andrew@0: kickString += ofToString(beatTimes.lastClickIndex, 2); andrew@0: kickString += " TYPE "; andrew@0: kickString += ofToString(beatTimes.beatSegment%12); andrew@0: kickString += " Time diff "; andrew@0: kickString += ofToString(beatTimes.timeDifference, 2); andrew@0: } andrew@0: andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: andrew@0: void BayesDrumTracker::startTatum(const float& startTatum){ andrew@0: beatTimes.tatum = startTatum; andrew@0: andrew@0: if (setDistributionOnStartTempo){ andrew@0: beatDistribution.setGaussianPosterior(ARRAY_SIZE/2, 8); andrew@0: tempoDistribution.setGaussianPosterior(ARRAY_SIZE/2, 12); andrew@0: float tmpIndex; andrew@0: tmpIndex = ( (beatTimes.tatum - ((tempoMinimum+tempoMaximum)/2) ) * ARRAY_SIZE)/(tempoMaximum - tempoMinimum); andrew@0: tempoDistribution.translateDistribution(tmpIndex); andrew@0: andrew@0: sendMaxTempo(); andrew@0: } andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::setUniformTempo(){ andrew@0: for (int i = 0;i < ARRAY_SIZE;i++) andrew@0: tempoDistribution.posterior[i] = (float)1/ARRAY_SIZE; andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::setUniformPhase(){ andrew@0: for (int i = 0;i < ARRAY_SIZE;i++) andrew@0: beatDistribution.posterior[i] = (float)1/ARRAY_SIZE; andrew@0: } andrew@0: andrew@0: void BayesDrumTracker::setBeatNow(const double& beatTime){ andrew@0: for (int i = 0;i < ARRAY_SIZE;i++) andrew@0: beatDistribution.prior[i] = (float)1/ARRAY_SIZE; andrew@0: andrew@0: setBeatToNowTime = ofGetElapsedTimeMillis(); andrew@0: double difference = (setBeatToNowTime - recentClickTime); andrew@0: printf("SET BEAT TO NOW %f vs %f :: diff %f tatum %f :: ", setBeatToNowTime, recentClickTime, difference, beatTimes.tatum ); andrew@0: andrew@0: double beatTimeToUse = 0; andrew@0: andrew@0: if (difference < beatTimes.tatum)//tatum is the eighth note time andrew@0: beatTimeToUse = difference/ (2*beatTimes.tatum); andrew@0: else andrew@0: beatTimeToUse = -1*(2*beatTimes.tatum - difference) / (2*beatTimes.tatum); andrew@0: andrew@0: printf("sending %f \n", beatTimeToUse); andrew@0: andrew@0: beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(beatTimeToUse*ARRAY_SIZE), 2); andrew@0: beatDistribution.calculatePosterior(); andrew@0: beatDistribution.renormalisePosterior(); andrew@0: andrew@0: sendMaxPhase(); andrew@0: andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::newBeat(int& beatIndex){ andrew@0: ofxOscMessage m; andrew@0: m.setAddress( "/beatInfo" ); andrew@0: andrew@0: m.addFloatArg(beatTimes.tatum); andrew@0: m.addFloatArg(maxPhase); andrew@0: andrew@0: beatTimes.tatum = maxTempo; andrew@0: printf("BEAT INFO %f, %f\n", beatTimes.tatum, maxPhase); andrew@0: andrew@0: sender.sendMessage( m ); andrew@0: andrew@0: } andrew@0: andrew@0: void BayesDrumTracker::sendMaxTempo(){ andrew@0: ofxOscMessage m; andrew@0: m.setAddress( "/tempo" ); andrew@0: andrew@0: //maxTempo = tempoDistribution.maximumIndex * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; andrew@0: //would be introduced new in bayesian8 andrew@0: maxTempo = tempoDistribution.getIntegratedEstimateIndex() * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; andrew@0: maxTempo += tempoMinimum; andrew@0: andrew@0: beatTimes.tatum = maxTempo; andrew@0: printf("SEND TATUM %f\n", beatTimes.tatum); andrew@0: andrew@0: m.addFloatArg( maxTempo ); andrew@0: sender.sendMessage( m ); andrew@0: andrew@0: //printf("max tempo %f\n", maxTempo); andrew@0: andrew@0: } andrew@0: andrew@0: void BayesDrumTracker::sendMaxPhase(){ andrew@0: andrew@0: andrew@0: // maxPhase = (beatDistribution.maximumIndex - (ARRAY_SIZE/2)) / ARRAY_SIZE; andrew@0: maxPhase = (beatDistribution.getIntegratedEstimateIndex() - (ARRAY_SIZE/2)) / ARRAY_SIZE; andrew@0: // printf("\nphase index %f :: %f\n", (float) beatDistribution.integratedEstimate , maxPhase); andrew@0: ofxOscMessage m; andrew@0: m.setAddress( "/phase" ); andrew@0: m.addFloatArg( maxPhase ); andrew@0: sender.sendMessage( m ); andrew@0: andrew@0: //beatCorrection = maxPhase * beatTimes.tatum / 4; andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::setNewClickIndex(const int& clickIndex, const float& clickTime){ andrew@0: andrew@0: beatTimes.lastClickIndex = clickIndex; andrew@0: beatTimes.lastClickTime = clickTime; andrew@0: andrew@0: int clickIndexToUse = clickIndex % 16; andrew@0: beatTimes.clickIndex = clickIndex; andrew@0: beatTimes.clickNumber[clickIndexToUse] = clickIndex; andrew@0: beatTimes.clickTimes[clickIndexToUse] = clickTime; andrew@0: andrew@0: recentClickTime = ofGetElapsedTimeMillis(); andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::doBeatCorrection(const float& beatCorrFloat){ andrew@0: beatCorrection = beatCorrFloat; andrew@0: correctBeatBy = round(correctionFactor * beatCorrection * ARRAY_SIZE / (2 * beatTimes.tatum)); andrew@0: beatDistribution.translateDistribution(-1 * correctBeatBy); andrew@0: } andrew@0: andrew@0: andrew@0: bool BayesDrumTracker::filterBeatTime(double newBeatTime){ andrew@0: bool newBeatFound = false; andrew@0: if ((newBeatTime - beatTimes.lastBeatTime) > 20 || beatTimes.lastBeatTime == 0){ andrew@0: andrew@0: crossUpdateArrays((float)(newBeatTime - beatTimes.lastBeatTime)); andrew@0: beatTimes.lastBeatTime = newBeatTime; andrew@0: newBeatFound = true; andrew@0: } andrew@0: return newBeatFound; andrew@0: } andrew@0: andrew@0: void BayesDrumTracker::crossUpdateArrays(float timeInterval){ andrew@0: andrew@0: int finalBeatIndex, tmpTempoIndex, startBeatIndex; andrew@0: //finalBeat has contribution from BEAT[finalBeat + INT.k] * TEMPO[Max_tempo + k] where INT = INTERVAL andrew@0: float interval; andrew@0: interval = timeInterval / maxTempo;//beatTimes.tatum; andrew@0: tempoDistribution.resetMaximumPosterior(); andrew@0: beatDistribution.resetMaximumPosterior(); andrew@0: andrew@0: andrew@0: int tmpBeatIndex; andrew@0: //&& interval > 0.8 idea? andrew@0: if (timeInterval > 0 && timeInterval < 12000 ){//need between 0 and 12 seconds only to update andrew@0: andrew@0: for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ andrew@0: andrew@0: tmpArray[tmpBeatIndex] = 0; andrew@0: float minusMsecToMakeUp = beatIndexToMsec(tmpBeatIndex) / interval; andrew@0: float plusMsecToMakeUp = beatIndexToMsec(ARRAY_SIZE - tmpBeatIndex) / interval; andrew@0: float convertMsecToTempoIndex = ARRAY_SIZE / (tempoMaximum - tempoMinimum) ; andrew@0: andrew@0: andrew@0: int minTempoIndex = -1 * (int)(minusMsecToMakeUp * convertMsecToTempoIndex); andrew@0: int maxTempoIndex = (int)(plusMsecToMakeUp * convertMsecToTempoIndex); andrew@0: andrew@0: andrew@0: if (tmpBeatIndex == beatDistribution.maximumIndex){ andrew@0: // minTmpDebug = tempoDistribution.maximumIndex + minTempoIndex; andrew@0: // maxTmpDebug = tempoDistribution.maximumIndex + maxTempoIndex; andrew@0: debugArray[0] = beatDistribution.maximumIndex;// andrew@0: debugArray[1] = timeInterval; andrew@0: debugArray[2] = interval;//beatDistribution.maximumIndex; andrew@0: debugArray[3] = tempoDistribution.maximumIndex; andrew@0: } andrew@0: andrew@0: for (tmpTempoIndex = minTempoIndex;tmpTempoIndex <= maxTempoIndex;tmpTempoIndex++){ andrew@0: andrew@0: if ((tempoDistribution.maximumIndex + tmpTempoIndex) >= 0 andrew@0: && (tempoDistribution.maximumIndex + tmpTempoIndex) < ARRAY_SIZE andrew@0: && (tmpBeatIndex - (int)(interval*tmpTempoIndex)) >= 0 andrew@0: && (tmpBeatIndex - (int)(interval*tmpTempoIndex))< ARRAY_SIZE){ andrew@0: tmpArray[tmpBeatIndex] += beatDistribution.posterior[tmpBeatIndex - (int)(interval*tmpTempoIndex)] * tempoDistribution.posterior[(int)tempoDistribution.maximumIndex + tmpTempoIndex]; andrew@0: } andrew@0: }//end for tmpTmepo andrew@0: andrew@0: andrew@0: andrew@0: } andrew@0: andrew@0: float tmpFloat; andrew@0: for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ andrew@0: //debug - dont actually update:: andrew@0: andrew@0: tmpFloat = beatDistribution.posterior[tmpBeatIndex]; andrew@0: beatDistribution.posterior[tmpBeatIndex] = tmpArray[tmpBeatIndex]; andrew@0: tmpArray[tmpBeatIndex] = tmpFloat; andrew@0: } andrew@0: beatDistribution.renormaliseArray(&beatDistribution.posterior[0], ARRAY_SIZE); andrew@0: andrew@0: } //end if andrew@0: andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::updateTempoProcess(const double& cpuTime, const string& onsetDescription){ andrew@0: andrew@0: if (filterBeatTime(cpuTime) == true){ andrew@0: //checks for no repeat andrew@0: andrew@0: if (onsetDescription == "kick") andrew@0: beatTimes.addBeatTime(cpuTime, 1); andrew@0: else andrew@0: beatTimes.addBeatTime(cpuTime, 2); andrew@0: andrew@0: andrew@0: //recalculate the distribution andrew@0: int altIndex = 0; andrew@0: andrew@0: tempoDataString = "Tatum :"; andrew@0: tempoDataString += ofToString(beatTimes.tatum, 2); andrew@0: tempoDataString += " BPM "; andrew@0: tempoDataString += ofToString((double)30000/beatTimes.tatum, 2); andrew@0: andrew@0: timeString = "Last BEAT "; andrew@0: timeString += ofToString(beatTimes.lastBeatTime); andrew@0: timeString += " CLICK "; andrew@0: timeString += ofToString(beatTimes.lastClickTime); andrew@0: timeString += " DIFDF "; andrew@0: timeString += ofToString(beatTimes.timeDifference); andrew@0: timeString += " segment "; andrew@0: timeString += ofToString(beatTimes.beatSegment); andrew@0: andrew@0: andrew@0: for (altIndex = 0;altIndex< 16;altIndex++){ andrew@0: tempoInterval = beatTimes.intervalDifferences[beatTimes.index][altIndex]; andrew@0: integerMultipleOfTatum = beatTimes.relativeIntervals[altIndex][1]; andrew@0: andrew@0: andrew@0: ///NEW VERSION andrew@0: tempoUpdateStrings[altIndex] = ""; andrew@0: double timeInterval = beatTimes.beatTimes[beatTimes.index] - beatTimes.beatTimes[altIndex]; andrew@0: //raw time difference andrew@0: beatTimes.intervalDifferences[beatTimes.index][altIndex] = 0; andrew@0: beatTimes.intervalUsed[beatTimes.index][altIndex] = false; andrew@0: andrew@0: if (onsetType == "kick") andrew@0: beatTimes.OnsetIsKick[beatTimes.index] = true; andrew@0: else andrew@0: beatTimes.OnsetIsKick[beatTimes.index] = false; andrew@0: andrew@0: andrew@0: andrew@0: if (!accompanimentStarted){ andrew@0: //if we need to find tempo and start use this method andrew@0: //we have 'started' once std dev is sufficiently low andrew@0: andrew@0: updateTempoIfWithinRange(timeInterval);//taken as being the tatum interval andrew@0: andrew@0: andrew@0: andrew@0: for (int i = 1;i <= 4;i++){ andrew@0: //we test the main beats and the two bar (16 tatum intervals) andrew@0: andrew@0: double testInterval = timeInterval / 2*i;//pow(2, i);//pow(2.0, i); andrew@0: andrew@0: if (updateTempoIfWithinRange(testInterval)){ andrew@0: //printf("test time %f, beats %i\n", testInterval, i); andrew@0: andrew@0: beatTimes.intervalUsed[beatTimes.index][altIndex] = true; andrew@0: beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; andrew@0: //xx what if two within range here? andrew@0: andrew@0: tempoUpdateStrings[altIndex] = "Tempo Updates ("; andrew@0: tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); andrew@0: tempoUpdateStrings[altIndex] += ") : ["; andrew@0: tempoUpdateStrings[altIndex] += ofToString(altIndex); andrew@0: tempoUpdateStrings[altIndex] += "]] : "; andrew@0: tempoUpdateStrings[altIndex] += ofToString(timeInterval); andrew@0: tempoUpdateStrings[altIndex] += ", ioi:"; andrew@0: tempoUpdateStrings[altIndex] += ofToString(i); andrew@0: //tempoUpdateStrings[altIndex] += ""; andrew@0: andrew@0: } andrew@0: andrew@0: } andrew@0: andrew@0: double testInterval = timeInterval / 16;//pow(2, i);//pow(2.0, i); andrew@0: if (updateTempoIfWithinRange(testInterval)){ andrew@0: beatTimes.intervalUsed[beatTimes.index][altIndex] = true; andrew@0: beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; andrew@0: } andrew@0: andrew@0: }else{ andrew@0: //OLD VERSON andrew@0: //THIS USES THE CURRENT TEMPO ESTIMATE TO DECIDE WHAT THE BEST INTERVAL IS andrew@0: //&& integerMultipleOfTatum % 2 == 0 removed below XXX put back andrew@0: if (altIndex != beatTimes.index && integerMultipleOfTatum < 17 andrew@0: && integerMultipleOfTatum > 0 && beatTimes.startIndex > 8//beattimes.index > 8 - the start andrew@0: && integerMultipleOfTatum%2 == 0){//mod 2 - i.e. proper beat intervals only andrew@0: andrew@0: double testInterval = timeInterval / integerMultipleOfTatum; andrew@0: andrew@0: if (updateTempoIfWithinRange(testInterval)){ andrew@0: andrew@0: beatTimes.intervalUsed[beatTimes.index][altIndex] = true; andrew@0: beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; andrew@0: andrew@0: if (paused == false){ andrew@0: tempoUpdateStrings[altIndex] = "Tempo Updates : ("; andrew@0: tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); andrew@0: tempoUpdateStrings[altIndex] += ") : ["; andrew@0: tempoUpdateStrings[altIndex] += ofToString(altIndex, 0); andrew@0: tempoUpdateStrings[altIndex] += "] :: "; andrew@0: tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); andrew@0: tempoUpdateStrings[altIndex] += " intervals :: "; andrew@0: tempoUpdateStrings[altIndex] += ofToString(tempoInterval); andrew@0: tempoUpdateStrings[altIndex] += " ms."; andrew@0: // tempoUpdateStrings[altIndex] += ", ioi:"; andrew@0: andrew@0: // tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); andrew@0: andrew@0: andrew@0: andrew@0: andrew@0: }//end if not paused andrew@0: andrew@0: andrew@0: }//end if good interval to update andrew@0: andrew@0: }//end if not same index etc andrew@0: andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: andrew@0: }//end for all intervals andrew@0: andrew@0: sendMaxTempo(); andrew@0: }//end if new beat time andrew@0: double tempoEstimate = tempoDistribution.getIntegratedEstimateIndex(); andrew@0: tempoDistribution.calculateStandardDeviation(); andrew@0: tempoStdDev = tempoDistribution.standardDeviation; andrew@0: andrew@0: } andrew@0: andrew@0: andrew@0: bool BayesDrumTracker::updateTempoIfWithinRange(double timeInterval){ andrew@0: andrew@0: bool updated = false; andrew@0: andrew@0: if (timeInterval > tempoMinimum && timeInterval < tempoMaximum ){ andrew@0: calculateTempoUpdate(timeInterval); andrew@0: updated = true; andrew@0: } andrew@0: andrew@0: return updated; andrew@0: } andrew@0: andrew@0: andrew@0: void BayesDrumTracker::calculateTempoUpdate(double tempoInterval){ andrew@0: andrew@0: andrew@0: tempoDistribution.resetPrior(); andrew@0: //need to relook at likelihood for the tempo distribution - not the same as.... andrew@0: tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval-tempoMinimum)/(tempoMaximum - tempoMinimum), tempoDistribution.likelihoodStdDev); andrew@0: tempoDistribution.calculatePosterior(); andrew@0: tempoDistribution.renormalisePosterior(); andrew@0: andrew@0: //did take pic of screen here - see initialiser4 andrew@0: } andrew@0: andrew@0: andrew@0: float BayesDrumTracker::tempoIndexToMsec(const int& index){ andrew@0: float msec; andrew@0: msec = index * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; andrew@0: msec += tempoMinimum; andrew@0: return msec; andrew@0: } andrew@0: andrew@0: float BayesDrumTracker::beatIndexToMsec(const int& index){ andrew@0: float msec; andrew@0: msec = index * maxTempo / ARRAY_SIZE; andrew@0: msec += tempoMinimum; andrew@0: return msec; andrew@0: } andrew@0: