Mercurial > hg > multitrack-audio-matcher
view src/AudioEventMatcher.cpp @ 6:746a5af43c02
windowed bayesian distributions - drawn within constrained portion of the screen
author | Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk> |
---|---|
date | Thu, 02 Feb 2012 17:52:08 +0000 |
parents | 5ef00d1dfe68 |
children | 33dedfe32893 |
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(){ //draw some outlines in blue ofSetColor(20,200,200); bayesPositionWindow.drawOutline(); bayesTempoWindow.drawOutline(); //draw the scrolling audio tracks recordedTracks.drawTracks(); ofSetColor(255); // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow); drawBayesianDistributions(); // bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); // bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow); } void AudioEventMatcher::drawBayesianDistributions(){ double screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); double screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame); double screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis; int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis); int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis); bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow); string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis); ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20); bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow); //bayesianStruct.likelihood.drawVector(bayesianStruct.likelihood.getRealTermsAsIndex(0), bayesianStruct.likelihood.getRealTermsAsIndex(screenWidthMillis), bayesLikelihoodWindow); bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), 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 int& channel, 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(channel, pitchIn, timeIn); } void AudioEventMatcher::newKickEvent(const double& timeIn){ // liveInput.addKickEvent(timeIn); matchNewOnsetEvent(0, timeIn); } void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){ // liveInput.addKickEvent(timeIn); matchNewOnsetEvent(channel, timeIn); } void AudioEventMatcher::newSnareEvent(const double& timeIn){ matchNewOnsetEvent(2, timeIn); } //Needs just to set bounds for the matching process, not have TimeIn void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){ bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets //start at beginning but OPTIMISE later double onsetLikelihoodToNoise = 0.3; 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 bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets ///set offsets // bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; double pitchLikelihoodToNoise = 0.2;//more noise 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, 20); 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; } } } if (numberOfMatches > 0){//no point updating unless there is a match bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length)); //tmp set likelihood constant and calculate using that //bayesianStruct.likelihood.zero(); //bayesianStruct.likelihood.addConstant(1); bayesianStruct.calculatePosterior(); } } 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); }