Mercurial > hg > midi-score-follower
changeset 2:5581023e0de4
Added separate CannamMidiFileLoader class to handle the loading in.
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Fri, 19 Aug 2011 01:26:40 +0100 |
parents | 1a32ce016bb9 |
children | de86d77f2612 |
files | src/BayesianArrayStructure.cpp src/BayesianArrayStructure.h src/CannamMidiFileLoader.cpp src/CannamMidiFileLoader.h src/DynamicVector.cpp src/DynamicVector.h src/midiEventHolder.cpp src/midiEventHolder.h src/testApp.cpp src/testApp.h |
diffstat | 10 files changed, 548 insertions(+), 85 deletions(-) [+] |
line wrap: on
line diff
--- a/src/BayesianArrayStructure.cpp Thu Aug 18 23:27:42 2011 +0100 +++ b/src/BayesianArrayStructure.cpp Fri Aug 19 01:26:40 2011 +0100 @@ -16,16 +16,16 @@ likelihood.createVector(1); posterior.createVector(1); - - tmpPrior.createVector(240); - tmpPrior.addGaussianShape(100, 40, 1); - tmpPrior.addGaussianShape(200, 10, 0.2); - tmpPrior.translateDistribution(20); - + lastEventTime = ofGetElapsedTimeMillis(); - speedDecayWidth = 20; - speedDecayAmount = 10; + /* + tmpPrior.createVector(240); + tmpPrior.addGaussianShape(100, 40, 1); + tmpPrior.addGaussianShape(200, 10, 0.2); + tmpPrior.translateDistribution(20); + */ + tmpBestEstimate = 0; } BayesianArrayStructure::BayesianArrayStructure(int length){ @@ -34,6 +34,8 @@ prior.createVector(length); likelihood.createVector(length); posterior.createVector(length); + + lastEventTime = 0; } @@ -46,6 +48,7 @@ likelihood.createVector(length); posterior.createVector(length); + acceleration.createVector(length); } @@ -57,13 +60,24 @@ relativeSpeedPosterior.zero(); relativeSpeedLikelihood.zero(); - relativeSpeedPosterior.addGaussianShape(40, 5, 0.6); + //relativeSpeedPosterior.addGaussianShape(40, 5, 0.6); - relativeSpeedPosterior.addGaussianShape(100, 5, 0.8); + relativeSpeedPosterior.addGaussianShape(100, 20, 0.8); +// relativeSpeedPosterior.addGaussianShape(50, 1, 0.8); + +// relativeSpeedPosterior.addToIndex(100, 1); + //relativeSpeedPosterior.addToIndex(50, 1); relativeSpeedPosterior.renormalise(); relativeSpeedPosterior.getMaximum(); - acceleration.addGaussianShape(2000, 20, 0.8); + prior.zero(); + posterior.zero(); +// posterior.offset = - 200; +// posterior.addGaussianShape(200, 40, 1); + posterior.addToIndex(0, 1); + posterior.renormalise(); + + //acceleration.addGaussianShape(2000, 20, 0.8); } @@ -73,32 +87,44 @@ relativeSpeedPrior.createVector(length); relativeSpeedLikelihood.createVector(length); relativeSpeedPosterior.createVector(length); - + tmpPosteriorForStorage.createVector(length); } + void BayesianArrayStructure::setRelativeSpeedScalar(double f){ relativeSpeedPrior.scalar = f; relativeSpeedPosterior.scalar = f; relativeSpeedLikelihood.scalar = f; } + +void BayesianArrayStructure::setPositionDistributionScalar(double f){ + if (f > 0){ + prior.scalar = f; + posterior.scalar = f; + likelihood.scalar = f; + } +} + void BayesianArrayStructure::simpleExample(){ //simple example - prior.addGaussianShape(50, 10, 1); - prior.addGaussianShape(150, 30, 0.3); - prior.addGaussianShape(250, 30, 0.2); - likelihood.addGaussianShape(90, 20, 0.6); - likelihood.addConstant(0.02); - posterior.doProduct(prior, likelihood); +// prior.addGaussianShape(50, 10, 1); +// prior.addGaussianShape(150, 30, 0.3); +// prior.addGaussianShape(250, 30, 0.2); + +// likelihood.addGaussianShape(90, 20, 0.6); +// likelihood.addConstant(0.02); +// posterior.doProduct(prior, likelihood); // relativeSpeedPosterior.addToIndex(100, 1); // relativeSpeedPosterior.addToIndex(40, 0.7); - relativeSpeedPosterior.addGaussianShape(100, 20, 1); -// relativeSpeedPosterior.addGaussianShape(10, 2, 0.5); + +// relativeSpeedPosterior.addGaussianShape(100, 2, 1); +// relativeSpeedPosterior.addGaussianShape(40, 2, 0.5); relativeSpeedPosterior.getMaximum(); - + relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior); } void BayesianArrayStructure::copyPriorToPosterior(){ @@ -108,39 +134,82 @@ } } +void BayesianArrayStructure::setStartPlaying(){ + lastEventTime = 0;//ofGetElapsedTimeMillis(); + bestEstimate = 0; + lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); + + resetArrays(); +} + void BayesianArrayStructure::resetArrays(){ + //called when we start playing + prior.zero(); likelihood.zero(); - prior.addGaussianShape(0, 80, 1); + posterior.zero(); + + updateCounter = 0; + + posterior.offset = 0; + setNewDistributionOffsets(0); + + int zeroIndex = posterior.getRealTermsAsIndex(0); + + posterior.addGaussianShape(zeroIndex, 500, 1); + // posterior.addToIndex(0, 1); likelihood.addConstant(1); - posterior.zero(); - posterior.addGaussianShape(0, 60, 1); - setNewDistributionOffsets(0); + + updateCounter = 0; + bestEstimate = 0; // lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); } +void BayesianArrayStructure::zeroArrays(){ + prior.zero(); + likelihood.zero(); + posterior.zero(); + + relativeSpeedPrior.zero(); + relativeSpeedPosterior.zero(); + relativeSpeedLikelihood.zero(); + +} + + +void BayesianArrayStructure::updateTmpBestEstimate(const double& timeDifference){ + //input is the time since the start of playing + +// double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime; + + tmpBestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDifference*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); + // + printf("tmp best %f and best %f time diff %f posterior MAP %f\n", tmpBestEstimate, bestEstimate, timeDifference, posterior.getIndexInRealTerms(posterior.MAPestimate)); + //lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); +} + void BayesianArrayStructure::updateBestEstimate(){ - double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime; +// double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;// + double timeDiff = ofGetElapsedTimeMillis() - lastBestEstimateUpdateTime; + bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); - bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); - // - //lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); +// bestEstimate = tmpBestEstimate; } void BayesianArrayStructure::calculatePosterior(){ - posterior.doProduct(prior, likelihood); + //posterior.doProduct(prior, likelihood); + + int i; + for (i = 0;i < posterior.length;i++){ + posterior.array[i] = likelihood.array[i] * prior.array[i]; + } + + posterior.renormalise(); - /* - int i; - for (i = 0;i < prior.length;i++){ - // printf("priori [%i] is %f\n", i, prior[i]); - *(posterior+i) = *(prior+i); - // posterior[i] = likelihood[i] * prior[i]; - } - */ + } @@ -151,7 +220,7 @@ void BayesianArrayStructure::setNewDistributionOffsets(const double& newOffset){ prior.offset = newOffset; likelihood.offset = newOffset; -// posterior.offset = newOffset; + //posterior.offset = newOffset; } @@ -175,10 +244,10 @@ if (speed.array[i] != 0){ - // printf("speed [%i] gives %f moved %i\n", i, speedValue, distanceMoved); + // printf("speed [%i] gives %f moved %i in %f units \n", i, speedValue, distanceMoved, timeDifferenceInPositionVectorUnits); for (int postIndex = 0;postIndex < position.arraySize;postIndex++){ - //old posterior contributing to new prior + //old posterior contributing to new prior int newPriorIndex = postIndex + position.offset - prior.offset + distanceMoved; if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){ prior.addToIndex(newPriorIndex, position.array[postIndex]*speed.array[i]); @@ -189,11 +258,38 @@ }//if not zero }//end speed - + updateCounter++; prior.renormalise(); } + +void BayesianArrayStructure::addGaussianNoiseToSpeedPosterior(const double& std_dev){ + tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior); + + for (int i = 0;i < relativeSpeedPosterior.length;i++){ + tmpPosteriorForStorage.addGaussianShape(i, std_dev, relativeSpeedPosterior.array[i]); + } + + tmpPosteriorForStorage.renormalise(); + + relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage); +} + + +void BayesianArrayStructure::addTriangularNoiseToSpeedPosterior(const double& std_dev){ + tmpPosteriorForStorage.copyFromDynamicVector(relativeSpeedPosterior); + + for (int i = 0;i < relativeSpeedPosterior.length;i++){ + //adding a linear amount depending on distance + tmpPosteriorForStorage.addTriangularShape(i, std_dev*2.0, relativeSpeedPosterior.array[i]); + } + + tmpPosteriorForStorage.renormalise(); + + relativeSpeedPosterior.copyFromDynamicVector(tmpPosteriorForStorage); +} + void BayesianArrayStructure::calculateNewPriorOffset(const double& timeDifference){ double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); @@ -246,7 +342,7 @@ //set new likelihood relativeSpeedLikelihood.zero(); - relativeSpeedLikelihood.addConstant(0.05); + relativeSpeedLikelihood.addConstant(speedLikelihoodNoise); relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5*matchFactor); @@ -303,14 +399,13 @@ //bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200); int displaySize = prior.arraySize; - ofSetColor(255,0,0); + ofSetColor(0,0,255); prior.drawVector(0, displaySize); ofSetColor(0,255,0); likelihood.drawVector(0, displaySize); - ofSetColor(0,0,255); + ofSetColor(255,0,255); posterior.drawVector(0, displaySize); - ofSetColor(255,255,0); - relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize); + // ofSetColor(255,255,255); // tmpPrior.drawVector(0,300); @@ -328,6 +423,9 @@ ofSetColor(255,255,0); relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize); + ofSetColor(0,0,255); + tmpPosteriorForStorage.drawVector(0, tmpPosteriorForStorage.arraySize); + ofSetColor(255,255, 255); ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen
--- a/src/BayesianArrayStructure.h Thu Aug 18 23:27:42 2011 +0100 +++ b/src/BayesianArrayStructure.h Fri Aug 19 01:26:40 2011 +0100 @@ -6,6 +6,9 @@ * Copyright 2011 QMUL. All rights reserved. * */ +#ifndef BAYESIAN_ARRAY_STRUCTURE +#define BAYESIAN_ARRAY_STRUCTURE + #include "ofMain.h" //#include "DynamicBayesianArray.h" @@ -27,6 +30,8 @@ void resetSize(int length); void resetArrays(); void simpleExample(); + void setStartPlaying(); + void zeroArrays(); double screenWidth; @@ -34,9 +39,11 @@ // DynamicBayesianArray bayesArray; double lastEventTime; + double likelihoodNoise; + double speedLikelihoodNoise; DynamicVector tmpPrior; - + DynamicVector tmpPosteriorForStorage; DynamicVector prior; DynamicVector posterior; DynamicVector likelihood; @@ -46,11 +53,20 @@ DynamicVector relativeSpeedPosterior; DynamicVector acceleration; + double tmpBestEstimate; + void updateTmpBestEstimate(const double& timeDifference); + + int updateCounter; + + void setPositionDistributionScalar(double f); + void resetSpeedToOne(); + void addGaussianNoiseToSpeedPosterior(const double& std_dev); + void addTriangularNoiseToSpeedPosterior(const double& std_dev); double bestEstimate; void updateBestEstimate(); -// double lastBestEstimateUpdateTime; + double lastBestEstimateUpdateTime; double speedDecayWidth, speedDecayAmount; void decaySpeedDistribution(double timeDifference); @@ -69,4 +85,4 @@ void crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference); }; - +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/CannamMidiFileLoader.cpp Fri Aug 19 01:26:40 2011 +0100 @@ -0,0 +1,236 @@ +/* + * CannamMidiFileLoader.cpp + * midi-score-follower + * + * Created by Andrew on 19/08/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "MIDIFileReader.h" +#include "CannamMidiFileLoader.h" + +int CannamMidiFileLoader::loadFile(std::string& filename, midiEventHolder& myMidiEvents){ + + + myMidiEvents.clearAllEvents(); + + //int main(int argc, char **argv) + //{ + // if (argc != 2) { + // cerr << "Usage: midifile <file.mid>" << endl; + // return 1; + // } + + // std::string filename = midiFileName;//argv[1]; + + MIDIFileReader fr(filename); + + if (!fr.isOK()) { + std::cerr << "Error: " << fr.getError().c_str() << std::endl; + return 1; + } + + MIDIComposition c = fr.load(); + + switch (fr.getFormat()) { + case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break; + case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break; + case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break; + default: cout << "Format: Unknown MIDI file format?" << endl; break; + } + + cout << "Tracks: " << c.size() << endl; + + int td = fr.getTimingDivision(); + if (td < 32768) { + cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl; + + myMidiEvents.pulsesPerQuarternote = fr.getTimingDivision(); + } else { + int frames = 256 - (td >> 8); + int subframes = td & 0xff; + cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl; + } + + for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) { + + cout << "Start of track: " << i->first+1 << endl; + + for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { + + unsigned int t = j->getTime(); + int ch = j->getChannelNumber(); + + if (j->isMeta()) { + int code = j->getMetaEventCode(); + string name; + bool printable = true; + switch (code) { + + case MIDI_END_OF_TRACK: + cout << t << ": End of track" << endl; + break; + + case MIDI_TEXT_EVENT: name = "Text"; break; + case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break; + case MIDI_TRACK_NAME: name = "Track name"; break; + case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break; + case MIDI_LYRIC: name = "Lyric"; break; + case MIDI_TEXT_MARKER: name = "Text marker"; break; + case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break; + case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break; + case MIDI_CUE_POINT: name = "Cue point"; break; + case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break; + case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break; + case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break; + + case MIDI_SET_TEMPO: + { + int m0 = j->getMetaMessage()[0]; + int m1 = j->getMetaMessage()[1]; + int m2 = j->getMetaMessage()[2]; + long tempo = (((m0 << 8) + m1) << 8) + m2; + + cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl; + myMidiEvents.tempo = 60000000.0 / double(tempo); + myMidiEvents.period = double(tempo)/1000.0; + + printf("period double is %f\n", myMidiEvents.period); + } + break; + + case MIDI_TIME_SIGNATURE: + { + int numerator = j->getMetaMessage()[0]; + int denominator = 1 << (int)j->getMetaMessage()[1]; + + cout << t << ": Time signature: " << numerator << "/" << denominator << endl; + } + + case MIDI_KEY_SIGNATURE: + { + int accidentals = j->getMetaMessage()[0]; + int isMinor = j->getMetaMessage()[1]; + bool isSharp = accidentals < 0 ? false : true; + accidentals = accidentals < 0 ? -accidentals : accidentals; + cout << t << ": Key signature: " << accidentals << " " + << (isSharp ? + (accidentals > 1 ? "sharps" : "sharp") : + (accidentals > 1 ? "flats" : "flat")) + << (isMinor ? ", minor" : ", major") << endl; + } + + } + + + if (name != "") { + if (printable) { + cout << t << ": File meta event: code " << code + << ": " << name << ": \"" << j->getMetaMessage() + << "\"" << endl; + } else { + cout << t << ": File meta event: code " << code + << ": " << name << ": "; + for (int k = 0; k < j->getMetaMessage().length(); ++k) { + cout << (int)j->getMetaMessage()[k] << " "; + } + } + } + continue; + } + + switch (j->getMessageType()) { + + case MIDI_NOTE_ON: + cout << t << ": Note: channel " << ch + << " duration " << j->getDuration() + << " pitch " << j->getPitch() + << " velocity " << j->getVelocity() + << "event time " << myMidiEvents.getEventTimeMillis(t) << endl; + v.clear(); + v.push_back(t); + v.push_back(j->getPitch()); + v.push_back(j->getVelocity()); + v.push_back(j->getDuration()); + myMidiEvents.recordedNoteOnMatrix.push_back(v); + myMidiEvents.recordedEventTimes.push_back(myMidiEvents.getEventTimeMillis(t)); + break; + + case MIDI_POLY_AFTERTOUCH: + cout << t << ": Polyphonic aftertouch: channel " << ch + << " pitch " << j->getPitch() + << " pressure " << j->getData2() << endl; + break; + + case MIDI_CTRL_CHANGE: + { + int controller = j->getData1(); + string name; + switch (controller) { + case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break; + case MIDI_CONTROLLER_VOLUME: name = "Volume"; break; + case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break; + case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break; + case MIDI_CONTROLLER_PAN: name = "Pan"; break; + case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break; + case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break; + case MIDI_CONTROLLER_RELEASE: name = "Release"; break; + case MIDI_CONTROLLER_ATTACK: name = "Attack"; break; + case MIDI_CONTROLLER_FILTER: name = "Filter"; break; + case MIDI_CONTROLLER_REVERB: name = "Reverb"; break; + case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break; + case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break; + case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break; + case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break; + case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break; + case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break; + case MIDI_CONTROLLER_RESET: name = "Reset"; break; + case MIDI_CONTROLLER_LOCAL: name = "Local"; break; + case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break; + } + cout << t << ": Controller change: channel " << ch + << " controller " << j->getData1(); + if (name != "") cout << " (" << name << ")"; + cout << " value " << j->getData2() << endl; + } + break; + + case MIDI_PROG_CHANGE: + cout << t << ": Program change: channel " << ch + << " program " << j->getData1() << endl; + break; + + case MIDI_CHNL_AFTERTOUCH: + cout << t << ": Channel aftertouch: channel " << ch + << " pressure " << j->getData1() << endl; + break; + + case MIDI_PITCH_BEND: + cout << t << ": Pitch bend: channel " << ch + << " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl; + break; + + case MIDI_SYSTEM_EXCLUSIVE: + cout << t << ": System exclusive: code " + << (int)j->getMessageType() << " message length " << + j->getMetaMessage().length() << endl; + break; + + + } + + + } + + + } + + + + +}//end cannam midi main + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/CannamMidiFileLoader.h Fri Aug 19 01:26:40 2011 +0100 @@ -0,0 +1,27 @@ +/* + * CannamMidiFileLoader.h + * midi-score-follower + * + * Created by Chris Cannam on 19/08/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#ifndef CANNAM_MIDI_FILE_LOADER +#define CANNAM_MIDI_FILE_LOADER + +#include "MIDIFileReader.h" +//#include "MIDIEvent.h" +#include "midiEventHolder.h" +using namespace MIDIConstants; + +class CannamMidiFileLoader{ + +public: + int loadFile(std::string& filename, midiEventHolder& myMidiEvents); + + typedef std::vector<int> IntVector; + IntVector v; + +}; +#endif \ No newline at end of file
--- a/src/DynamicVector.cpp Thu Aug 18 23:27:42 2011 +0100 +++ b/src/DynamicVector.cpp Fri Aug 19 01:26:40 2011 +0100 @@ -7,6 +7,7 @@ * */ + #include "DynamicVector.h" DynamicVector::DynamicVector(){ @@ -51,6 +52,20 @@ return max; } +double DynamicVector::getIntegratedEstimate(){ + //returns the index of the integrated average - where the probability distribution is centred + double estimate = 0; + double integratedTotal = 0; + for (int i = 0;i < length;i++){ + estimate += array[i]*i; + integratedTotal += array[i]; + } + if (integratedTotal > 0){ + estimate /= integratedTotal; + } + return estimate; +} + void DynamicVector::zero(){ for (int i = 0;i < array.size();i++) array[i] = 0; @@ -99,12 +114,22 @@ void DynamicVector::addGaussianShape(double mean, double StdDev, double factor){ int i; + factor *= (1/(StdDev*sqrt(2*PI))); for (i=0;i<array.size();i++){ - array[i] += factor*(1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); + array[i] += factor*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); } //printf("ADDED GAUSSIAN SHAPE %i\n", (int)array.size()); } +void DynamicVector::addTriangularShape(double mean, double width, double factor){ + int i; + + for (i= max(0., (double)(mean - width));i < min((mean+width), (double)array.size());i++){ + array[i] += factor * abs(i - mean) / mean; + } + +} + void DynamicVector::addConstant(double value){ for (int i=0;i<array.size();i++){ array[i] += value;
--- a/src/DynamicVector.h Thu Aug 18 23:27:42 2011 +0100 +++ b/src/DynamicVector.h Fri Aug 19 01:26:40 2011 +0100 @@ -25,11 +25,14 @@ typedef std::vector<double> DoubleVector; DoubleVector array; double getMaximum(); + double getIntegratedEstimate(); + void drawVector(const int& minIndex, const int& maxIndex); void drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex); void addConstant(double value); void addGaussianShape(double mean, double stddev, double factor); + void addTriangularShape(double mean, double width, double factor); void addToIndex(int index, double constant); void doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo);
--- a/src/midiEventHolder.cpp Thu Aug 18 23:27:42 2011 +0100 +++ b/src/midiEventHolder.cpp Fri Aug 19 01:26:40 2011 +0100 @@ -27,16 +27,25 @@ minimumMatchSpeed = 0.7; maximumMatchSpeed = 1.3; + likelihoodWidth = 100; - likelihoodToNoiseRatio = 50; + likelihoodToNoiseRatio = 0.02; - matchWindowWidth = 4000;//window size for matching in ms + bayesStruct.speedLikelihoodNoise = 0.05;//was 0.05 + bayesStruct.speedDecayWidth = 20; + bayesStruct.speedDecayAmount = 10; + + + matchWindowWidth = 8000;//window size for matching in ms bayesStruct.resetSize(matchWindowWidth); + bayesStruct.setPositionDistributionScalar(1); + bayesStruct.resetSpeedSize(200); bayesStruct.setRelativeSpeedScalar(0.01); bayesStruct.relativeSpeedPrior.getMaximum(); - bayesStruct.simpleExample(); + //bayesStruct.simpleExample(); + noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); } @@ -44,6 +53,8 @@ void midiEventHolder::reset(){ + //called when we start playing + noteArrayIndex = 0; tickLocation = 0; lastPeriodUpdateTime = ofGetElapsedTimeMillis(); @@ -108,18 +119,28 @@ //would update the arrays at this point to show where out current location (phase) and tempo is. - double timeNow = ofGetElapsedTimeMillis() - startTime; - recentNoteOnTime = timeNow; +// double timeNow = ofGetElapsedTimeMillis() - startTime; + double timeNow = timePlayed;// - startTime; + recentNoteOnTime = timePlayed; - printf("Max time %f OF time %f \n", timePlayed, timeNow); +// printf("Max time %f OF time %f \n", timePlayed, timeNow); playedEventTimes.push_back(timePlayed); - double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; +// double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; + double timeDifference = timePlayed - bayesStruct.lastEventTime; + printf("note %i played at %f and last event %f\n", pitch, timePlayed, bayesStruct.lastEventTime); //addnoise to the tempo distribution - bayesStruct.decaySpeedDistribution(timeDifference); - + //bayesStruct.decaySpeedDistribution(timeDifference); + if (timeDifference > 50){ + bayesStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10 / 100.); +// bayesStruct.addTriangularNoiseToSpeedPosterior(timeDifference * 10 / 100.); + } + + bayesStruct.updateTmpBestEstimate(timeDifference);// debug - didnt work bayesStruct.bestEstimate = bayesStruct.tmpBestEstimate; + bayesStruct.updateBestEstimate(); + bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); // double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis @@ -149,8 +170,8 @@ //be able to draw the prior in correct location relative to the midi notes + //this calculates the cross update of all possible speeds and all possible positions bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); -// bayesStruct.crossUpdateArrays(bayesStruct.prior, bayesStruct.relativeSpeedPosterior, timeDifference); timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); @@ -160,7 +181,8 @@ // bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); //trying to switch to prior - bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); + //bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); + bayesStruct.lastEventTime = timePlayed; //do the cross update to find current posterior for location // totalConfidence= 0; @@ -171,7 +193,7 @@ //having found matches we have matches for new note and matches for previous notes findLocalTempoPairs(); - + //bayesStruct.addGaussianNoiseToSpeedPosterior(10); } @@ -197,7 +219,7 @@ bayesStruct.likelihood.offset = bayesStruct.prior.offset; bayesStruct.likelihood.zero();//set to zero - + double quantity = likelihoodToNoiseRatio / numberOfMatches; for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); @@ -206,11 +228,11 @@ // double confidenceMeasure = 0; // if (totalConfidence > 0) // confidenceMeasure = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[matchesFound[i]])/totalConfidence; - - bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, 0.5 * likelihoodToNoiseRatio );//* confidenceMeasure + + bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, quantity);//* confidenceMeasure }//end if } - bayesStruct.likelihood.addConstant(0.01); + bayesStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesStruct.likelihood.length); } int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ @@ -290,13 +312,16 @@ double speedRatio = recordedTimeDifference / playedTimeDifference; if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ - printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); + /* + printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); printf("[%i] :: ", recordedPreviousIndex); printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); printf("update on speed ratio %f\n", speedRatio); + */ // matchString += " speed: "+ofToString(speedRatio, 3); // commented for debug - bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match + + bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match } // printf("\n"); @@ -306,7 +331,7 @@ }//end while previousindex countdown }//end for loop through possible current matches - + //printf("current speed is %f\n", bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); } @@ -383,6 +408,10 @@ ofSetColor(250,100,0); ofLine(xLocation, 0, xLocation, (*screenHeight)); + xLocation = getLocationFromMillis(bayesStruct.tmpBestEstimate); + ofSetColor(250,100,0); + ofLine(xLocation, 0, xLocation, (*screenHeight)); + //lines where matching window start and end are ofSetColor(0,100,255); @@ -416,8 +445,15 @@ ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); double confidence = bayesStruct.posterior.getValueAtMillis(mouseX); - string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; +/* + string mouseString = "mouseX "+ofToString(confidence, 3)+" ."; ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); +*/ + string mouseString = "updateCounter "+ofToString(bayesStruct.updateCounter); + ofDrawBitmapString(mouseString, 20 , ofGetHeight() - 40); + + string infostring = "speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 3); + ofDrawBitmapString(infostring, 20 , ofGetHeight() - 60); } int midiEventHolder::getLocationFromTicks(double tickPosition){ @@ -439,11 +475,15 @@ void midiEventHolder::setStartPlayingTimes(){ lastPeriodUpdateTime = ofGetElapsedTimeMillis(); - bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); startTime = lastPeriodUpdateTime; +/* + bayesStruct.lastEventTime = 0;//ofGetElapsedTimeMillis(); + bayesStruct.bestEstimate = 0; bayesStruct.resetArrays(); -// bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); + bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); +*/ + bayesStruct.setStartPlaying(); matchString = ""; }
--- a/src/midiEventHolder.h Thu Aug 18 23:27:42 2011 +0100 +++ b/src/midiEventHolder.h Fri Aug 19 01:26:40 2011 +0100 @@ -6,6 +6,9 @@ * Copyright 2011 QMUL. All rights reserved. * */ +#ifndef MIDI_EVENT_HOLDER +#define MIDI_EVENT_HOLDER + #include "ofMain.h" #include "BayesianArrayStructure.h" @@ -26,11 +29,13 @@ //the rehearsal version IntMatrix recordedNoteOnMatrix;//note, velocity, duration + DoubleVector recordedEventTimes; + IntVector matchesFound; BoolVector noteOnMatches; // int recordedNoteOnIndex; - DoubleVector recordedEventTimes; + IntMatrix playedNoteOnMatrix; DoubleVector playedEventTimes; @@ -110,4 +115,5 @@ string timeString; double startTime; -}; \ No newline at end of file +}; +#endif \ No newline at end of file
--- a/src/testApp.cpp Thu Aug 18 23:27:42 2011 +0100 +++ b/src/testApp.cpp Fri Aug 19 01:26:40 2011 +0100 @@ -19,7 +19,8 @@ screenHeight = ofGetHeight(); midiEvents.screenWidth = &screenWidth; midiEvents.screenHeight = &screenHeight; - ofSetFrameRate(100); + midiEvents.drawTempoMode = false; + ofSetFrameRate(30); } //-------------------------------------------------------------- @@ -206,7 +207,7 @@ int testApp::cannamMainFunction(){ - midiEvents.clearAllEvents(); + midiEvents.clearAllEvents(); //int main(int argc, char **argv) //{ @@ -216,8 +217,18 @@ // } std::string filename = midiFileName;//argv[1]; - - MIDIFileReader fr(filename); + + fileLoader.loadFile(filename, midiEvents); + +}//new end of load function + + + + + //trying to port to new class + /* + MIDIFileReader fr(filename); + if (!fr.isOK()) { std::cerr << "Error: " << fr.getError().c_str() << std::endl; return 1; @@ -418,10 +429,8 @@ } - //} +}//end cannam midi main - - +*/ -}//end cannam midi main
--- a/src/testApp.h Thu Aug 18 23:27:42 2011 +0100 +++ b/src/testApp.h Fri Aug 19 01:26:40 2011 +0100 @@ -15,7 +15,7 @@ - +//uses ftmMidiPlay in max5 via osc to communicate notes in #include "ofMain.h" @@ -23,7 +23,7 @@ #include "ofxFileDialogOSX.h" #include "drawMidiNotes.h" #include "DynamicBayesianArray.h" - +#include "CannamMidiFileLoader.h" #include <iostream> #include "midiEventHolder.h" @@ -68,10 +68,13 @@ // BayesianArrayStructure bayesStruct; int screenWidth, screenHeight; + CannamMidiFileLoader fileLoader; private: ofxOscReceiver receiver; + + }; #endif