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