andrew@0: /* andrew@0: * AudioEventMatcher.cpp andrew@0: * MultipleAudioMathcher andrew@0: * andrew@0: * Created by Andrew on 31/01/2012. andrew@0: * Copyright 2012 QMUL. All rights reserved. andrew@0: * andrew@0: */ andrew@0: andrew@0: #include "AudioEventMatcher.h" andrew@0: andrew@0: andrew@2: const int matchWindowWidth = 6000; andrew@0: andrew@0: AudioEventMatcher::AudioEventMatcher(){ andrew@7: andrew@15: andrew@17: pitchLikelihoodToNoise = 0.7;//more noise andrew@16: andrew@17: onsetLikelihoodToNoise = 0.5; andrew@17: onsetLikelihoodWidth = 10;//in ms andrew@15: andrew@0: setArraySizes(); andrew@3: andrew@3: usingRealTime = false; andrew@3: bayesianStruct.realTimeMode = &usingRealTime; andrew@7: recentPitch = 0; andrew@8: currentAlignmentPosition = 0; andrew@14: andrew@15: andrew@9: andrew@9: followingLiveInput = true; andrew@15: startedPlaying = false; andrew@20: recordedTempoIndex = 0; andrew@20: // temporal.setUpEventTimeMatrix(); andrew@20: // recordedTempoData.setUpEventTimeMatrix(); andrew@0: } andrew@0: andrew@14: andrew@19: andrew@19: andrew@7: void AudioEventMatcher::setWindowDimensions(){ andrew@7: double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight; andrew@7: double heightAvailable = 1 - startHeight; andrew@19: heightAvailable /= NUMBER_OF_CHANNELS; andrew@7: andrew@7: bayesPositionWindow.setToRelativeSize(0, startHeight, 1, heightAvailable); andrew@7: bayesLikelihoodWindow.setToRelativeSize(0, startHeight + 1*heightAvailable, 1, heightAvailable); andrew@7: bayesTempoWindow.setToRelativeSize(0, startHeight + 2*heightAvailable, 1, heightAvailable); andrew@7: andrew@7: andrew@7: } andrew@0: andrew@0: void AudioEventMatcher::setArraySizes(){ andrew@0: bayesianStruct.resetSpeedSize(200); andrew@0: bayesianStruct.setRelativeSpeedScalar(0.01); andrew@0: bayesianStruct.setSpeedPrior(1.0); andrew@0: bayesianStruct.relativeSpeedPrior.getMaximum(); andrew@0: andrew@0: bayesianStruct.resetSize(matchWindowWidth); andrew@0: bayesianStruct.setPositionDistributionScalar(1); andrew@0: andrew@0: } andrew@0: andrew@16: void AudioEventMatcher::loadAudioFiles(){ andrew@16: recordedTracks.loadTestAudio(); andrew@16: synchroniser.fileLengthSamples = recordedTracks.loadedAudioFiles[0].fileLoader.totalNumberOfSamples; andrew@16: printf("synchroniser has %f samples\n", synchroniser.fileLengthSamples); andrew@20: andrew@20: calculateRecordedTempoData(); andrew@20: printf("\n\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@20: setTempoPrior(recordedTempoData.playingTempo); andrew@20: calculateRecordedTempoData();//now calculate again using better prior andrew@20: andrew@20: printf("\n\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@20: printf("GLOBAL TEMPO of RECORDED FILES\n"); andrew@20: recordedTempoData.printTempoTimes(); andrew@20: } andrew@20: andrew@20: void AudioEventMatcher::setTempoPrior(double tempo){ andrew@20: recordedTempoData.zero(); andrew@20: recordedTempoData.tempoPosterior.zero(); andrew@20: recordedTempoData.tempoPosterior.addGaussianShapeFromRealTime(tempo, 3, 1); andrew@20: andrew@20: } andrew@20: andrew@20: void AudioEventMatcher::calculateRecordedTempoData(){ andrew@20: int indexForOnsets[3]; andrew@20: indexForOnsets[0] = 0; andrew@20: indexForOnsets[1] = 0; andrew@20: indexForOnsets[2] = 0; andrew@20: int kickTime, snareTime; andrew@20: while (indexForOnsets[0] < recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.chromaOnsets.size() || andrew@20: indexForOnsets[2] < recordedTracks.loadedAudioFiles[2].fileLoader.onsetDetect.chromaOnsets.size()) { andrew@20: andrew@20: setNextOnsetTime(0, kickTime, &indexForOnsets[0]); andrew@20: setNextOnsetTime(2, snareTime, &indexForOnsets[0]); andrew@20: andrew@20: if (kickTime < snareTime){ andrew@20: printf("update kick at %i\n", kickTime); andrew@20: recordedTempoData.updateTempo(0, kickTime); andrew@20: printf("recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@20: indexForOnsets[0]++; andrew@20: }else { andrew@20: printf("update snare at %i\n", snareTime); andrew@20: recordedTempoData.updateTempo(2, snareTime); andrew@20: printf("recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@20: indexForOnsets[2]++; andrew@20: } andrew@20: }//end while andrew@20: andrew@20: andrew@20: } andrew@20: andrew@20: void AudioEventMatcher::setNextOnsetTime(const int& channel, int& time, int* indexForOnsets){ andrew@20: if (indexForOnsets[channel] < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){ andrew@20: time = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[indexForOnsets[channel]].millisTime; andrew@20: } andrew@20: else { andrew@20: time = 2147483647;//infinity andrew@20: } andrew@16: } andrew@16: andrew@9: void AudioEventMatcher::startPlaying(){ andrew@3: bayesianStruct.setStartPlaying(); andrew@8: currentAlignmentPosition = 0; andrew@8: startTime = ofGetElapsedTimeMillis(); andrew@11: andrew@11: projectedPrior = bayesianStruct.prior; andrew@15: startedPlaying = true; andrew@17: synchroniser.reset(); andrew@19: temporal.reset(); andrew@17: andrew@20: recordedTempoIndex = 0; andrew@20: recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex]; andrew@20: andrew@20: currentSpeedRatio = 1; andrew@20: andrew@21: temporal.tempoPosterior.zero(); andrew@21: temporal.tempoPosterior.addGaussianShapeFromRealTime(recordedTempo, 10, 1); andrew@21: andrew@20: //SET TEMPO PRIOR for Speed Ratio andrew@20: //the update this andrew@20: setSpeedRatioDistribution(currentSpeedRatio); andrew@3: //bayesianStruct.posterior.printArray(); andrew@3: } andrew@3: andrew@9: andrew@20: void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){ andrew@20: bayesianStruct.relativeSpeedPosterior.zero(); andrew@20: bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1); andrew@22: bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(1, 0.06, 0.8); andrew@20: } andrew@20: andrew@15: void AudioEventMatcher::stopPlaying(){ andrew@15: startedPlaying = false; andrew@19: temporal.printEventTimes(); andrew@15: } andrew@15: andrew@22: void AudioEventMatcher::rescue(){ andrew@22: bayesianStruct.posterior.zero(); andrew@22: bayesianStruct.posterior.addConstant(1); andrew@22: bayesianStruct.prior.zero(); andrew@22: bayesianStruct.prior.addConstant(1); andrew@22: } andrew@22: andrew@9: void AudioEventMatcher::updatePosition(){ andrew@19: andrew@19: if (startedPlaying){ andrew@9: if (!followingLiveInput) andrew@9: recordedTracks.updatePosition(); andrew@19: else andrew@9: recordedTracks.updatePositionToMillis(currentAlignmentPosition); andrew@9: andrew@20: updateBestAlignmentPosition(); andrew@19: } andrew@19: andrew@20: updateRecordedTempo(); andrew@20: andrew@19: temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 ); andrew@9: } andrew@9: andrew@20: void AudioEventMatcher::updateRecordedTempo(){ andrew@20: //tempo of equivalent recorded position is updated andrew@20: while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){ andrew@20: recordedTempoIndex++; andrew@20: } andrew@20: recordedTempo = recordedTempoData.globalTempo[recordedTempoIndex]; andrew@20: double tmpRatio = currentSpeedRatio; andrew@20: currentSpeedRatio = temporal.playingTempo / recordedTempo; andrew@20: if (currentSpeedRatio != tmpRatio) andrew@20: setSpeedRatioDistribution(currentSpeedRatio); andrew@20: } andrew@20: andrew@8: void AudioEventMatcher::updateBestAlignmentPosition(){ andrew@10: //THIS DEALS WITH WHERE WE ARE NOW! ON THE SCREEN andrew@10: //DIFFERENT TO WHEN EVENTS COME IN AS THEY ARE TIMESTAMPED - SO EG A PITCH EVENT MAY ARRIVE 16 CHROMA FRAMES LATER - BIG DIFFERENCE andrew@10: andrew@10: int newTime = ofGetElapsedTimeMillis() - startTime; andrew@10: // double tmp = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate);; andrew@10: // double timetmp = (newTime - lastAlignmentTime); andrew@10: // double speedtmp = bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate); andrew@11: // currentAlignmentTime = newTime; andrew@9: currentAlignmentPosition = bayesianStruct.posterior.getIndexInRealTerms(bayesianStruct.posterior.MAPestimate); andrew@10: currentAlignmentPosition += (newTime - lastAlignmentTime) * bayesianStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesianStruct.relativeSpeedPosterior.MAPestimate); andrew@10: andrew@16: andrew@17: synchroniser.updateRecordedPosition(currentAlignmentPosition, newTime); andrew@16: andrew@16: synchroniser.updateOutputSpeed(); andrew@16: andrew@11: bayesianStruct.projectDistribution(newTime, currentAlignmentPosition, projectedPrior);//prior gets updated to where we are now andrew@11: andrew@10: // printf("ALIGN pos %f time diff %f (now %f , last %f)speed %f :: ALIGN BEST %f\n", tmp, timetmp, (double)ofGetElapsedTimeMillis(), lastAlignmentTime, speedtmp, currentAlignmentPosition); andrew@8: } andrew@8: andrew@0: void AudioEventMatcher::draw(){ andrew@6: //draw some outlines in blue andrew@3: ofSetColor(20,200,200); andrew@3: bayesPositionWindow.drawOutline(); andrew@3: bayesTempoWindow.drawOutline(); andrew@0: andrew@6: //draw the scrolling audio tracks andrew@1: recordedTracks.drawTracks(); andrew@7: andrew@2: ofSetColor(255); andrew@2: // bayesianStruct.relativeSpeedPrior.drawVector(0, 200, bayesTempoWindow); andrew@9: andrew@9: setScreenDisplayTimes(); andrew@6: drawBayesianDistributions(); andrew@8: andrew@11: //bayesianStruct.posterior.drawVector(0, bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); andrew@6: //bayesianStruct.posterior.drawVector(bayesianStruct.posterior.getRealTermsAsIndex(0), bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis), bayesPositionWindow); andrew@11: //bayesianStruct.relativeSpeedPosterior.drawVector(0, bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(2), bayesTempoWindow); andrew@18: string tmpStr = "pitch "+ofToString(recentPitch, 2); andrew@18: tmpStr += " Nearest "+ofToString(pitchOfNearestMatch,2); andrew@18: tmpStr += " dist "+ofToString(distanceOfNearestMatch, 2); andrew@18: tmpStr += ", Time "+ofToString(recentTime, 0); andrew@18: ofDrawBitmapString(tmpStr, 20, 20); andrew@18: andrew@18: andrew@9: andrew@16: string alignString = " align "+ofToString(currentAlignmentPosition, 2); andrew@16: alignString += " playing "+ofToString(synchroniser.playingPositionRatio, 5); andrew@17: alignString += " pos "+ofToString(synchroniser.playingPositionMillis,0)+" ms"; andrew@17: alignString += " rec pos "+ofToString(synchroniser.recordedPositionMillis,0)+" ms"; andrew@16: ofDrawBitmapString(alignString, 20, 50); andrew@16: andrew@9: ofDrawBitmapString("pos "+ofToString(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPosition), 200,600); andrew@20: andrew@20: temporal.drawTempoArray(bayesLikelihoodWindow); andrew@20: andrew@20: drawRecordedTempo(); andrew@20: drawPlayingTempo(); andrew@20: andrew@20: andrew@6: } andrew@20: andrew@20: void AudioEventMatcher::drawRecordedTempo(){ andrew@6: andrew@21: int xTempoIndex = ofGetWidth() * (double)(recordedTempo - recordedTempoData.minimumTempoInterval)/(double)(recordedTempoData.maximumTempoInterval - recordedTempoData.minimumTempoInterval); andrew@20: ofSetColor(0, 200, 0); andrew@20: ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height); andrew@20: ofDrawBitmapString(ofToString(recordedTempo), xTempoIndex, bayesLikelihoodWindow.y + 10); andrew@20: } andrew@20: andrew@20: void AudioEventMatcher::drawPlayingTempo(){ andrew@21: //purple line for MAP estimate of new intervals andrew@21: int xTempoIndex = (double)(ofGetWidth() * (temporal.playingTempo - temporal.minimumTempoInterval))/(double)(temporal.maximumTempoInterval - temporal.minimumTempoInterval); andrew@20: ofSetColor(200, 0, 200); andrew@20: ofLine(xTempoIndex, bayesLikelihoodWindow.y, xTempoIndex, bayesLikelihoodWindow.y + bayesLikelihoodWindow.height); andrew@21: ofDrawBitmapString(ofToString(temporal.playingTempo), xTempoIndex, bayesLikelihoodWindow.y + 10); andrew@20: andrew@21: //red line where the ratio is between playing tempo and recorded one andrew@20: int xSpeedRatioIndex = (double)(temporal.tempoPosterior.getIndexInRealTerms(currentSpeedRatio)*ofGetWidth())/(double)temporal.tempoPosterior.arraySize; andrew@20: ofSetColor(200,0,0); andrew@20: ofLine(xSpeedRatioIndex, bayesTempoWindow.y, xSpeedRatioIndex, bayesTempoWindow.y + bayesTempoWindow.height); andrew@21: string tmpString = "playing "+ofToString(temporal.playingTempo); andrew@21: tmpString += ", recorded "+ofToString(recordedTempo); andrew@21: tmpString += " ratio "+ofToString(currentSpeedRatio); andrew@21: ofSetColor(155,155,155); andrew@21: ofDrawBitmapString(tmpString, 20, bayesTempoWindow.y+10); andrew@20: andrew@20: } andrew@20: andrew@20: andrew@9: void AudioEventMatcher::setScreenDisplayTimes(){ andrew@9: screenWidthMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.amplitudeNumber); andrew@9: // if (!followingLiveInput){ andrew@9: andrew@9: screenStartTimeMillis = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.drawParams.windowStartFrame); andrew@9: screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis; andrew@9: andrew@9: //need PRECISION in this alignment andrew@9: andrew@9: andrew@9: /*}else{ andrew@9: andrew@9: screenStartTimeMillis = (int)(currentAlignmentPosition/screenWidthMillis) * screenWidthMillis; andrew@9: screenEndTimeMillis = screenStartTimeMillis + screenWidthMillis; andrew@9: }*/ andrew@9: } andrew@9: andrew@6: void AudioEventMatcher::drawBayesianDistributions(){ andrew@6: andrew@6: andrew@6: int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis); andrew@6: int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis); andrew@4: andrew@6: bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow); andrew@6: andrew@6: string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis); andrew@6: ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20); andrew@4: andrew@8: // bayesianStruct.likelihood.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesLikelihoodWindow); andrew@2: andrew@6: bayesianStruct.relativeSpeedPosterior.drawConstrainedVector(0, bayesianStruct.relativeSpeedPosterior.arraySize, 0, ofGetWidth(), bayesTempoWindow); andrew@6: andrew@3: string tmpStr = "zero is "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(0)); andrew@3: tmpStr += " offsetis "+ofToString(bayesianStruct.posterior.offset); andrew@3: tmpStr += " screenWidth = "+ofToString(bayesianStruct.posterior.getRealTermsAsIndex(screenWidthMillis)); andrew@3: ofDrawBitmapString(tmpStr, 20,140); andrew@3: tmpStr = "best est "+ofToString(bayesianStruct.bestEstimate); andrew@3: ofDrawBitmapString(tmpStr, 20, 180); andrew@3: andrew@8: ofDrawBitmapString("screenwidth "+ofToString(screenWidthMillis), 20, 800); andrew@3: andrew@9: //green line at current best estimate andrew@13: ofSetColor(0,255,0);//green scrolling line best position andrew@8: double currentEstimateIndex = (currentAlignmentPosition - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis; andrew@8: ofLine(currentEstimateIndex, bayesPositionWindow.y, currentEstimateIndex, bayesPositionWindow.y + bayesPositionWindow.height); andrew@7: andrew@16: andrew@16: ofSetColor(0,255,255);//synchroniser position andrew@16: currentEstimateIndex = (synchroniser.playingPositionMillis - screenStartTimeMillis)*ofGetWidth()/screenWidthMillis; andrew@16: ofLine(currentEstimateIndex, bayesLikelihoodWindow.y, currentEstimateIndex, bayesLikelihoodWindow.y + bayesPositionWindow.height); andrew@16: andrew@16: andrew@16: andrew@7: //draw track by track likelihoods andrew@7: for (int i = 0; i 0){ andrew@1: liveInput.addPitchEvent(pitchIn, timeIn); andrew@4: andrew@10: //printPosteriorMAPinfo(); andrew@11: andrew@7: matchNewPitchEvent(channel, pitchIn, timeIn);//main pitch matching fn andrew@7: andrew@7: likelihoodVisualisation[1] = bayesianStruct.likelihood; andrew@7: andrew@7: recentPitch = pitchIn;//for drawing andrew@7: recentTime = timeIn; andrew@7: } andrew@8: andrew@2: } andrew@2: andrew@6: void AudioEventMatcher::newKickEvent(const double& timeIn){ andrew@6: // liveInput.addKickEvent(timeIn); andrew@2: matchNewOnsetEvent(0, timeIn); andrew@7: likelihoodVisualisation[0] = bayesianStruct.likelihood; andrew@2: } andrew@2: andrew@6: void AudioEventMatcher::newKickEvent(const int& channel, const double& timeIn){ andrew@6: // liveInput.addKickEvent(timeIn); andrew@6: matchNewOnsetEvent(channel, timeIn); andrew@7: likelihoodVisualisation[0] = bayesianStruct.likelihood; andrew@6: } andrew@6: andrew@2: andrew@2: void AudioEventMatcher::newSnareEvent(const double& timeIn){ andrew@6: matchNewOnsetEvent(2, timeIn); andrew@7: likelihoodVisualisation[2] = bayesianStruct.likelihood; andrew@7: } andrew@7: andrew@7: andrew@7: void AudioEventMatcher::newSnareEvent(const int& channel, const double& timeIn){ andrew@7: matchNewOnsetEvent(channel, timeIn); andrew@7: likelihoodVisualisation[2] = bayesianStruct.likelihood; andrew@2: } andrew@2: andrew@2: //Needs just to set bounds for the matching process, not have TimeIn andrew@2: void AudioEventMatcher::matchNewOnsetEvent(const int& channel, const double& timeIn){ andrew@3: andrew@6: bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets andrew@10: andrew@2: //start at beginning but OPTIMISE later andrew@15: andrew@2: andrew@2: bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; andrew@2: bayesianStruct.likelihood.zero();//set to zero andrew@2: andrew@2: double quantity = 1;//likelihoodToNoiseRatio / numberOfMatches; andrew@2: int numberOfMatchesFound = 0; andrew@2: andrew@2: andrew@10: double startMatchingTime = bayesianStruct.likelihood.offset; andrew@10: double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth; andrew@2: andrew@2: if (channel <= recordedTracks.numberOfAudioTracks){ andrew@2: for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ andrew@2: double millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; andrew@10: if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){ andrew@14: bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity); andrew@2: numberOfMatchesFound++; andrew@6: // printf("Adding Gaussian for onset at time %f offset %f\n", millisTime, bayesianStruct.likelihood.offset); andrew@2: andrew@2: } andrew@2: } andrew@2: } andrew@2: andrew@11: if (numberOfMatchesFound > 0){ andrew@3: // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length); andrew@3: bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length)); andrew@2: bayesianStruct.likelihood.renormalise(); andrew@2: andrew@8: bayesianStruct.calculatePosterior(); andrew@10: lastAlignmentTime = timeIn;//use TIMESTAMP andrew@10: recentEventTime[channel] = timeIn;//ofGetElapsedTimeMillis() - startTime; andrew@11: andrew@11: recentPriors[channel] = bayesianStruct.prior; andrew@13: projectedPrior = bayesianStruct.prior; andrew@19: andrew@19: andrew@19: temporal.updateTempo(channel, timeIn); andrew@11: } andrew@11: andrew@11: andrew@6: andrew@3: } andrew@3: andrew@3: andrew@3: andrew@3: void AudioEventMatcher::matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn){ andrew@3: //start at beginning but OPTIMISE later andrew@10: /*printf("TIME %i\n", ofGetElapsedTimeMillis()); andrew@10: //tmp debug andrew@10: updateBestAlignmentPosition(); andrew@10: printf("current alignment best estimate %f\n", currentAlignmentPosition); andrew@10: */ andrew@6: bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets andrew@8: andrew@7: //set the lielihoods by matching the pitched note andrew@7: andrew@15: andrew@3: int numberOfMatches = 0; andrew@3: bayesianStruct.likelihood.zero();//set to zero andrew@18: double newOnsetTime; andrew@18: double closestDistance = INFINITY; andrew@3: andrew@3: double quantity = 0; andrew@3: if (channel <= recordedTracks.numberOfAudioTracks){ andrew@3: for (int i = 0;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size();i++){ andrew@3: andrew@3: if (checkMatch(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn)) { andrew@18: quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, 8); andrew@18: andrew@3: bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, 30, quantity); andrew@3: recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true; andrew@3: numberOfMatches++; andrew@3: } andrew@3: else{ andrew@3: recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = false; andrew@3: } andrew@18: //checking nearest pitch andrew@18: newOnsetTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; andrew@18: if (abs(newOnsetTime - currentAlignmentPosition) < closestDistance){ andrew@18: closestDistance = abs(newOnsetTime - currentAlignmentPosition); andrew@18: pitchOfNearestMatch = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch; andrew@18: distanceOfNearestMatch = quantity; andrew@18: } andrew@3: andrew@3: } andrew@3: } andrew@6: andrew@8: andrew@8: andrew@6: if (numberOfMatches > 0){//no point updating unless there is a match andrew@7: andrew@6: bayesianStruct.likelihood.addConstant(numberOfMatches*(1-pitchLikelihoodToNoise)/(pitchLikelihoodToNoise*bayesianStruct.likelihood.length)); andrew@4: andrew@4: //tmp set likelihood constant and calculate using that andrew@6: //bayesianStruct.likelihood.zero(); andrew@6: //bayesianStruct.likelihood.addConstant(1); andrew@7: andrew@6: bayesianStruct.calculatePosterior(); andrew@11: lastAlignmentTime = timeIn;//has to use the STAMPED time andrew@11: recentEventTime[channel] = timeIn; andrew@11: andrew@11: recentPriors[channel] = bayesianStruct.prior; andrew@13: projectedPrior = bayesianStruct.prior; andrew@19: andrew@19: temporal.eventTimes[channel].push_back(timeIn); andrew@6: } andrew@4: andrew@11: andrew@1: } andrew@1: andrew@3: double AudioEventMatcher::getPitchDistance(const double& pitchOne, const double& pitchTwo, const double& scale){ andrew@3: andrew@18: double scaleFactor = scale * pitchOne / 110.0; andrew@16: andrew@18: int multiplicationFactor = 1; andrew@18: if (pitchTwo > 0){ andrew@18: int multiplicationFactor = round(pitchOne/pitchTwo); andrew@18: } andrew@16: andrew@18: double distance = abs(pitchOne - pitchTwo*multiplicationFactor); andrew@16: if (distance < scaleFactor) andrew@16: distance = 1 - (distance/scaleFactor); andrew@3: else andrew@3: distance = 0; andrew@3: andrew@3: // printf("[pitch distance %f vs %f = %f\n", pitchOne, pitchTwo, distance); andrew@3: return distance; andrew@3: andrew@3: } andrew@3: andrew@3: andrew@3: bool AudioEventMatcher::checkMatch(const double& recordedPitch, const double& livePitch){ andrew@18: andrew@18: if (livePitch > 0){ andrew@18: int multiplicationFactor = (int)(round(recordedPitch/livePitch)); andrew@18: andrew@18: if (abs(recordedPitch - livePitch * multiplicationFactor) < 16) andrew@3: return true; andrew@3: else andrew@3: return false; andrew@18: }else { andrew@18: return false; andrew@18: } andrew@18: andrew@3: } andrew@3: andrew@3: andrew@1: andrew@1: void AudioEventMatcher::windowResized(const int& w, const int& h){ andrew@1: recordedTracks.windowResized(w,h); andrew@3: bayesTempoWindow.resized(w,h); andrew@3: bayesPositionWindow.resized(w,h); andrew@3: } andrew@3: andrew@10: /* andrew@10: andrew@10: void printPosteriorMAPinfo(){ //tmp print stuff andrew@10: printf("New pitch MAP post estimate now %i, ", bayesianStruct.posterior.MAPestimate); andrew@10: double tmp = bayesianStruct.posterior.getMAPestimate(); andrew@10: printf(" getting it %f and offset %f == %f ms\n", tmp, bayesianStruct.posterior.offset, bayesianStruct.posterior.getIndexInRealTerms(tmp)); andrew@10: andrew@10: } andrew@10: */ andrew@3: