Mercurial > hg > multitrack-audio-matcher
view src/AudioEventMatcher.cpp @ 4:45b5cf9be377
checking through Bayesian update procedure - working without cross update method.
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Thu, 02 Feb 2012 12:13:44 +0000 |
parents | 5e188c0035b6 |
children | 5ef00d1dfe68 |
line wrap: on
line source
/* * AudioEventMatcher.cpp * MultipleAudioMathcher * * Created by Andrew on 31/01/2012. * Copyright 2012 QMUL. All rights reserved. * */ #include "AudioEventMatcher.h" const int matchWindowWidth = 6000; AudioEventMatcher::AudioEventMatcher(){ bayesPositionWindow.setToRelativeSize(0, 0.4, 1, 0.2); bayesTempoWindow.setToRelativeSize(0, 0.8, 1, 0.2); bayesLikelihoodWindow.setToRelativeSize(0, 0.6, 1, 0.2); setArraySizes(); usingRealTime = false; bayesianStruct.realTimeMode = &usingRealTime; } void AudioEventMatcher::setArraySizes(){ bayesianStruct.resetSpeedSize(200); bayesianStruct.setRelativeSpeedScalar(0.01); bayesianStruct.setSpeedPrior(1.0); bayesianStruct.relativeSpeedPrior.getMaximum(); bayesianStruct.resetSize(matchWindowWidth); bayesianStruct.setPositionDistributionScalar(1); } void AudioEventMatcher::startPlaying(){ bayesianStruct.setStartPlaying(); //bayesianStruct.posterior.printArray(); } void AudioEventMatcher::draw(){ ofSetColor(20,200,200); bayesPositionWindow.drawOutline(); bayesTempoWindow.drawOutline(); recordedTracks.drawTracks(); ofSetColor(255); // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow); double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); // bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow); bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow); string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0)); tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset); tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis)); ofDrawBitmapString(tmpStr, 20,140); tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate); ofDrawBitmapString(tmpStr, 20, 180); ofDrawBitmapString("screenamp "+ofToString(screenWidthMillis), 20, 100); } void AudioEventMatcher::newPitchEvent(const double& pitchIn, const double& timeIn){ liveInput.addPitchEvent(pitchIn, timeIn); //tmp print stuff printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate); double tmp = bayesianStruct.posterior.getMAPestimate(); printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp)); matchNewPitchEvent(0, pitchIn, timeIn); } void AudioEventMatcher::newKickEvent(const double& timeIn){ // liveInput.addKickEvent(time); matchNewOnsetEvent(0, timeIn); } void AudioEventMatcher::newSnareEvent(const double& timeIn){ matchNewOnsetEvent(0, timeIn); } //Needs just to set bounds for the matching process, not have TimeIn void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){ //start at beginning but OPTIMISE later double onsetLikelihoodToNoise = 0.5; double likelihoodWidth = 40; bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; bayesianStruct.likelihood.zero();//set to zero double quantity = 1;//likelihoodToNoiseRatio / numberOfMatches; int numberOfMatchesFound = 0; double startTime = bayesianStruct.likelihood.offset; double endTime = bayesianStruct.likelihood.offset + matchWindowWidth; if (channel <= recordedTracks.numberOfAudioTracks){ for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; if (millisTime >= startTime && millisTime <= endTime){ bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, likelihoodWidth, quantity); numberOfMatchesFound++; printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset); } } } // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length); bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length)); bayesianStruct.likelihood.renormalise(); } void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ //start at beginning but OPTIMISE later updateBayesianDistributions(timeIn); ///set offsets // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; double pitchLikelihoodToNoise = 0.5; int numberOfMatches = 0; bayesianStruct.likelihood.zero();//set to zero double quantity = 0; if (channel <= recordedTracks.numberOfAudioTracks){ for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) { quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 40); bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity); recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true; numberOfMatches++; } else{ recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false; } } } bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length)); recordedTracks.recentPitch = pitchIn; //tmp set likelihood constant and calculate using that bayesianStruct.likelihood.zero(); bayesianStruct.likelihood.addConstant(1); bayesianStruct.calculatePosterior(); //tmp print stuff printf("After CALC"); printPostOffset(); } double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){ double distance = abs(pitchOne - pitchTwo); if (distance < scale) distance = 1 - (distance/scale); else distance = 0; // printf("[pitch distance %f vs %f = %f\n", pitchOne, pitchTwo, distance); return distance; } bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){ if (abs(recordedPitch - livePitch) < 40) return true; else return false; } void AudioEventMatcher::windowResized(const int& w, const int& h){ recordedTracks.windowResized(w,h); bayesTempoWindow.resized(w,h); bayesPositionWindow.resized(w,h); } void AudioEventMatcher::updateBayesianDistributions(const double& newEventTime){ //MOVE INTO bayesianStruct?? XX //NEED TO CHECK HERE THAT THEY HAVE THE SAME OFFSETS bayesianStruct.prior.copyFromDynamicVector(bayesianStruct.posterior);//try the otehr way //bayesianStruct.copyPriorToPosterior(); //need to get new MAP position and set the offset of the arrays //currently bestEstimate is the approx for the new MAP position int tmpMap = bayesianStruct.posterior.getMAPestimate(); double timeDifference = newEventTime - bayesianStruct.lastEventTime; printf("updating distributions at time %f diff %f offset %f tmpmap est %i\n", newEventTime, timeDifference, bayesianStruct.posterior.offset, tmpMap); //addnoise to the tempo distribution //bayesianStruct.decaySpeedDistribution(timeDifference); if (timeDifference > 50){ bayesianStruct.addGaussianNoiseToSpeedPosterior(timeDifference * 10.0 / 100.); } bayesianStruct.updateBestEstimate(timeDifference); bayesianStruct.lastBestEstimateUpdateTime = newEventTime;//getTimeNow(timePlayed); // printf("set new distrb max 0 or %f\n", bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2)); //tmp print stuff printf("HALFWAY BEST "); printPostOffset(); bayesianStruct.setNewDistributionOffsets(max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2))); bayesianStruct.crossUpdateArrays(bayesianStruct.posterior, bayesianStruct.relativeSpeedPosterior, timeDifference); //i.e. using the same offset as prior bayesianStruct.posterior.offset = bayesianStruct.prior.offset;// // float tmpPrior = max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2));// bayesianStruct.prior.offset = max(0., bayesianStruct.bestEstimate - (bayesianStruct.prior.scalar*bayesianStruct.prior.arraySize/2)); // printf("Using prior offset of %f not %f\n", tmpPrior, bayesianStruct.prior.offset); bayesianStruct.lastEventTime = newEventTime;//bayesianStruct.lastEventTime = ofGetElapsedTimeMillis(); } void AudioEventMatcher::printPostOffset(){ double tmp = bayesianStruct.posterior.getMAPestimate(); printf(" MAP index %i post offset %f == %f ms\n", bayesianStruct.posterior.MAPestimate, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate)); }