# HG changeset patch # User Andrew N Robertson # Date 1314731795 -3600 # Node ID 0f9165f96bdb16c0b993d5d16db32d536d73e2a1 started drum tracker project svn diff -r 000000000000 -r 0f9165f96bdb .DS_Store Binary file .DS_Store has changed diff -r 000000000000 -r 0f9165f96bdb src/BayesDrumTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/BayesDrumTracker.cpp Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,625 @@ +/* + * BayesDrumTracker.cpp + * bayesianTempoInitialiser5 + * + * Created by Andrew on 14/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "BayesDrumTracker.h" +#define OUTPORT 12346 +#define HOST "localhost" + + +//beatCorrection process indicates how the phase is changing from max + + +BayesDrumTracker::BayesDrumTracker(){ + + initialiseTracker(); + sender.setup( HOST, OUTPORT ); +} + + +BayesDrumTracker::~BayesDrumTracker(){} + +void BayesDrumTracker::initialiseTracker(){ + + beatDistribution.initialiseArray(); + tempoDistribution.initialiseArray(); + beatTimes.lastBeatTime = 0; + correctionFactor = 0.5; + + tempoDistribution.likelihoodStdDev = ARRAY_SIZE / 32; + // tempoDistribution.likelihoodNoise = 0.96; + tempoDistribution.likelihoodNoise = 0.7; + tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1);//wide + + beatDistribution.likelihoodStdDev = ARRAY_SIZE / 32; + beatDistribution.likelihoodNoise = 0.56; + beatDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1); + + + tempoMinimum = 180; + tempoMaximum = 400; + posteriorMaximum = 0.1; + + adaptiveStandardDeviationMode = false; + setDistributionOnStartTempo = true; + + setBeatToNowTime = ofGetElapsedTimeMillis(); + recentClickTime = ofGetElapsedTimeMillis(); + + resetParameters(); + //check what we can delete above SINCE RESET CALLED + +} + + +void BayesDrumTracker::resetParameters(){ + + beatTimes.startIndex = 0; + beatTimes.lastBeatTime = 0; + maxPhase = 0; + posteriorMaximum = 0.1; + + accompanimentStarted = false; + + tempoDistribution.likelihoodNoise = 0.8; + tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/2);//wide + + beatDistribution.initialiseArray(); + tempoDistribution.initialiseArray(); + + tempoDistribution.calculateStandardDeviation(); + beatDistribution.calculateStandardDeviation(); + + tempoStdDev = tempoDistribution.standardDeviation; + + beatTimes.resetBeatTimeArray(); + +} + + + +void BayesDrumTracker::decayDistributions(){ + + if (accompanimentStarted){ + tempoDistribution.decayPosteriorWithGaussianNoise (); + beatDistribution.decayPosteriorWithGaussianNoise(); + } + else{ + if (tempoStdDev < 0.8 && beatDistribution.standardDeviation < 5) + accompanimentStarted = true; + + } +} + + +void BayesDrumTracker::setBeatDistribution(int beatPosition){ + switch (beatPosition){ + //early sixteenth is that the beat is a sixteenth earlier + case 0: + case 1: + case 11: + //i.e. these zones are interpreted as "on the beat" + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0; + break; + //10 and 2 were here + + case 2: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + //i.e. a 25% chance it is early sixteenth - 75% that the beat actually lies here + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 3: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.3;//was 0.4 in Bayesian8 //half chance it is early + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 5: + case 6: + case 7: + beatDistribution.eighthNoteProportion = 0.3;//i.e. nearly half a chance we are on the 8th note + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 4: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + beatDistribution.lateSixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 + //chsanged to 0.2 and 0.1 then back + break; + + case 8: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 + beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + break; + + case 9: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0.35;//was 0.4 in Bayesian8 + break; + + case 10: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.2 in Bayesian8 + break; + + } + +} + +void BayesDrumTracker::newKickError(const float& error, const double& cpuEventTime, const string& onsetTypeString){ + + onsetType = onsetTypeString; + cpuBeatTime = cpuEventTime; + kickError = error; + + //printf("beat errror %f time %f\n", kickError, cpuBeatTime); + + while (kickError > 0.5){ + kickError -= 1; + } + + if (paused != true){ + updateTempoProcess(cpuBeatTime, onsetType); + //this also cross updates the distributions + beatTimes.beatMapTimeDifferences[beatTimes.beatSegment] = kickError*beatTimes.tatum; + }//end if paused + + + + if (onsetType == "kick"){ + if (accompanimentStarted) + beatDistribution.likelihoodNoise = 0.5; + else + beatDistribution.likelihoodNoise = 0.5; + // printf("kick %f ", cpuBeatTime); + } + else{ + //snare + if (accompanimentStarted) + beatDistribution.likelihoodNoise = 0.7; + else + beatDistribution.likelihoodNoise = 0.85; + // printf("snare %f ", cpuBeatTime); + } + + + setBeatDistribution(beatTimes.beatSegment%12); + + if (kickError <= 0.5 && kickError >= -0.5) + { + float beatStandardDeviation; + if (adaptiveStandardDeviationMode) + beatStandardDeviation = min((double)beatDistribution.likelihoodStdDev, beatDistribution.standardDeviation); + else + beatStandardDeviation = beatDistribution.likelihoodStdDev; + + + beatDistribution.resetPrior(); + beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(kickError*ARRAY_SIZE), beatStandardDeviation); + beatDistribution.calculatePosterior(); + beatDistribution.renormalisePosterior(); + + sendMaxPhase(); + + beatDistribution.calculateStandardDeviation(); + + }//end if error < 0.5 + + + + if (beatTimes.beatSegment % 12 == 6){ + kickString = "Kick "; + kickString += ofToString(kickError); + kickString += " ERROR "; + kickString += ofToString(kickError, 2); + kickString += " at time diff "; + kickString += ofToString(cpuBeatTime - beatTimes.lastClickTime, 2); + kickString += " index "; + kickString += ofToString(beatTimes.lastClickIndex, 2); + kickString += " TYPE "; + kickString += ofToString(beatTimes.beatSegment%12); + kickString += " Time diff "; + kickString += ofToString(beatTimes.timeDifference, 2); + } + + +} + + + +void BayesDrumTracker::startTatum(const float& startTatum){ + beatTimes.tatum = startTatum; + + if (setDistributionOnStartTempo){ + beatDistribution.setGaussianPosterior(ARRAY_SIZE/2, 8); + tempoDistribution.setGaussianPosterior(ARRAY_SIZE/2, 12); + float tmpIndex; + tmpIndex = ( (beatTimes.tatum - ((tempoMinimum+tempoMaximum)/2) ) * ARRAY_SIZE)/(tempoMaximum - tempoMinimum); + tempoDistribution.translateDistribution(tmpIndex); + + sendMaxTempo(); + } +} + + +void BayesDrumTracker::setUniformTempo(){ + for (int i = 0;i < ARRAY_SIZE;i++) + tempoDistribution.posterior[i] = (float)1/ARRAY_SIZE; +} + + +void BayesDrumTracker::setUniformPhase(){ + for (int i = 0;i < ARRAY_SIZE;i++) + beatDistribution.posterior[i] = (float)1/ARRAY_SIZE; +} + +void BayesDrumTracker::setBeatNow(const double& beatTime){ + for (int i = 0;i < ARRAY_SIZE;i++) + beatDistribution.prior[i] = (float)1/ARRAY_SIZE; + + setBeatToNowTime = ofGetElapsedTimeMillis(); + double difference = (setBeatToNowTime - recentClickTime); + printf("SET BEAT TO NOW %f vs %f :: diff %f tatum %f :: ", setBeatToNowTime, recentClickTime, difference, beatTimes.tatum ); + + double beatTimeToUse = 0; + + if (difference < beatTimes.tatum)//tatum is the eighth note time + beatTimeToUse = difference/ (2*beatTimes.tatum); + else + beatTimeToUse = -1*(2*beatTimes.tatum - difference) / (2*beatTimes.tatum); + + printf("sending %f \n", beatTimeToUse); + + beatDistribution.setGaussianLikelihoodForBeats((ARRAY_SIZE/2)+(beatTimeToUse*ARRAY_SIZE), 2); + beatDistribution.calculatePosterior(); + beatDistribution.renormalisePosterior(); + + sendMaxPhase(); + + +} + + +void BayesDrumTracker::newBeat(int& beatIndex){ + ofxOscMessage m; + m.setAddress( "/beatInfo" ); + + m.addFloatArg(beatTimes.tatum); + m.addFloatArg(maxPhase); + + beatTimes.tatum = maxTempo; + printf("BEAT INFO %f, %f\n", beatTimes.tatum, maxPhase); + + sender.sendMessage( m ); + +} + +void BayesDrumTracker::sendMaxTempo(){ + ofxOscMessage m; + m.setAddress( "/tempo" ); + + //maxTempo = tempoDistribution.maximumIndex * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; + //would be introduced new in bayesian8 + maxTempo = tempoDistribution.getIntegratedEstimateIndex() * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; + maxTempo += tempoMinimum; + + beatTimes.tatum = maxTempo; + printf("SEND TATUM %f\n", beatTimes.tatum); + + m.addFloatArg( maxTempo ); + sender.sendMessage( m ); + + //printf("max tempo %f\n", maxTempo); + +} + +void BayesDrumTracker::sendMaxPhase(){ + + + // maxPhase = (beatDistribution.maximumIndex - (ARRAY_SIZE/2)) / ARRAY_SIZE; + maxPhase = (beatDistribution.getIntegratedEstimateIndex() - (ARRAY_SIZE/2)) / ARRAY_SIZE; +// printf("\nphase index %f :: %f\n", (float) beatDistribution.integratedEstimate , maxPhase); + ofxOscMessage m; + m.setAddress( "/phase" ); + m.addFloatArg( maxPhase ); + sender.sendMessage( m ); + + //beatCorrection = maxPhase * beatTimes.tatum / 4; +} + + +void BayesDrumTracker::setNewClickIndex(const int& clickIndex, const float& clickTime){ + + beatTimes.lastClickIndex = clickIndex; + beatTimes.lastClickTime = clickTime; + + int clickIndexToUse = clickIndex % 16; + beatTimes.clickIndex = clickIndex; + beatTimes.clickNumber[clickIndexToUse] = clickIndex; + beatTimes.clickTimes[clickIndexToUse] = clickTime; + + recentClickTime = ofGetElapsedTimeMillis(); + +} + + +void BayesDrumTracker::doBeatCorrection(const float& beatCorrFloat){ + beatCorrection = beatCorrFloat; + correctBeatBy = round(correctionFactor * beatCorrection * ARRAY_SIZE / (2 * beatTimes.tatum)); + beatDistribution.translateDistribution(-1 * correctBeatBy); +} + + +bool BayesDrumTracker::filterBeatTime(double newBeatTime){ + bool newBeatFound = false; + if ((newBeatTime - beatTimes.lastBeatTime) > 20 || beatTimes.lastBeatTime == 0){ + + crossUpdateArrays((float)(newBeatTime - beatTimes.lastBeatTime)); + beatTimes.lastBeatTime = newBeatTime; + newBeatFound = true; + } + return newBeatFound; +} + +void BayesDrumTracker::crossUpdateArrays(float timeInterval){ + + int finalBeatIndex, tmpTempoIndex, startBeatIndex; + //finalBeat has contribution from BEAT[finalBeat + INT.k] * TEMPO[Max_tempo + k] where INT = INTERVAL + float interval; + interval = timeInterval / maxTempo;//beatTimes.tatum; + tempoDistribution.resetMaximumPosterior(); + beatDistribution.resetMaximumPosterior(); + + + int tmpBeatIndex; + //&& interval > 0.8 idea? + if (timeInterval > 0 && timeInterval < 12000 ){//need between 0 and 12 seconds only to update + + for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ + + tmpArray[tmpBeatIndex] = 0; + float minusMsecToMakeUp = beatIndexToMsec(tmpBeatIndex) / interval; + float plusMsecToMakeUp = beatIndexToMsec(ARRAY_SIZE - tmpBeatIndex) / interval; + float convertMsecToTempoIndex = ARRAY_SIZE / (tempoMaximum - tempoMinimum) ; + + + int minTempoIndex = -1 * (int)(minusMsecToMakeUp * convertMsecToTempoIndex); + int maxTempoIndex = (int)(plusMsecToMakeUp * convertMsecToTempoIndex); + + + if (tmpBeatIndex == beatDistribution.maximumIndex){ + // minTmpDebug = tempoDistribution.maximumIndex + minTempoIndex; + // maxTmpDebug = tempoDistribution.maximumIndex + maxTempoIndex; + debugArray[0] = beatDistribution.maximumIndex;// + debugArray[1] = timeInterval; + debugArray[2] = interval;//beatDistribution.maximumIndex; + debugArray[3] = tempoDistribution.maximumIndex; + } + + for (tmpTempoIndex = minTempoIndex;tmpTempoIndex <= maxTempoIndex;tmpTempoIndex++){ + + if ((tempoDistribution.maximumIndex + tmpTempoIndex) >= 0 + && (tempoDistribution.maximumIndex + tmpTempoIndex) < ARRAY_SIZE + && (tmpBeatIndex - (int)(interval*tmpTempoIndex)) >= 0 + && (tmpBeatIndex - (int)(interval*tmpTempoIndex))< ARRAY_SIZE){ + tmpArray[tmpBeatIndex] += beatDistribution.posterior[tmpBeatIndex - (int)(interval*tmpTempoIndex)] * tempoDistribution.posterior[(int)tempoDistribution.maximumIndex + tmpTempoIndex]; + } + }//end for tmpTmepo + + + + } + + float tmpFloat; + for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ + //debug - dont actually update:: + + tmpFloat = beatDistribution.posterior[tmpBeatIndex]; + beatDistribution.posterior[tmpBeatIndex] = tmpArray[tmpBeatIndex]; + tmpArray[tmpBeatIndex] = tmpFloat; + } + beatDistribution.renormaliseArray(&beatDistribution.posterior[0], ARRAY_SIZE); + + } //end if + + +} + + +void BayesDrumTracker::updateTempoProcess(const double& cpuTime, const string& onsetDescription){ + + if (filterBeatTime(cpuTime) == true){ + //checks for no repeat + + if (onsetDescription == "kick") + beatTimes.addBeatTime(cpuTime, 1); + else + beatTimes.addBeatTime(cpuTime, 2); + + + //recalculate the distribution + int altIndex = 0; + + tempoDataString = "Tatum :"; + tempoDataString += ofToString(beatTimes.tatum, 2); + tempoDataString += " BPM "; + tempoDataString += ofToString((double)30000/beatTimes.tatum, 2); + + timeString = "Last BEAT "; + timeString += ofToString(beatTimes.lastBeatTime); + timeString += " CLICK "; + timeString += ofToString(beatTimes.lastClickTime); + timeString += " DIFDF "; + timeString += ofToString(beatTimes.timeDifference); + timeString += " segment "; + timeString += ofToString(beatTimes.beatSegment); + + + for (altIndex = 0;altIndex< 16;altIndex++){ + tempoInterval = beatTimes.intervalDifferences[beatTimes.index][altIndex]; + integerMultipleOfTatum = beatTimes.relativeIntervals[altIndex][1]; + + + ///NEW VERSION + tempoUpdateStrings[altIndex] = ""; + double timeInterval = beatTimes.beatTimes[beatTimes.index] - beatTimes.beatTimes[altIndex]; + //raw time difference + beatTimes.intervalDifferences[beatTimes.index][altIndex] = 0; + beatTimes.intervalUsed[beatTimes.index][altIndex] = false; + + if (onsetType == "kick") + beatTimes.OnsetIsKick[beatTimes.index] = true; + else + beatTimes.OnsetIsKick[beatTimes.index] = false; + + + + if (!accompanimentStarted){ + //if we need to find tempo and start use this method + //we have 'started' once std dev is sufficiently low + + updateTempoIfWithinRange(timeInterval);//taken as being the tatum interval + + + + for (int i = 1;i <= 4;i++){ + //we test the main beats and the two bar (16 tatum intervals) + + double testInterval = timeInterval / 2*i;//pow(2, i);//pow(2.0, i); + + if (updateTempoIfWithinRange(testInterval)){ + //printf("test time %f, beats %i\n", testInterval, i); + + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + //xx what if two within range here? + + tempoUpdateStrings[altIndex] = "Tempo Updates ("; + tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); + tempoUpdateStrings[altIndex] += ") : ["; + tempoUpdateStrings[altIndex] += ofToString(altIndex); + tempoUpdateStrings[altIndex] += "]] : "; + tempoUpdateStrings[altIndex] += ofToString(timeInterval); + tempoUpdateStrings[altIndex] += ", ioi:"; + tempoUpdateStrings[altIndex] += ofToString(i); + //tempoUpdateStrings[altIndex] += ""; + + } + + } + + double testInterval = timeInterval / 16;//pow(2, i);//pow(2.0, i); + if (updateTempoIfWithinRange(testInterval)){ + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + } + + }else{ + //OLD VERSON + //THIS USES THE CURRENT TEMPO ESTIMATE TO DECIDE WHAT THE BEST INTERVAL IS + //&& integerMultipleOfTatum % 2 == 0 removed below XXX put back + if (altIndex != beatTimes.index && integerMultipleOfTatum < 17 + && integerMultipleOfTatum > 0 && beatTimes.startIndex > 8//beattimes.index > 8 - the start + && integerMultipleOfTatum%2 == 0){//mod 2 - i.e. proper beat intervals only + + double testInterval = timeInterval / integerMultipleOfTatum; + + if (updateTempoIfWithinRange(testInterval)){ + + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + + if (paused == false){ + tempoUpdateStrings[altIndex] = "Tempo Updates : ("; + tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); + tempoUpdateStrings[altIndex] += ") : ["; + tempoUpdateStrings[altIndex] += ofToString(altIndex, 0); + tempoUpdateStrings[altIndex] += "] :: "; + tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); + tempoUpdateStrings[altIndex] += " intervals :: "; + tempoUpdateStrings[altIndex] += ofToString(tempoInterval); + tempoUpdateStrings[altIndex] += " ms."; + // tempoUpdateStrings[altIndex] += ", ioi:"; + + // tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); + + + + + }//end if not paused + + + }//end if good interval to update + + }//end if not same index etc + + + } + + + + }//end for all intervals + + sendMaxTempo(); + }//end if new beat time + double tempoEstimate = tempoDistribution.getIntegratedEstimateIndex(); + tempoDistribution.calculateStandardDeviation(); + tempoStdDev = tempoDistribution.standardDeviation; + +} + + +bool BayesDrumTracker::updateTempoIfWithinRange(double timeInterval){ + + bool updated = false; + + if (timeInterval > tempoMinimum && timeInterval < tempoMaximum ){ + calculateTempoUpdate(timeInterval); + updated = true; + } + + return updated; +} + + +void BayesDrumTracker::calculateTempoUpdate(double tempoInterval){ + + + tempoDistribution.resetPrior(); + //need to relook at likelihood for the tempo distribution - not the same as.... + tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval-tempoMinimum)/(tempoMaximum - tempoMinimum), tempoDistribution.likelihoodStdDev); + tempoDistribution.calculatePosterior(); + tempoDistribution.renormalisePosterior(); + + //did take pic of screen here - see initialiser4 +} + + +float BayesDrumTracker::tempoIndexToMsec(const int& index){ + float msec; + msec = index * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; + msec += tempoMinimum; + return msec; +} + +float BayesDrumTracker::beatIndexToMsec(const int& index){ + float msec; + msec = index * maxTempo / ARRAY_SIZE; + msec += tempoMinimum; + return msec; +} + diff -r 000000000000 -r 0f9165f96bdb src/BayesDrumTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/BayesDrumTracker.h Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,107 @@ +/* + * BayesDrumTracker.h + * bayesianTempoInitialiser5 + * + * Created by Andrew on 14/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofxOsc.h" +#include "bayesianArray.h" +#include "beatTempo.h" + +class BayesDrumTracker{ + +#ifndef _BAYES_DRUM_TRACKER +#define _BAYES_DRUM_TRACKER +#define ARRAY_SIZE 240 +//#define BAYES_ARRAY_SIZE 240 + + public: + + BayesDrumTracker(); + ~BayesDrumTracker(); + + void initialiseTracker(); + void resetParameters(); + void decayDistributions();//on update + + void setBeatDistribution(int beatPosition); + + void newKickError(const float& error, const double& cpuEventTime, const string& onsetTypeString); + void startTatum(const float& startTatum); + void setNewClickIndex(const int& clickIndex, const float& clickTime); + void sendMaxTempo(); + void sendMaxPhase(); + void newBeat(int& beatIndex); + + void setUniformTempo(); + void setUniformPhase(); + void setBeatNow(const double& beatTime); + void doBeatCorrection(const float& beatCorrFloat); + + + bool filterBeatTime(double newBeatTime); + void crossUpdateArrays(float timeInterval); + bool updateTempoIfWithinRange(double timeInterval); + void calculateTempoUpdate(double tempoInterval); + void updateTempoProcess(const double& cpuTime, const string& onsetDescription); + + + float beatIndexToMsec(const int& index); + float tempoIndexToMsec(const int& index); + + + float kickError, snareError; + double cpuBeatTime; + float testArray[5]; + + double setBeatToNowTime; + + float prior [ARRAY_SIZE]; + float posterior [ARRAY_SIZE]; + float likelihood [ARRAY_SIZE]; + float likelihoodMean, likelihoodStdDev, likelihoodNoise, stepSize; + float maximumEstimate; + float maximumTest, posteriorDecayRate, maximumIndex; + float eighthNoteProportion; + + bool paused; + double maxPhase, maxTempo; + + float tmpArray[ARRAY_SIZE]; + + float correctionFactor; + float beatCorrection; + int correctBeatBy; + + bayesianArray beatDistribution; + bayesianArray tempoDistribution; + double tempoMinimum, tempoMaximum; + double tempoInterval; + beatTempo beatTimes; + + string onsetType; + string timeString; + //double cpuBeatTime; + + ofxOscSender sender; + + double posteriorMaximum; + bool adaptiveStandardDeviationMode; + double tempoStdDev; + bool accompanimentStarted; + bool setDistributionOnStartTempo; + int integerMultipleOfTatum; + + double recentClickTime; + + string kickString;//for info + + float debugArray [4]; + string tempoUpdateStrings[16]; + string tempoDataString; +}; + +#endif \ No newline at end of file diff -r 000000000000 -r 0f9165f96bdb src/bayesianArray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bayesianArray.cpp Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,290 @@ +/* + * bayesianArray.cpp + * bayesianTest5 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#include "bayesianArray.h" +#include "math.h" +#include "ofMain.h" + +bayesianArray::bayesianArray(){ + likelihoodNoise = 0.5; + likelihoodMean = ARRAY_SIZE/2; + likelihoodStdDev = ARRAY_SIZE / 12; +initialiseArray(); +} + +void bayesianArray::initialiseArray(){ + + //maximumIndex = 12;//change this + setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1); + setGaussianLikelihood(ARRAY_SIZE/2, ARRAY_SIZE/1);//likelihoodMean, likelihoodStdDev); + + calculatePosterior(); + renormalisePosterior(); + posteriorDecayRate = 0.06; + + eighthNoteProportion = 0.35;//must be less than 0.5 to discriminate - was 0.4 + earlySixteenthNoteProportion = 0; + lateSixteenthNoteProportion = 0; + decayNoiseAmount = 0.1; + decayNoiseStdDev = ARRAY_SIZE/24; + standardDeviation = likelihoodStdDev; + setDecayNoiseGaussian(ARRAY_SIZE/2, decayNoiseStdDev); + + setGaussianLikelihood(likelihoodMean, likelihoodStdDev); +} + + +void bayesianArray::setGaussianPrior(float mean, float StdDev){ +int i; + for (i=0;i= 0 && mean <= ARRAY_SIZE){ +int i; float eighthDifference; +int eighthPosition = ((int)mean + ARRAY_SIZE/2)%ARRAY_SIZE; +int earlySixteenthPosition = ((int)mean + (3*ARRAY_SIZE/4))%ARRAY_SIZE;; +int lateSixteenthPosition = ((int)mean + (ARRAY_SIZE/4))%ARRAY_SIZE;; + +float mainDifference, sixteenthDifference; +float gaussianProportion = 1 - likelihoodNoise; +float mainProportion = (1 - eighthNoteProportion - earlySixteenthNoteProportion - lateSixteenthNoteProportion); + + for (i=0;i < ARRAY_SIZE;i++){ + + mainDifference = min( fabs(i-mean) , (double)(i + ARRAY_SIZE - mean)); + likelihood[i] = gaussianProportion * mainProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(mainDifference)*(mainDifference)/(2*StdDev*StdDev)) ; + + eighthDifference = min( abs(i - eighthPosition) , i + ARRAY_SIZE - eighthPosition); + eighthDifference = min(eighthDifference , (float)(ARRAY_SIZE + eighthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * eighthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(eighthDifference)*(eighthDifference)/(2*StdDev*StdDev)) ; + + sixteenthDifference = min( abs(i - earlySixteenthPosition) , i + ARRAY_SIZE - earlySixteenthPosition); + sixteenthDifference = min(sixteenthDifference , (float)(ARRAY_SIZE + earlySixteenthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * earlySixteenthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(sixteenthDifference)*(sixteenthDifference)/(2*StdDev*StdDev)) ; + + sixteenthDifference = min( abs(i - lateSixteenthPosition) , i + ARRAY_SIZE - lateSixteenthPosition); + sixteenthDifference = min(sixteenthDifference , (float)(ARRAY_SIZE + lateSixteenthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * lateSixteenthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(sixteenthDifference)*(sixteenthDifference)/(2*StdDev*StdDev)) ; + + + + likelihood[i] += (likelihoodNoise / ARRAY_SIZE); + //likelihood[i] = (float) max(gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)) , + //(double) (likelihoodNoise / ARRAY_SIZE) ); + } +// renormaliseArray(&likelihood[0], ARRAY_SIZE); +}//end if mean within limits +} + + +void bayesianArray::setGaussianLikelihood(float mean, float StdDev){ +if (mean >= 0 && mean <= ARRAY_SIZE){ +int i; float eighthDifference; +int eighthPosition = ((int)mean + ARRAY_SIZE/2)%ARRAY_SIZE; +float mainDifference; +float gaussianProportion = 1 - likelihoodNoise; + + for (i=0;i < ARRAY_SIZE;i++){ + + mainDifference = min( fabs(i-mean) , (double)(i + ARRAY_SIZE - mean)); + //without * (1 - eighthNoteProportion) + likelihood[i] = gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(mainDifference)*(mainDifference)/(2*StdDev*StdDev)) ; + + likelihood[i] += (likelihoodNoise / ARRAY_SIZE); + //likelihood[i] = (float) max(gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)) , + //(double) (likelihoodNoise / ARRAY_SIZE) ); + } +// renormaliseArray(&likelihood[0], ARRAY_SIZE); +}//end if mean within limits +} + +void bayesianArray::calculatePosterior(){ +int i; + for (i=0;i < ARRAY_SIZE;i++){ + posterior[i] = likelihood[i] * prior[i]; + } + //renormalisePosterior(); +} + + +float bayesianArray::getMaximum(float *ptr, int length){ +int i; +float max = 0; + for (i=0;i < length;i++){ + if (*(ptr+i)>max) + max = *(ptr+i); + } + maximumValue = max; + return max; +} + +float* bayesianArray::getMaximumEstimate(float *ptr, int length){ +float returnArray[2]; +int i; +float max = 0; +maximumIndex = 0; + for (i=0;i < length;i++){ + if (*(ptr+i)>max){ + max = *(ptr+i); + maximumIndex = i; + } + } + returnArray[0] = max; + returnArray[1] = maximumIndex; + maximumValue = max; + return &returnArray[0]; +} + + + +double bayesianArray::getIntegratedEstimateIndex(){ + int i; + float integratedQuantity = 0; + float integratedTotal = 0; + double integratedIndex = 0; + for (i=0;i < ARRAY_SIZE;i++){ + integratedQuantity += posterior[i];//the values of the probability distribution + integratedTotal += i*posterior[i]; + } + if (integratedQuantity > 0){ + integratedIndex = integratedTotal / integratedQuantity; + } + integratedEstimate = (float) integratedIndex; + return integratedIndex; +} + + +double bayesianArray::calculateStandardDeviation(){ + + double total = 0; + double pdfSum; + double variance = 0; + for (int i=0;i < ARRAY_SIZE;i++){ +//*posterior[i] * + total += posterior[i] * (i - integratedEstimate) * (i - integratedEstimate);//the values of the probability distribution + pdfSum += posterior[i]; + } + + if (pdfSum > 0) + variance = total / pdfSum; + else + variance = ARRAY_SIZE; + + standardDeviation = sqrt(variance); + return standardDeviation; +} + + + +void bayesianArray::renormaliseArray(float *ptr, int length){ +int i; +float totalArea = 0; + for (i=0;i < length;i++){ + totalArea += *(ptr+i); + } + + for (i=0;i < length;i++){ + *(ptr+i) /= totalArea; + } + +} + +void bayesianArray::resetPrior(){ + int i; + for (i=0;imax){ + maximumIndex = i; + max = posterior[i]; + } + } +} + +void bayesianArray::translateDistribution(int translationIndex){ +int tmpIndex; + //copy array + int i; + for (i=0;i < ARRAY_SIZE;i++){ + tempPosteriorArray[i] = posterior[i] ; + } + //translate values + for (i=0;i < ARRAY_SIZE;i++){ + tmpIndex = (i + translationIndex + ARRAY_SIZE)%ARRAY_SIZE; + posterior[tmpIndex] = tempPosteriorArray[i]; + } + //now delete tmp array +} + + diff -r 000000000000 -r 0f9165f96bdb src/bayesianArray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bayesianArray.h Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,62 @@ +/* + * bayesianArray.h + * bayesianTest5 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef _BAYESIAN_ARRAY +#define _BAYESIAN_ARRAY + +#define ARRAY_SIZE 240 + + +class bayesianArray{ + +public: + + bayesianArray(); + void initialiseArray(); + + void setGaussianLikelihoodForBeats(float mean, float StdDev); + void setGaussianLikelihood(float mean, float StdDev); + void setGaussianPrior(float mean, float StdDev); + void setGaussianPosterior(float mean, float StdDev); + + void calculatePosterior(); + void renormalisePosterior(); + void resetMaximumPosterior();//resets the max index + void decayPosteriorWithGaussianNoise(); + void translateDistribution(int translationIndex); + void setDecayNoiseGaussian(float mean, float StdDev); + double calculateStandardDeviation(); + + + float getMaximum(float *ptr, int length); + void renormaliseArray(float *ptr, int length); + void resetPrior(); + void decayPosterior(); + float* getMaximumEstimate(float *ptr, int length); + double getIntegratedEstimateIndex(); + + float prior [ARRAY_SIZE]; + float posterior [ARRAY_SIZE]; + float likelihood [ARRAY_SIZE]; + float tempPosteriorArray[ARRAY_SIZE]; + + float decayNoiseArray[ARRAY_SIZE]; + float decayNoiseStdDev, decayNoiseAmount; + + float likelihoodMean, likelihoodStdDev, likelihoodNoise; + float maximumTest, posteriorDecayRate, maximumValue; + float eighthNoteProportion, earlySixteenthNoteProportion, lateSixteenthNoteProportion ; + float maximumEstimate, maximumIndex, integratedEstimate; + double standardDeviation; + +private: +}; + +#endif + \ No newline at end of file diff -r 000000000000 -r 0f9165f96bdb src/beatTempo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/beatTempo.cpp Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,188 @@ +/* + * beatTempo.cpp + * bayesianTempo1 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#include "beatTempo.h" + +beatTempo::beatTempo(){ +index = 0; +lastBeatTime = 0; +decayAmount = 0; +} + +//records a loop of cpu times for the last 16 events received + +void beatTempo::addBeatTime(double f, int type){ +//type 1 is kick, type 2 is snare + + index++; + startIndex++; + if (index == 16){ + index = 0; + } + lastBeatTime = f; + beatTimes[index] = f; + + //find the closest click time to this new cputime + //NOT ACTUALLY USED ANYWHERE.... + double useThisClickTime = lastClickTime; + int useThisClickIndex = lastClickIndex ; + + if (lastClickTime + (tatum/2) < f){ + //next click time + closestClickIndexToBeat[index] = lastClickIndex + 1; + //useThisClickTime += tatum; + // useThisClickIndex++; + } + else{ + //recent click time + closestClickIndexToBeat[index] = lastClickIndex; + } + //end not used + + + int lastBeatSegment = beatSegment; + + //timeDifference = f - lastClickTime; + timeDifference = f - lastClickTime; + //[0, 1] => [0, 2*tatum] + beatSegment = (6*(lastClickIndex%8)); + beatSegment += ( ( (int)floor( ( ( (timeDifference + (tatum/12)) * 6) ) / tatum) ) ); + + + + //this calculates the probabilities of events in the different zones + //not yet used in the algorithm + beatSegment = beatSegment%48; + //wipe old onez + while (lastBeatSegment%48 != beatSegment){ + lastBeatSegment++; + if (lastBeatSegment%12 == 0) + decayProbabilityDistributionRow((lastBeatSegment/12)%4); + + beatMap[lastBeatSegment%48] = 0; + + } + addToProbabilityDistribution(beatSegment, type); + //end of new addition + + beatMap[beatSegment] = type; + + + + double intervalCalculation; + int otherIndex; + for (otherIndex = 0;otherIndex < 16;otherIndex++){ + + if (otherIndex != index){ + intervalCalculation = calculateInterval(index, otherIndex); + relativeIntervals[otherIndex][0] = intervalCalculation; + intervalDifferences[index][otherIndex] = intervalCalculation; + + //integer multiple is relativeIntervals[otherIndex][1] + } + else{ + intervalDifferences[index][otherIndex] = 0; + } + } + + + +} + + +void beatTempo::addToProbabilityDistribution(int beatSegment, int type){ + //printf("beat segment %i\n", beatSegment); + int beatNumber = (int) (beatSegment + 1)/12; + beatNumber = beatNumber%4; + float newProbabilityContribution = 1 - decayAmount; + switch (beatSegment%12) { + case 0: + beatProbabilityDistribution[beatNumber][0][type - 1] = newProbabilityContribution; + break; + case 1: + beatProbabilityDistribution[beatNumber][0][type - 1] = 1*newProbabilityContribution; + break; + case 2: + beatProbabilityDistribution[beatNumber][0][type - 1] = 0.5*newProbabilityContribution; + beatProbabilityDistribution[beatNumber][1][type - 1] = 0.5*newProbabilityContribution; + break; + case 3: + beatProbabilityDistribution[beatNumber][1][type - 1] = 1*newProbabilityContribution; + break; + case 4: + beatProbabilityDistribution[beatNumber][1][type - 1] = 0.4*newProbabilityContribution; + beatProbabilityDistribution[beatNumber][2][type - 1] = 0.6*newProbabilityContribution; + break; + case 5: + beatProbabilityDistribution[beatNumber][2][type - 1] = 0.4*newProbabilityContribution; + beatProbabilityDistribution[beatNumber][3][type - 1] = 0.6*newProbabilityContribution; + break; + case 6: + beatProbabilityDistribution[beatNumber][3][type - 1] = 1*newProbabilityContribution; + break; + case 7: + beatProbabilityDistribution[beatNumber][3][type - 1] = 1*newProbabilityContribution; + break; + case 8: + beatProbabilityDistribution[beatNumber][4][type - 1] = 0.6*newProbabilityContribution; + beatProbabilityDistribution[beatNumber][5][type - 1] = 0.4*newProbabilityContribution; + break; + case 9: + beatProbabilityDistribution[beatNumber][5][type - 1] = 1*newProbabilityContribution; + break; + case 10: + beatProbabilityDistribution[beatNumber][5][type - 1] = 0.5*newProbabilityContribution; + break; + case 11: + beatProbabilityDistribution[(beatNumber+1)%4][0][type - 1] = 1*newProbabilityContribution; + break; + } + + +} + +void beatTempo::decayProbabilityDistributionRow(int row){ + + for (int x = 0;x<6;x++){ + beatProbabilityDistribution[row][x][0] *= decayAmount; + beatProbabilityDistribution[row][x][1] *= decayAmount; + } + + +} + +double beatTempo::calculateInterval(int newIndex, int otherIndex){ + + double newTime, otherTime, interval, relativeInterval; + relativeInterval = tatum; + int tatumMultiple; + newTime = beatTimes[newIndex]; + otherTime = beatTimes[otherIndex]; + if (otherTime > 0){ + interval = newTime - otherTime; +// tatumMultiple = closestClickIndexToBeat[newIndex] - closestClickIndexToBeat[otherIndex]; - to be added + tatumMultiple = round (interval / tatum); + if (tatumMultiple > 0){ + relativeInterval = interval / (tatumMultiple); + relativeIntervals[otherIndex][1] = tatumMultiple; + tatumMultiples[newIndex][otherIndex] = tatumMultiple; + }//end if + } + return relativeInterval; + +} + + +void beatTempo::resetBeatTimeArray(){ + for (int i = 0;i < 16;i++){ + beatTimes[i] = 0; + for (int k = 0;k < 16;k++) + intervalDifferences[i][k] = 0; + } +} \ No newline at end of file diff -r 000000000000 -r 0f9165f96bdb src/beatTempo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/beatTempo.h Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,49 @@ +/* + * beatTempo.h + * bayesianTempo1 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +class beatTempo{ + +public: + beatTempo(); + + double beatTimes[16]; + double relativeIntervals[16][2]; + double intervalDifferences[16][16];//diff between new index , other index + bool intervalUsed[16][16]; + int tatumMultiples[16][16]; + bool OnsetIsKick[16]; + + int closestClickIndexToBeat[16]; + int clickIndex;//used by testApp but to be replaced +// int clickPosition[16]; + + double clickTimes[16]; + int clickNumber[16]; + float beatMapTimeDifferences[48]; + + float beatProbabilityDistribution[4][6][2]; + +// int recentClickIndex; + + int index, startIndex; + + char beatMap[48]; + + void addBeatTime(double f, int type); + double calculateInterval(int newIndex, int otherIndex); + void addToProbabilityDistribution(int beatSegment, int typeToAdd); + void decayProbabilityDistributionRow(int row); + void resetBeatTimeArray(); + + double tatum; + double lastClickTime, lastBeatTime; + int lastClickIndex, beatSegment, timeDifference; + float decayAmount;//amount that the old probability observation contributed to the probability array + +}; \ No newline at end of file diff -r 000000000000 -r 0f9165f96bdb src/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cpp Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "testApp.h" +#include "ofAppGlutWindow.h" + +//======================================================================== +int main( ){ + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp( new testApp()); + +} diff -r 000000000000 -r 0f9165f96bdb src/testApp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.cpp Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,1521 @@ +#include "testApp.h" + + +//-------------------------------------------------------------- +//relooking at this problem +//bayesianTempo7 - have had working well with Bayesian8NEW maxmsp set + +//updated in bayesian8 +//integrate so that maxPhase and tempo are the integrated result across the pdf +//rather tahn the maximum index - tends to reflect the actuial distribution better +//and is the "correct" bayesian method + +//added [ and ] tpo change the alignment when rescue is needed + +//in Bayesian9 (BayesianTest8NEW) +//added noise in phase process +//started probability distribution for observed beat events + +//in bayesian 11 +//get s.d. of posterior +//this is set to be used as the s.d. of the likelihood + + +//Initialiser : the algorithm has an initialisation stage with flat prior that detects liekly tempo + + + +//BAYESIAN DISTRIBUTION SET by class BayesianArray +//SETUP - initialises array +//UPDATE - decay the distribution with noise +//this should be done using tempo and noise +//DRAW - Draw current distributions and also the maximum + +//Runs with bayesian11NEW +//and B-KeeperOldBayesianTestNew in Live +//Needs - categorisation of beats and tempo +//can we use our distribution to filter the input or is that cheating? + +//INtroduce lock scheme for tempo - we know where the beat fell, so can calculate the appropriate tempo interval + +void testApp::setup(){ +// listen on the given port + cout << "listening for osc messages on port " << PORT << "\n"; + receiver.setup( PORT ); + +// sender.setup( HOST, OUTPORT ); + ofSetCircleResolution(50); + ofBackground(255,255,255); + bSmooth = false; + msg_string = "setup"; + + ofSetWindowTitle("Bayesian Test"); + + ofSetFrameRate(60); // if vertical sync is off, we can go a bit fast... this caps the framerate at 60fps. + +/* + beatDistribution.initialiseArray(); + tempoDistribution.initialiseArray(); + beatTimes.lastBeatTime = 0; + correctionFactor = 0.5; + + + + tempoDistribution.likelihoodStdDev = ARRAY_SIZE / 32; +// tempoDistribution.likelihoodNoise = 0.96; + tempoDistribution.likelihoodNoise = 0.7; + tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1);//wide + + beatDistribution.likelihoodStdDev = ARRAY_SIZE / 32; + beatDistribution.likelihoodNoise = 0.56; + beatDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1); + + + tempoMinimum = 180; + tempoMaximum = 400; + posteriorMaximum = 0.1; + + */ + hidePriorMode = false; + + printInterval = true; + drawData = false; + + screenToDraw = 0; + + ofSetLineWidth(2); + ofEnableSmoothing(); + + + bSnapshot = false; + snapCounter = 0; + + drumTracker.paused = false; + +// setDistributionOnStartTempo = true; + + resetParameters(); + + arrayToMsecScaleFactor = (drumTracker.tempoMaximum - drumTracker.tempoMinimum)/ ARRAY_SIZE;//turns array into ms + tempoWindowMinimum = 100; + tempoWindowMaximum = 150; + tempoWindowWidth = 50; +} + + +void testApp::resetParameters(){ + /* + beatTimes.startIndex = 0; + beatTimes.lastBeatTime = 0; + maxPhase = 0; + posteriorMaximum = 0.1; + + accompanimentStarted = false; + + tempoDistribution.likelihoodNoise = 0.8; + tempoDistribution.setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/2);//wide + + beatDistribution.initialiseArray(); + tempoDistribution.initialiseArray(); + + tempoDistribution.calculateStandardDeviation(); + beatDistribution.calculateStandardDeviation(); + + tempoStdDev = tempoDistribution.standardDeviation; + + beatTimes.resetBeatTimeArray(); + */ +} + +//-------------------------------------------------------------- +void testApp::update(){ + + + updateOSCmessages(); + + //update tempo window range - this for viewing tempo closeup + while (tempoWindowMinimum + tempoWindowWidth/4 > drumTracker.tempoDistribution.integratedEstimate) + tempoWindowMinimum -= tempoWindowWidth/4; + + while (tempoWindowMinimum + 3*tempoWindowWidth/4 < drumTracker.tempoDistribution.integratedEstimate) + tempoWindowMinimum += tempoWindowWidth/4; + + tempoWindowMaximum = tempoWindowMinimum + tempoWindowWidth; + + drumTracker.decayDistributions(); + +} + + +void testApp::updateOSCmessages(){ + + + // check for waiting messages + while( receiver.hasWaitingMessages() ) + { + ofxOscMessage m; + receiver.getNextMessage( &m ); + string newAddress = m.getAddress(); + + if ( m.getAddress() == "/Reset" ){ + printf("baysian reset\n"); + drumTracker.resetParameters(); + } + + + if ( m.getAddress() == "/beatError" ){ + double timeNow = ofGetElapsedTimeMillis(); + if (timeNow - drumTracker.setBeatToNowTime > 1000) + drumTracker.newKickError(m.getArgAsFloat(0), m.getArgAsFloat(2), m.getArgAsString(1)); + }//end if new error + + + + if ( m.getAddress() == "/tatum" ){ + drumTracker.beatTimes.tatum = m.getArgAsFloat(0); + printf("got tatum as %f\n", m.getArgAsFloat(0)); + } + + if ( m.getAddress() == "/startTatum" ){ + drumTracker.startTatum(m.getArgAsFloat(0)); + printf("START TATUM %f\n", m.getArgAsFloat(0)); + //then change so tempo distribution is correct.... + }//end start tatum + + + if ( m.getAddress() == "/uniformTempo" ){ + drumTracker.setUniformTempo(); + + } + + + if ( m.getAddress() == "/uniformPhase" ){ + drumTracker.setUniformPhase(); + + } + + + if ( m.getAddress() == "/setBeatNow" ){ + + double beatTime = m.getArgAsFloat(0); + drumTracker.setBeatNow(beatTime); + //printf("SET BEAT NOW %f\n", beatTime); + } + + + if ( m.getAddress() == "/clickindex" ){ + + int clickIndex = m.getArgAsInt32(0); + float clickTime = m.getArgAsFloat(1); + drumTracker.setNewClickIndex(clickIndex, clickTime); + } + + + if ( m.getAddress() == "/newBeat" ){ + int beatIndex = m.getArgAsInt32(0); + drumTracker.newBeat(beatIndex); + } + + + if ( m.getAddress() == "/beatCorrection" ) + { + float beatCorrValue = m.getArgAsFloat(0); + drumTracker.doBeatCorrection(beatCorrValue); + + }//end correction by + + + if ( m.getAddress() == "/BayesianNoise" ){ + drumTracker.beatDistribution.likelihoodNoise = m.getArgAsFloat(0);; + printf("bayesian noise set to %f\n", drumTracker.beatDistribution.likelihoodNoise); + // beatDistribution.setGaussianLikelihood(beatDistribution.likelihoodMean, beatDistribution.likelihoodStdDev); + } + + if ( m.getAddress() == "/BayesianStdDev" ){ + drumTracker.beatDistribution.likelihoodStdDev = ARRAY_SIZE / m.getArgAsFloat(0); + // beatDistribution.setGaussianLikelihood(beatDistribution.likelihoodMean, beatDistribution.likelihoodStdDev); + } + + + }//end while there is new message + + +} + + +void testApp::takePictureOfScreen(){ + // grab a rectangle at 200,200, width and height of 300,180 + img.grabScreen(0,0,screenWidth,screenHeight); + char fileName[255]; + sprintf(fileName, "snapshot_%0.3i.png", snapCounter); + img.saveImage(fileName); + //printf("saved %s\n", fileName); + snapCounter++; + bSnapshot = false; +} + +/* +void testApp::setBeatDistribution(int beatPosition){ + switch (beatPosition){ + //early sixteenth is that the beat is a sixteenth earlier + case 0: + case 1: + case 11: + //i.e. these zones are interpreted as "on the beat" + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0; + break; + //10 and 2 were here + + case 2: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + //i.e. a 25% chance it is early sixteenth - 75% that the beat actually lies here + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 3: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.3;//was 0.4 in Bayesian8 //half chance it is early + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 5: + case 6: + case 7: + beatDistribution.eighthNoteProportion = 0.3;//i.e. nearly half a chance we are on the 8th note + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0; + break; + + case 4: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + beatDistribution.lateSixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 + //chsanged to 0.2 and 0.1 then back + break; + + case 8: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0.05;//was 0.2 in Bayesian8 + beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.3 in Bayesian8 + break; + + case 9: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0.35;//was 0.4 in Bayesian8 + break; + + case 10: + beatDistribution.eighthNoteProportion = 0; + beatDistribution.earlySixteenthNoteProportion = 0; + beatDistribution.lateSixteenthNoteProportion = 0.25;//was 0.2 in Bayesian8 + break; + + } + +} +*/ +//-------------------------------------------------------------- +void testApp::draw(){ + //--------------------------- lines + // a bunch of red lines, make them smooth if the flag is set + + + + if (bSmooth){ + ofEnableSmoothing(); + } + + switch (screenToDraw){ + case 0: + drawBayesianDistribution(); + break; + case 1: + drawTempoDistribution(); + break; + case 2: + drawBeatMap(); + break; + case 3: + // drawNormalisedLikelihood(); + drawRestrictedTempoDistribution(tempoWindowMinimum, tempoWindowMaximum); + break; + case 4: + drawTempoData(); + break; + case 5: + drawBeatProbabilityDistribution(); + break; + case 6: + drawPosterior(); + break; + case 7: + drawGreyscaleBayesianDistribution(); + break; + + } + + + + if (bSnapshot == true){ + takePictureOfScreen(); + bSnapshot = false; + } + +}//end draw + + +void testApp::drawTempoData(){ + + ofSetColor(0xFFFF00); +//yellow line in centre +ofLine( 0, (screenHeight/2), screenWidth, (screenHeight/2)); + +ofSetColor(0x0000FF); +int tempoIndex = 0; +int widthOffset = 20; +float stepWidth = screenWidth / 16; + ofDrawBitmapString("tatums : ", 600,180); + ofDrawBitmapString(ofToString(drumTracker.beatTimes.tatum, 1), 700,180); + ofDrawBitmapString("bpm : ", 600,200); + ofDrawBitmapString(ofToString((drumTracker.beatTimes.tatum/30000), 1), 700,200); +int intervalIndex; +int intervalWidth = 2; +float magnifyingFactor = 8; +for (tempoIndex = 0;tempoIndex < 16; tempoIndex++){ + +for (intervalIndex = 0;intervalIndex < 16;intervalIndex++){ +//new color code +if (drumTracker.beatTimes.intervalUsed[tempoIndex][intervalIndex] == true){ +ofSetColor(0x00FFFF); +} +else{ +ofSetColor(0xFF00FF); +} +//end new code + +ofLine((stepWidth*tempoIndex)+ (intervalWidth*intervalIndex) + widthOffset, screenHeight, + (stepWidth*tempoIndex) + (intervalWidth*intervalIndex) + widthOffset, (screenHeight/2) * (1 + (magnifyingFactor * (1-drumTracker.beatTimes.intervalDifferences[tempoIndex][intervalIndex])))); + + if (printInterval == true){ + ofDrawBitmapString(ofToString(drumTracker.beatTimes.intervalDifferences[tempoIndex][intervalIndex], 3), + (stepWidth*tempoIndex) + widthOffset,20+(intervalIndex*20)); + } + + + ofDrawBitmapString(ofToString(drumTracker.beatTimes.relativeIntervals[tempoIndex][0], 3), 700,220+(tempoIndex*20)); + ofDrawBitmapString(ofToString(drumTracker.beatTimes.relativeIntervals[tempoIndex][1], 1), 750,220+(tempoIndex*20)); +}//end for interval index +}//end for tempo index + + ofDrawBitmapString(ofToString(drumTracker.beatTimes.clickIndex), 750,20); + + ofDrawBitmapString(ofToString(mouseBPM), 50,20); + ofDrawBitmapString(drumTracker.tempoDataString, 50, 100); + +}//end draw tempo data + + +void testApp::drawTempoDistribution(){ + float maximum = drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.posterior[0], ARRAY_SIZE)); + + maximum *= 1.1; + + float stepHeight = screenHeight/maximum; + + + +//draw prior in green + ofSetColor(0x888888); + for (int i = 1; i < ARRAY_SIZE; i+=2){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.prior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.prior[i]*stepHeight)); + } + + +//draw posterior in dark + ofSetColor(0x000000); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.posterior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.posterior[i]*stepHeight)); + } + + +//black line is the max probability +ofSetColor(0x000000); + ofLine(drumTracker.tempoDistribution.integratedEstimate *stepSize, screenHeight, drumTracker.tempoDistribution.integratedEstimate *stepSize, 0); + + //blue is the current kick received + ofSetColor(0xAAAAAA); + +int altIndex = 0; + for (altIndex = 0;altIndex< 16;altIndex++){ + + double tempoInterval = drumTracker.beatTimes.intervalDifferences[drumTracker.beatTimes.index][altIndex]; + + if (altIndex != drumTracker.beatTimes.index && tempoInterval > drumTracker.tempoMinimum && tempoInterval < drumTracker.tempoMaximum){ + + + + //draw likelihood + //draw likelhood in blue +// //need to reset likelihood for this! + //XXX remove + double timeInterval = drumTracker.beatTimes.beatTimes[drumTracker.beatTimes.index] - drumTracker.beatTimes.beatTimes[altIndex]; + if (timeInterval > 2*drumTracker.tempoMinimum && timeInterval < 2*drumTracker.tempoMaximum) + { + + ofLine(stepSize*(ARRAY_SIZE * (tempoInterval-drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum)), screenHeight, + stepSize*(ARRAY_SIZE * (tempoInterval - drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum)) , 0); + + drumTracker.tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval - drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum), drumTracker.tempoDistribution.likelihoodStdDev); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i]*stepHeight)); + } + } + + } + + }//end for + + if (bSmooth){ + ofDisableSmoothing(); + } + + drawTempoInfo(); + +} + + +int testApp::xcoordinateFromTempoDataPoint(float f){ + //f is the time + + int xcoordinateForInterval = 0; + if (f >= drumTracker.tempoMinimum && f <= drumTracker.tempoMaximum) + xcoordinateForInterval = ((float)(f - drumTracker.tempoMinimum)*screenWidth/(float)(drumTracker.tempoMaximum - drumTracker.tempoMinimum)); + return xcoordinateForInterval; + +} + + +int testApp::xcoordinateFromRestrictedTempoDataPoint(float f, const int& tmpMin, const int& tmpMax){ + + + int xcoordinateForInterval = -1; + if (f >= drumTracker.tempoMinimum+tmpMin && f <= min(drumTracker.tempoMinimum+tmpMax,drumTracker.tempoMaximum)) + xcoordinateForInterval = ((float)(f - drumTracker.tempoMinimum - tmpMin*arrayToMsecScaleFactor)*screenWidth/(float)((tmpMax - tmpMin)*arrayToMsecScaleFactor)); + return xcoordinateForInterval; + +} + + +void testApp::drawTempoInfo(){ + float maximum = drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.posterior[0], ARRAY_SIZE)); + + + ofSetColor(0x000000); + string testString; + testString = "max is "; + testString += ofToString(maximum); + ofDrawBitmapString(testString, 700,620); + + ofDrawBitmapString(msg_string, 700,650); + + ofDrawBitmapString(kickString, 700,670); + + testString = "std dev : "; + testString += ofToString(drumTracker.tempoStdDev, 6); + + testString += ", "; + testString += ofToString(drumTracker.accompanimentStarted); + ofDrawBitmapString(testString, 20, 120); + + int tempoUpdateIndex; + for (tempoUpdateIndex = 0;tempoUpdateIndex<16;tempoUpdateIndex++){ +// ofDrawBitmapString(tempoUpdateStrings[tempoUpdateIndex], 700, 200 + (20 * tempoUpdateIndex)); + } + + ofDrawBitmapString("Mouse located at tempo: ", 50,10); + ofDrawBitmapString(ofToString(mouseBPM, 1), 50,20); + + ofDrawBitmapString("Current tempo: ", 50,40); + ofDrawBitmapString(ofToString(30000/drumTracker.beatTimes.tatum, 1), 50,50); + + ofDrawBitmapString(drumTracker.tempoDataString, 50, 100); + + + for (int i = 1;i < 16; i++){ + for (int altIndex = 0; altIndex < 16;altIndex++){ + string newString; + newString = " :"; + int recentIndex = (altIndex-i+16)%16; + if (drumTracker.beatTimes.intervalDifferences[altIndex][recentIndex] > 0 && drumTracker.beatTimes.intervalUsed[altIndex][recentIndex]){ + + + int xcoordinateForInterval = xcoordinateFromTempoDataPoint(drumTracker.beatTimes.intervalDifferences[altIndex][recentIndex]); + float beatInterval = (float) drumTracker.beatTimes.tatumMultiples[altIndex][recentIndex]/2; + + if (drumTracker.beatTimes.OnsetIsKick[altIndex]) + ofSetColor(255*(8-beatInterval)/(float)8, 0, 255*beatInterval/(float)8); + else + ofSetColor(0, 255*(8-beatInterval)/(float)8, 255*beatInterval/(float)8); + //red kick, green snare + + ofCircle(xcoordinateForInterval, 200 + (altIndex * 20), 3); + + newString += ofToString(drumTracker.beatTimes.intervalDifferences[altIndex][recentIndex],0); + newString += " ("; + newString += ofToString(drumTracker.beatTimes.tatumMultiples[altIndex][recentIndex]/2, 0); + newString += ")"; + + } + ofSetColor(0,0,0); + //ofDrawBitmapString(newString, 200 + i*80, 200 + (altIndex * 20)); + + + } + } + +} + + + + +void testApp::drawTempoDataPoints(const int& tmpMin, const int& tmpMax, const float& tmpStepSize){ + + for (int i = 1;i < 16; i++){ + for (int altIndex = 0; altIndex < 16;altIndex++){ + // string newString; + // newString = " :"; + + int recentIndex = (altIndex-i+16)%16; + if (drumTracker.beatTimes.intervalDifferences[altIndex][recentIndex] > 0 && drumTracker.beatTimes.intervalUsed[altIndex][recentIndex]){ + + int xcoordinateForInterval = xcoordinateFromRestrictedTempoDataPoint(drumTracker.beatTimes.intervalDifferences[altIndex][recentIndex], tmpMin, tmpMax); + float beatInterval = (float) drumTracker.beatTimes.tatumMultiples[altIndex][recentIndex]/2; + + if (drumTracker.beatTimes.OnsetIsKick[altIndex]) + ofSetColor(255*(7-beatInterval+1)/(float)7, 255*(beatInterval-1)/(float)7, 0);//100+155*(8-beatInterval)/(float)8 + else + ofSetColor(0, 255*(7-beatInterval+1)/(float)7, 255*(beatInterval-1)/(float)7);//, 155*beatInterval/(float)8); + //red kick, green snare + + ofCircle(xcoordinateForInterval, 200 + (altIndex * 20), 3); + ofDrawBitmapString(ofToString(beatInterval, 0), xcoordinateForInterval-2, 200 + (altIndex * 20) - 3); + /* newString += ofToString(beatTimes.intervalDifferences[altIndex][recentIndex],0); + newString += " ("; + newString += ofToString(beatTimes.tatumMultiples[altIndex][recentIndex]/2, 0); + newString += ")"; + */ + } + ofSetColor(0,0,0); + //ofDrawBitmapString(newString, 200 + i*80, 200 + (altIndex * 20)); + + + } + } + +} + + +void testApp::drawRestrictedTempoDistribution(int tmpMin, int tmpMax){ + //min and max are in the tempo array coordinates + + tmpMin = max(tmpMin, 0); + tmpMax = min(tmpMax, ARRAY_SIZE-1); + + float maximum = drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.posterior[0], ARRAY_SIZE)); + + maximum *= 1.1; + + float stepHeight = screenHeight/maximum; + int tmpWidth = tmpMax - 1 - tmpMin; + float tmpStepSize = screenWidth / (float) tmpWidth; + + + //draw prior in green + ofSetColor(0x888888); + for (int i = 1; i < tmpWidth; i+=2){ + ofLine((i-1)*tmpStepSize, screenHeight - (drumTracker.tempoDistribution.prior[tmpMin+i-1]*stepHeight), i * tmpStepSize, screenHeight - (drumTracker.tempoDistribution.prior[tmpMin+i]*stepHeight)); + } + + + //draw posterior in dark + ofSetColor(0x000000); + for (int i = 1; i < tmpWidth; i++){ + ofLine((i-1) * tmpStepSize, screenHeight - (drumTracker.tempoDistribution.posterior[tmpMin+i-1]*stepHeight), i*tmpStepSize, screenHeight - (drumTracker.tempoDistribution.posterior[tmpMin+i]*stepHeight)); + } + + + //black line is the max probability + ofSetColor(0x000000); + ofLine((drumTracker.tempoDistribution.integratedEstimate - tmpMin)* tmpStepSize, screenHeight, (drumTracker.tempoDistribution.integratedEstimate-tmpMin) *tmpStepSize, 0); + + //blue is the current kick received + ofSetColor(0xAAAAAA); + + int altIndex = 0; + for (altIndex = 0;altIndex< 16;altIndex++){ + //iterate through all recent beat intervals + + double tempoInterval = drumTracker.beatTimes.intervalDifferences[drumTracker.beatTimes.index][altIndex]; + + if (altIndex != drumTracker.beatTimes.index && tempoInterval > drumTracker.tempoMinimum && tempoInterval < drumTracker.tempoMaximum){ + + double timeInterval = drumTracker.beatTimes.beatTimes[drumTracker.beatTimes.index] - drumTracker.beatTimes.beatTimes[altIndex]; + + if (timeInterval > 2*drumTracker.tempoMinimum && timeInterval < 2*drumTracker.tempoMaximum){ + //i.e. within the beat range only + //so we only draw the likelihood realtime for happening beat intervals + //in fact much more is going on than this but harder to visualise + + float indexOfNewLocation = ARRAY_SIZE*(tempoInterval-drumTracker.tempoMinimum)/(float)(drumTracker.tempoMaximum - drumTracker.tempoMinimum); + + + if (indexOfNewLocation >= tmpMin){ + ofLine(tmpStepSize * (indexOfNewLocation-tmpMin), screenHeight, tmpStepSize * (indexOfNewLocation-tmpMin) , 0); + } + + + drumTracker.tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval - drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum), drumTracker.tempoDistribution.likelihoodStdDev); + //setting the tempo distribution likeihood just for visualisation purposes + for (int i = 1; i < tmpWidth; i++){ + ofLine((i-1)*tmpStepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i+tmpMin-1]*stepHeight), i*tmpStepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i+tmpMin]*stepHeight)); + + } + } + + } + + }//end for + + if (bSmooth){ + ofDisableSmoothing(); + } + + + drawTempoDataPoints(tmpMin, tmpMax, tmpStepSize); + +// lines for background + for (int i = tmpMin-(tmpMin%20);i < tmpMax; i+=20){ + ofSetColor(0,0,200,100); + ofLine(tmpStepSize * (i-tmpMin), screenHeight, tmpStepSize * (i-tmpMin) , 0); + string tmpTempoString = ofToString(drumTracker.tempoMinimum + i*arrayToMsecScaleFactor, 0); + ofDrawBitmapString(tmpTempoString, tmpStepSize * (i-tmpMin) , 20); + } + + string currentTatumString = "Beat Period : "; + currentTatumString += ofToString(drumTracker.beatTimes.tatum, 1); + currentTatumString += " MaxIndex : "; + currentTatumString += ofToString(drumTracker.tempoDistribution.integratedEstimate, 1); + + ofDrawBitmapString(currentTatumString, 20, 40); + //drawTempoInfo(); + +} + + + + + + + + + + + +void testApp::drawBeatMap(){ +int x,y; + +for (x=0;x < 6;x++){ + for (y=0;y<8;y++){ + int cell = x+(y*6); + if (cell == drumTracker.beatTimes.beatSegment){ + if (drumTracker.beatTimes.beatMap[cell] == 1)//for kick + ofSetColor(drumTracker.beatTimes.beatMap[cell]*255, 0, 0); + + if (drumTracker.beatTimes.beatMap[cell] == 2)//for kick + ofSetColor(0, drumTracker.beatTimes.beatMap[cell]*255, 100); + + } + else{ + if (drumTracker.beatTimes.beatMap[cell] == 1)//for kick + ofSetColor(drumTracker.beatTimes.beatMap[cell]*155, 0, 0); + else //for snare + ofSetColor(0,drumTracker.beatTimes.beatMap[cell]*155, 0);//beatTimes.beatMap[cell]*155); + + } + ofRect(screenWidth*x/6, screenHeight*y/8, screenWidth/6, screenHeight/8); + + ofSetColor(255,0,0); + ofDrawBitmapString(ofToString(x+(y*6)), screenWidth*x/6, screenHeight*y/8); + + if (drumTracker.beatTimes.beatMap[cell] == 1){ + ofSetColor(0,255,255);// + ofDrawBitmapString(ofToString(drumTracker.beatTimes.beatMapTimeDifferences[cell], 2), (screenWidth*(x+0.5)/6) , (screenHeight*(y+0.5)/8) ); + } + if (drumTracker.beatTimes.beatMap[cell] == 2){ + ofSetColor(0,0,100);// + ofDrawBitmapString(ofToString(drumTracker.beatTimes.beatMapTimeDifferences[cell], 2), (screenWidth*(x+0.5)/6) , (screenHeight*(y+0.5)/8) ); + } + + + } +} + +} + + + + +void testApp::drawBeatProbabilityDistribution(){ + int x,y; + + for (x=0;x < 6;x++){ + for (y=0;y<4;y++){ + int cell = x+(y*6); + ofSetColor(drumTracker.beatTimes.beatProbabilityDistribution[y][x][0]*255, 0, 0); + ofRect(screenWidth*x/6, screenHeight*y/8, screenWidth/6, screenHeight/8); + } + } + for (x=0;x < 6;x++){ + for (y=0;y<4;y++){ + int cell = x+(y*6); + ofSetColor(0, drumTracker.beatTimes.beatProbabilityDistribution[y][x][1]*255, 0); + ofRect(screenWidth*x/6, screenHeight*(y+4)/8, screenWidth/6, screenHeight/8); + } + } + +} + + +void testApp::drawNormalisedLikelihood(){ + float maximum = drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.prior[0], ARRAY_SIZE)); + //maximum = max(maximum, beatDistribution.getMaximum(&beatDistribution.posterior[0], ARRAY_SIZE)); + float stepHeight = screenHeight/maximum; + +if (!hidePriorMode){ +//draw likelhood in blue + + ofSetColor(0x0000FF); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i]*stepHeight)); + } + +//draw prior in green + ofSetColor(0x00AA00); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i]*stepHeight)); + } +}//end hide prior mode + + + +} + + + +void testApp::drawPosterior(){ + float maximum = drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.posterior[0], ARRAY_SIZE); + + if (drumTracker.posteriorMaximum < maximum){ + drumTracker.posteriorMaximum = 1.2*maximum; + } + + float stepHeight = screenHeight/drumTracker.posteriorMaximum; + ofSetColor(0xFF00FF); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i]*stepHeight)); + } + + + //yellow is the middle + ofSetColor(0xFFFF00); + ofLine(ARRAY_SIZE*stepSize/2, screenHeight, ARRAY_SIZE*stepSize/2, 0); + + + + //blue is the current kick received + ofSetColor(0x0000FF); + ofLine(stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), screenHeight,stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), 0); + + //purple line is the integrated max probability + int integratedBeatEstimateDrawPoint = round(drumTracker.beatDistribution.integratedEstimate*stepSize) ; + ofSetColor(0xFF22FF); + ofLine(integratedBeatEstimateDrawPoint, screenHeight, integratedBeatEstimateDrawPoint, 0); + + string testString = "maximum: "; + testString += ofToString(drumTracker.posteriorMaximum, 2); + ofDrawBitmapString(testString, 100,120); + + +} + + + + + +void testApp::drawBayesianDistribution(){ + float maximum = drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.posterior[0], ARRAY_SIZE)); + float stepHeight = screenHeight/maximum; + + if (!hidePriorMode){ + //draw likelhood in blue + if (drumTracker.onsetType == "kick") + ofSetColor(0xff0000);//red : kick + else + ofSetColor(0x00FF00);//green : snare + + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i]*stepHeight)); + } + + //;line where the current kick is received + ofLine(stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), screenHeight,stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), 0); + + + //draw prior in aqua blue + ofSetColor(0x00AAAA); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i]*stepHeight)); + } + }//end hide prior mode + + //draw posterior in red + ofSetColor(0x0000FF); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i]*stepHeight)); + } + + //draw the previous updated posteriror in purple + /* ofSetColor(0xFF22FF); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (tmpArray[i-1]*stepHeight), i*stepSize, screenHeight - (tmpArray[i]*stepHeight)); + } + */ + + //yellow is the middle + ofSetColor(0xFFFF00); + ofLine(ARRAY_SIZE*stepSize/2, screenHeight, ARRAY_SIZE*stepSize/2, 0); + + //black line is the max probability + ofSetColor(0x000000); + ofLine(drumTracker.beatDistribution.maximumIndex*stepSize, screenHeight, drumTracker.beatDistribution.maximumIndex*stepSize, 0); + + + //purple line is the integrated max probability + int integratedBeatEstimate = drumTracker.beatDistribution.integratedEstimate ; + ofSetColor(0x2222FF); + ofLine(integratedBeatEstimate *stepSize, screenHeight, integratedBeatEstimate *stepSize, 0); + + + if (bSmooth){ + ofDisableSmoothing(); + } + + printBayesianData(); +} + +void testApp::printBayesianData(){ + //not optimised!!! XXX + float maximum = drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.posterior[0], ARRAY_SIZE)); + + ofSetColor(0x000000); + string testString; + testString = "max2 is "; + testString += ofToString(maximum, 3); + testString += " :: "; + + testString = "correction of "; + testString += ofToString(drumTracker.beatCorrection); + testString += " corr by :"; + testString += ofToString(drumTracker.correctBeatBy); + + //ofDrawBitmapString(testString, 100,120); + + testString = "MaxPhase "; + testString += ofToString(drumTracker.maxPhase); +// ofDrawBitmapString(testString, 100,140); + + + testString = "Likelihood noise "; + testString += ofToString(drumTracker.beatDistribution.likelihoodNoise, 2); + //ofDrawBitmapString(testString, 100,160); + +// ofDrawBitmapString(msg_string, 100,140); + +// ofDrawBitmapString(kickString, 100,180); + +/* debugString = "Min Debug = "; + debugString += ofToString(drumTracker.tempoDistribution.maximumIndex + drumTracker.minTempoIndex); + debugString += " Max Debug = "; + debugString += ofToString(drumTracker.tempoDistribution.maximumIndex + drumTracker.maxTempoIndex); +*/ + //ofDrawBitmapString(debugString, 300,370); + + debugString = "CLICK INDEX = "; + debugString += ofToString(drumTracker.beatTimes.clickIndex); + //ofDrawBitmapString(debugString, 100, 20); + + debugString = "STD DEV = "; + debugString += ofToString(drumTracker.beatDistribution.standardDeviation, 2); +// ofDrawBitmapString(debugString, 100, 40); + + + + debugString = "interval "; + debugString += ofToString(drumTracker.debugArray[2], 2); + debugString += " time int = "; + debugString += ofToString(drumTracker.debugArray[1], 2); + debugString += " Beat max = "; + debugString += ofToString(drumTracker.debugArray[0 ], 2); + debugString += " Tempo max = "; + debugString += ofToString(drumTracker.debugArray[3 ], 2); +// ofDrawBitmapString(debugString, 300,570); + + debugString = " last = "; + debugString += ofToString(drumTracker.beatTimes.lastBeatTime, 2); +// ofDrawBitmapString(debugString, 300,470); + + + string closestClickString = "Closest Click "; + closestClickString += ofToString(drumTracker.beatTimes.closestClickIndexToBeat[drumTracker.beatTimes.index]); + closestClickString += " beat seg "; + closestClickString += ofToString(drumTracker.beatTimes.beatSegment%12); + closestClickString += " lastCindex"; + closestClickString += ofToString(drumTracker.beatTimes.lastClickIndex); + closestClickString += " TD "; + closestClickString += ofToString(drumTracker.beatTimes.timeDifference); + +// ofDrawBitmapString(closestClickString, 100,100); + +// ofDrawBitmapString(timeString, 100,60); +} + + + +void testApp::drawGreyscaleBayesianDistribution(){ + ofSetColor(255,255,255); + ofRect(0,0,screenWidth, screenHeight); + + float maximum = drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.beatDistribution.getMaximum(&drumTracker.beatDistribution.posterior[0], ARRAY_SIZE)); + maximum *= 1.1; + float stepHeight = screenHeight/maximum; + + if (!hidePriorMode){ + //draw likelhood in blue + ofSetColor(0x555555); + for (int i = 1; i < ARRAY_SIZE; i+=2){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.likelihood[i]*stepHeight)); + } + + //draw prior in green + ofSetColor(0xAAAAAA); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.prior[i]*stepHeight)); + } + }//end hide prior mode + + //draw posterior in dark grey + ofSetColor(0x222222); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.beatDistribution.posterior[i]*stepHeight)); + } + + /* + //dotted the middle + ofSetColor(0x555555); + for (int i = 1; i < screenHeight; i+=4){ + ofLine(ARRAY_SIZE*stepSize/2, i, ARRAY_SIZE*stepSize/2, i-2); + } + */ + + //purple line is the integrated max probability +// int integratedBeatEstimate = beatDistribution.integratedEstimate ; +// ofSetColor(0x000000); +// ofLine(integratedBeatEstimate *stepSize, screenHeight, integratedBeatEstimate *stepSize, 0); + + //purple line is the integrated max probability + float tmpIntegratedBeatEstimate = drumTracker.beatDistribution.getIntegratedEstimateIndex(); + ofSetColor(0x000000); + int drawLinePoint = round(tmpIntegratedBeatEstimate *stepSize); + ofLine(drawLinePoint, screenHeight, drawLinePoint, 0); + + //blue is the current kick received + ofSetColor(0x555555); + for (int i = 1; i < screenHeight; i+=40){ + ofLine(stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), i,stepSize*((ARRAY_SIZE/2) + (ARRAY_SIZE*drumTracker.kickError)), i-20); + } + + +} + + + + +void testApp::drawGreyscaleTempoDistribution(double tempoInterval){ + ofSetColor(255,255,255); + ofRect(0,0,screenWidth, screenHeight); + + float maximum = drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.likelihood[0], ARRAY_SIZE); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.prior[0], ARRAY_SIZE)); + maximum = max(maximum, drumTracker.tempoDistribution.getMaximum(&drumTracker.tempoDistribution.posterior[0], ARRAY_SIZE)); + + maximum *= 1.1; + + float stepHeight = screenHeight/maximum; + + //draw prior in green + ofSetColor(0x777777); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.prior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.prior[i]*stepHeight)); + } + + + //draw posterior in dark + ofSetColor(0x000000); + for (int i = 1; i < ARRAY_SIZE; i++){ + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.posterior[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.posterior[i]*stepHeight)); + } + + + //black line is the max probability + ofSetColor(0xFF0000); + ofLine(drumTracker.tempoDistribution.integratedEstimate *stepSize, screenHeight, drumTracker.tempoDistribution.integratedEstimate *stepSize, 0); + + //blue is the current kick received + ofSetColor(0xAAAAAA); + + + + + for (int k =1;k < screenHeight/12;k+=2){ + ofLine(stepSize*(ARRAY_SIZE * (tempoInterval-drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum)), 12*k, + stepSize*(ARRAY_SIZE * (tempoInterval-drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum)) , 12*(k-1)); + } + + drumTracker.tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval - drumTracker.tempoMinimum)/(drumTracker.tempoMaximum - drumTracker.tempoMinimum), drumTracker.tempoDistribution.likelihoodStdDev); + for (int i = 1; i < ARRAY_SIZE; i+=2){ + //dotted line likelihood fn + ofLine((i-1)*stepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i-1]*stepHeight), i*stepSize, screenHeight - (drumTracker.tempoDistribution.likelihood[i]*stepHeight)); + } + + + + + if (bSmooth){ + ofDisableSmoothing(); + } + +} + + + + +//-------------------------------------------------------------- +void testApp::keyPressed (int key){ + if (key == 's'){ + bSmooth = !bSmooth; + } + + if (key == 'x'){ + printInterval = !printInterval; + } + + + if (key == 'y'){ + drawData = !drawData; + } + + if (key == 'f'){ + ofToggleFullscreen(); + } + + if (key == 'h' || key == 'H'){ + hidePriorMode = !hidePriorMode;//drawData; + } + + + +if ( key =='a' || key == 'A' ) + { + + } + + if (key == ' '){ + drumTracker.paused = !drumTracker.paused; + } + + if (key == OF_KEY_RIGHT){ + screenToDraw++; + screenToDraw = screenToDraw % NUMBER_OF_SCREENS; + } + if (key == OF_KEY_LEFT){ + screenToDraw += NUMBER_OF_SCREENS - 1; + screenToDraw = screenToDraw % NUMBER_OF_SCREENS; + } + + if (key == ']') + drumTracker.beatDistribution.translateDistribution(ARRAY_SIZE / 4); + + if (key == '[') + drumTracker.beatDistribution.translateDistribution(-1*ARRAY_SIZE / 4); + + if (key == 'x'){ + bSnapshot = true; + } + + if (key == 'q') + drumTracker.adaptiveStandardDeviationMode = !drumTracker.adaptiveStandardDeviationMode; + +} + +/* +void testApp::sendMaxTempo(){ + ofxOscMessage m; + m.setAddress( "/tempo" ); + + //maxTempo = tempoDistribution.maximumIndex * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; + //would be introduced new in bayesian8 + maxTempo = drumTracker.tempoDistribution.getIntegratedEstimateIndex() * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; + maxTempo += tempoMinimum; + + + m.addFloatArg( maxTempo ); + sender.sendMessage( m ); + + printf("max tempo %f\n", maxTempo); + +} + +void testApp::sendMaxPhase(){ + + + // maxPhase = (beatDistribution.maximumIndex - (ARRAY_SIZE/2)) / ARRAY_SIZE; + maxPhase = (drumTracker.beatDistribution.getIntegratedEstimateIndex() - (ARRAY_SIZE/2)) / ARRAY_SIZE; + printf("\nphase index %f :: %i\n", drumTracker.beatDistribution.integratedEstimate , maxPhase); + ofxOscMessage m; + m.setAddress( "/phase" ); + m.addFloatArg( maxPhase ); + sender.sendMessage( m ); + + //beatCorrection = maxPhase * beatTimes.tatum / 4; +} + */ +//-------------------------------------------------------------- +void testApp::keyReleased (int key){ + +} + +//-------------------------------------------------------------- +void testApp::mouseMoved(int x, int y ){ + + mouseBPM = convertToBPM(drumTracker.tempoMinimum+ ((x * (drumTracker.tempoMaximum - drumTracker.tempoMinimum) ) / ofGetWidth() )) ; +} + +//-------------------------------------------------------------- +void testApp::mouseDragged(int x, int y, int button){ +} + +//-------------------------------------------------------------- +void testApp::mousePressed(int x, int y, int button){ +} + + +//-------------------------------------------------------------- +void testApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::windowResized(int w, int h){ + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight(); + stepSize = screenWidth / (float)(ARRAY_SIZE); +} + +double testApp::convertToBPM(double interval){ +//interval is in ms and is the tatum interval - eighth nbote - so 250ms for 120bpm +return (30000/interval); + +} +/* +noyt needed? +float testApp::tempoIndexToMsec(int index){ +float msec; +msec = index * (tempoMaximum - tempoMinimum) / ARRAY_SIZE; +msec += tempoMinimum; +return msec; +} + +float testApp::beatIndexToMsec(int index){ +float msec; +msec = index * maxTempo / ARRAY_SIZE; +msec += tempoMinimum; +return msec; +} +*/ +/* + + bool testApp::filterBeatTime(double newBeatTime){ + bool newBeatFound = false; + if ((newBeatTime - beatTimes.lastBeatTime) > 20 || beatTimes.lastBeatTime == 0){ + + crossUpdateArrays((float)(newBeatTime - beatTimes.lastBeatTime)); + beatTimes.lastBeatTime = newBeatTime; + newBeatFound = true; + } + return newBeatFound; + } + + void testApp::crossUpdateArrays(float timeInterval){ + + int finalBeatIndex, tmpTempoIndex, startBeatIndex; + //finalBeat has contribution from BEAT[finalBeat + INT.k] * TEMPO[Max_tempo + k] where INT = INTERVAL + float interval; + interval = timeInterval / maxTempo;//beatTimes.tatum; + tempoDistribution.resetMaximumPosterior(); + beatDistribution.resetMaximumPosterior(); + + + int tmpBeatIndex; + //&& interval > 0.8 idea? + if (timeInterval > 0 && timeInterval < 12000 ){//need between 0 and 12 seconds only to update + + for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ + + tmpArray[tmpBeatIndex] = 0; + float minusMsecToMakeUp = beatIndexToMsec(tmpBeatIndex) / interval; + float plusMsecToMakeUp = beatIndexToMsec(ARRAY_SIZE - tmpBeatIndex) / interval; + float convertMsecToTempoIndex = ARRAY_SIZE / (tempoMaximum - tempoMinimum) ; + + + int minTempoIndex = -1 * (int)(minusMsecToMakeUp * convertMsecToTempoIndex); + int maxTempoIndex = (int)(plusMsecToMakeUp * convertMsecToTempoIndex); + + + if (tmpBeatIndex == beatDistribution.maximumIndex){ + minTmpDebug = tempoDistribution.maximumIndex + minTempoIndex; + maxTmpDebug = tempoDistribution.maximumIndex + maxTempoIndex; + debugArray[0] = beatDistribution.maximumIndex;// + debugArray[1] = timeInterval; + debugArray[2] = interval;//beatDistribution.maximumIndex; + debugArray[3] = tempoDistribution.maximumIndex; + } + + for (tmpTempoIndex = minTempoIndex;tmpTempoIndex <= maxTempoIndex;tmpTempoIndex++){ + + if ((tempoDistribution.maximumIndex + tmpTempoIndex) >= 0 + && (tempoDistribution.maximumIndex + tmpTempoIndex) < ARRAY_SIZE + && (tmpBeatIndex - (int)(interval*tmpTempoIndex)) >= 0 + && (tmpBeatIndex - (int)(interval*tmpTempoIndex))< ARRAY_SIZE){ + tmpArray[tmpBeatIndex] += beatDistribution.posterior[tmpBeatIndex - (int)(interval*tmpTempoIndex)] * tempoDistribution.posterior[(int)tempoDistribution.maximumIndex + tmpTempoIndex]; + } + }//end for tmpTmepo + + + + } + + float tmpFloat; + for (tmpBeatIndex = 0;tmpBeatIndex < ARRAY_SIZE;tmpBeatIndex++){ + //debug - dont actually update:: + + tmpFloat = beatDistribution.posterior[tmpBeatIndex]; + beatDistribution.posterior[tmpBeatIndex] = tmpArray[tmpBeatIndex]; + tmpArray[tmpBeatIndex] = tmpFloat; + } + beatDistribution.renormaliseArray(&beatDistribution.posterior[0], ARRAY_SIZE); + + } //end if + + + } + + + void testApp::updateTempoProcess(double cpuTime, string onsetDescription){ + + if (filterBeatTime(cpuTime) == true){ + //checks for no repeat + + if (onsetDescription == "kick") + beatTimes.addBeatTime(cpuTime, 1); + else + beatTimes.addBeatTime(cpuTime, 2); + + + //recalculate the distribution + int altIndex = 0; + + tempoDataString = "Tatum :"; + tempoDataString += ofToString(beatTimes.tatum, 2); + tempoDataString += " BPM "; + tempoDataString += ofToString((double)30000/beatTimes.tatum, 2); + + timeString = "Last BEAT "; + timeString += ofToString(beatTimes.lastBeatTime); + timeString += " CLICK "; + timeString += ofToString(beatTimes.lastClickTime); + timeString += " DIFDF "; + timeString += ofToString(beatTimes.timeDifference); + timeString += " segment "; + timeString += ofToString(beatTimes.beatSegment); + + + for (altIndex = 0;altIndex< 16;altIndex++){ + tempoInterval = beatTimes.intervalDifferences[beatTimes.index][altIndex]; + integerMultipleOfTatum = beatTimes.relativeIntervals[altIndex][1]; + + + ///NEW VERSION + tempoUpdateStrings[altIndex] = ""; + double timeInterval = beatTimes.beatTimes[beatTimes.index] - beatTimes.beatTimes[altIndex]; + //raw time difference + beatTimes.intervalDifferences[beatTimes.index][altIndex] = 0; + beatTimes.intervalUsed[beatTimes.index][altIndex] = false; + + if (onsetType == "kick") + beatTimes.OnsetIsKick[beatTimes.index] = true; + else + beatTimes.OnsetIsKick[beatTimes.index] = false; + + + + if (!accompanimentStarted){ + //if we need to find tempo and start use this method + //we have 'started' once std dev is sufficiently low + + updateTempoIfWithinRange(timeInterval);//taken as being the tatum interval + + + + for (int i = 1;i <= 4;i++){ + //we test the main beats and the two bar (16 tatum intervals) + + double testInterval = timeInterval / 2*i;//pow(2, i);//pow(2.0, i); + + if (updateTempoIfWithinRange(testInterval)){ + printf("test time %f, beats %i\n", testInterval, i); + + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + //xx what if two within range here? + + tempoUpdateStrings[altIndex] = "Tempo Updates ("; + tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); + tempoUpdateStrings[altIndex] += ") : ["; + tempoUpdateStrings[altIndex] += ofToString(altIndex); + tempoUpdateStrings[altIndex] += "]] : "; + tempoUpdateStrings[altIndex] += ofToString(timeInterval); + tempoUpdateStrings[altIndex] += ", ioi:"; + tempoUpdateStrings[altIndex] += ofToString(i); + //tempoUpdateStrings[altIndex] += ""; + + } + + } + + double testInterval = timeInterval / 16;//pow(2, i);//pow(2.0, i); + if (updateTempoIfWithinRange(testInterval)){ + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + } + + }else{ + //OLD VERSON + //THIS USES THE CURRENT TEMPO ESTIMATE TO DECIDE WHAT THE BEST INTERVAL IS + //&& integerMultipleOfTatum % 2 == 0 removed below XXX put back + if (altIndex != beatTimes.index && integerMultipleOfTatum < 17 + && integerMultipleOfTatum > 0 && beatTimes.startIndex > 8//beattimes.index > 8 - the start + && integerMultipleOfTatum%2 == 0){//mod 2 - i.e. proper beat intervals only + + double testInterval = timeInterval / integerMultipleOfTatum; + + if (updateTempoIfWithinRange(testInterval)){ + + beatTimes.intervalUsed[beatTimes.index][altIndex] = true; + beatTimes.intervalDifferences[beatTimes.index][altIndex] = testInterval; + + if (paused == false){ + tempoUpdateStrings[altIndex] = "Tempo Updates : ("; + tempoUpdateStrings[altIndex] += ofToString(beatTimes.index, 0); + tempoUpdateStrings[altIndex] += ") : ["; + tempoUpdateStrings[altIndex] += ofToString(altIndex, 0); + tempoUpdateStrings[altIndex] += "] :: "; + tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); + tempoUpdateStrings[altIndex] += " intervals :: "; + tempoUpdateStrings[altIndex] += ofToString(tempoInterval); + tempoUpdateStrings[altIndex] += " ms."; + // tempoUpdateStrings[altIndex] += ", ioi:"; + + // tempoUpdateStrings[altIndex] += ofToString(integerMultipleOfTatum); + + + + + }//end if not paused + + + }//end if good interval to update + + }//end if not same index etc + + + } + + + + }//end for all intervals + + sendMaxTempo(); + }//end if new beat time + double tempoEstimate = tempoDistribution.getIntegratedEstimateIndex(); + tempoDistribution.calculateStandardDeviation(); + tempoStdDev = tempoDistribution.standardDeviation; + + } + + + bool testApp::updateTempoIfWithinRange(double timeInterval){ + + bool updated = false; + + if (timeInterval > tempoMinimum && timeInterval < tempoMaximum ){ + calculateTempoUpdate(timeInterval); + updated = true; + } + + return updated; + } + + + */ +//end +/* +void testApp::calculateTempoUpdate(double tempoInterval){ + + + tempoDistribution.resetPrior(); + //need to relook at likelihood for the tempo distribution - not the same as.... + tempoDistribution.setGaussianLikelihood(ARRAY_SIZE * (tempoInterval-tempoMinimum)/(tempoMaximum - tempoMinimum), tempoDistribution.likelihoodStdDev); + tempoDistribution.calculatePosterior(); + tempoDistribution.renormalisePosterior(); + + //did take pic of screen here - see initialiser4 +} +*/ + diff -r 000000000000 -r 0f9165f96bdb src/testApp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.h Tue Aug 30 20:16:35 2011 +0100 @@ -0,0 +1,159 @@ +#ifndef _TEST_APP +#define _TEST_APP + + + +#include "ofMain.h" +#include "ofxOsc.h" +//#include "bayesianArray.h" +//#include "beatTempo.h" +#include "BayesDrumTracker.h" + +// listen on port 12345 +#define PORT 12345 +#define NUM_MSG_STRINGS 45 +#define HOST "localhost" +#define ARRAY_SIZE 240//need to replace this with const int in drumtracker + +#define NUMBER_OF_SCREENS 8 + +class testApp : public ofBaseApp{ + + public: + + void setup(); + void update(); + void draw(); + void drawBayesianDistribution(); + void drawTempoData(); + void drawTempoDistribution(); + void drawRestrictedTempoDistribution(int tmpMin, int tmpMax); + + void drawBeatMap(); + void drawNormalisedLikelihood(); + void drawBeatProbabilityDistribution(); + void drawPosterior(); + void printBayesianData(); + void drawGreyscaleBayesianDistribution(); + void drawGreyscaleTempoDistribution(double tempoInterval); + void drawTempoInfo(); + + void resetParameters(); + void takePictureOfScreen(); + + void crossUpdateArrays(float timeInterval); + void updateTempoProcess(double cpuTime, string onsetType); + + void sendMaxTempo(); + void sendMaxPhase(); + double convertToBPM(double interval); + bool filterBeatTime(double newBeatTime); + +// float beatIndexToMsec(int index); +// float tempoIndexToMsec(int index); + + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + + void setGaussianLikelihood(float mean, float StdDev); + void setGaussianPrior(float mean, float StdDev); + void calculatePosterior(); + void renormalisePosterior(); + float getMaximum(float *ptr, int length); + void renormaliseArray(float *ptr, int length); + void updateOSCmessages(); + void resetPrior(); + void decayPosterior(); + void translateDistribution(int translationIndex); + void setBeatDistribution(int beatPosition); + void calculateTempoUpdate(double tempoInterval); + bool updateTempoIfWithinRange(double timeInterval); + + float* getMaximumEstimate(float *ptr, int length); + void drawTempoDataPoints(const int& tmpMin, const int& tmpMax, const float& tmpStepSize); + int xcoordinateFromTempoDataPoint(float f); + int xcoordinateFromRestrictedTempoDataPoint(float f, const int& tmpMin, const int& tmpMax); + + float arrayToMsecScaleFactor;// = (tempoMaximum - tempoMinimum)/ ARRAY_SIZE;//turns array into ms + + + + int tempoWindowMinimum, tempoWindowMaximum, tempoWindowWidth; + + ofTrueTypeFont font; + + ofxOscReceiver receiver; + string msg_string, debugString, kickString; + + bool bSmooth; + // float kickError, snareError; + // float testArray[5]; + + // float prior [ARRAY_SIZE]; + // float posterior [ARRAY_SIZE]; + // float likelihood [ARRAY_SIZE]; + // float likelihoodMean, likelihoodStdDev, likelihoodNoise, stepSize; + // float maximumEstimate; + // float maximumTest, posteriorDecayRate, maximumIndex; + // float eighthNoteProportion; + + float stepSize; + int screenWidth, screenHeight; + + bool printInterval, paused; + bool drawData, hidePriorMode; + + + /* + bayesianArray beatDistribution; + + double tempoMinimum, tempoMaximum; + double tempoInterval; + beatTempo beatTimes; +*/ + //double tempoInterval; + float mouseBPM; +// int correctBeatBy; +// string tempoUpdateStrings[16]; +// string tempoDataString; + + private: + + // ofxOscSender sender; + + //float noiseFactor, stdDevFactor; + // int minTmpDebug, maxTmpDebug; + + // float correctionFactor; + + + +// string onsetType; +// string timeString; +// double cpuBeatTime; + +// double cpuClockTime; + int screenToDraw; +// double posteriorMaximum; +// bool adaptiveStandardDeviationMode; + + bool bSnapshot; + int snapCounter; + ofImage img; + + // double tempoStdDev; +// bool accompanimentStarted; +// bool setDistributionOnStartTempo; +// int integerMultipleOfTatum; + + BayesDrumTracker drumTracker; + +}; + +#endif +