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@55: //whi are there two Tempo Follower class objects? andrew@55: andrew@0: andrew@39: const int matchWindowWidth = 8000;//ms in which to match andrew@39: andrew@32: const float pitchCutOff = 16;//within which pitches are even considered andrew@56: const double pitchWidth = 12; andrew@0: andrew@55: bool printInfo = false; andrew@50: andrew@0: AudioEventMatcher::AudioEventMatcher(){ andrew@7: andrew@55: ofBackground(0); andrew@50: useChromaDotProduct = false;//false for most tests andrew@37: printingData = false; andrew@56: updateTempoMethodOn = false; andrew@37: andrew@23: pitchLikelihoodToNoise = 0.6;//more noise andrew@56: pitchLikelihoodWidth = 30; andrew@56: andrew@32: chromaLikelihoodToNoise = 0.5;//lower => more noise, higher more weight for events andrew@32: chromaLikelihoodWidth = 50;//ms round onset event andrew@16: andrew@56: //onsetLikelihoodToNoise = 0.2;//0.1 and 10 as to 9/5/12 andrew@53: kickLikelihoodToNoise = 0.3; andrew@53: snareLikelihoodToNoise = 0.1; andrew@53: andrew@53: andrew@48: onsetLikelihoodWidth = 6;//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@9: followingLiveInput = true; andrew@15: startedPlaying = false; andrew@20: recordedTempoIndex = 0; andrew@39: andrew@42: bayesianStruct.startingWindowWidth = 100;//matchWindowWidth / 8; andrew@42: bayesianStruct.matchWindowWidth = matchWindowWidth; andrew@50: andrew@51: drawLikelihoods = true; andrew@50: drawPosterior = false; andrew@50: andrew@53: temporal.printOutput = true;//printInfo; andrew@50: andrew@52: andrew@20: // temporal.setUpEventTimeMatrix(); andrew@20: // recordedTempoData.setUpEventTimeMatrix(); andrew@0: } andrew@0: andrew@14: andrew@19: andrew@19: andrew@7: void AudioEventMatcher::setWindowDimensions(){ andrew@53: andrew@7: double startHeight = recordedTracks.numberOfAudioTracks * recordedTracks.trackScreenHeight; andrew@7: double heightAvailable = 1 - startHeight; andrew@32: heightAvailable /= numberOfChannels; 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@36: float scalarForBayesianDistribution = 2; andrew@36: andrew@36: bayesianStruct.resetSize(matchWindowWidth / scalarForBayesianDistribution); andrew@36: bayesianStruct.setPositionDistributionScalar(2); 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@55: printf("First PASS\n"); andrew@20: andrew@20: calculateRecordedTempoData(); andrew@55: recordedTempoData.printTempoTimes(); andrew@53: printf("\n audioeventmatcher\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@55: andrew@55: printf("SECOND PASS\n"); andrew@20: setTempoPrior(recordedTempoData.playingTempo); andrew@20: calculateRecordedTempoData();//now calculate again using better prior andrew@20: andrew@53: printf("\n audioeventmatcher\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@53: andrew@55: int kickTime = 0; andrew@55: int snareTime = 0; andrew@53: 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@53: printf("kick(%i) at %i\n", indexForOnsets[0], kickTime); andrew@20: recordedTempoData.updateTempo(0, kickTime); andrew@53: // printf("recorded tempo is %f\n", recordedTempoData.playingTempo); andrew@20: indexForOnsets[0]++; andrew@20: }else { andrew@53: printf("snare(%i) at %i\n", indexForOnsets[2], snareTime); andrew@20: recordedTempoData.updateTempo(2, snareTime); andrew@53: // 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: 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@55: printf("recorded tempo is %f\n", recordedTempo); andrew@20: currentSpeedRatio = 1; andrew@53: relativeTempo = 1; andrew@20: andrew@55: temporal.reset(); andrew@55: // temporal.tempoPosterior.zero(); andrew@55: // temporal.tempoPosterior.addGaussianShapeFromRealTime(recordedTempo, 2000, 1); andrew@21: andrew@20: //SET TEMPO PRIOR for Speed Ratio andrew@20: //the update this andrew@20: setSpeedRatioDistribution(currentSpeedRatio); andrew@37: andrew@37: euclideanMaximumDistance = 0; andrew@37: andrew@3: //bayesianStruct.posterior.printArray(); andrew@3: } andrew@3: andrew@9: andrew@20: void AudioEventMatcher::setSpeedRatioDistribution(const double& speedRatio){ andrew@39: //here is the speed combo actually used andrew@20: bayesianStruct.relativeSpeedPosterior.zero(); andrew@39: // bayesianStruct.relativeSpeedPosterior.addToIndex(bayesianStruct.relativeSpeedPosterior.getRealTermsAsIndex(speedRatio), 1); andrew@53: bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.1, 3); andrew@53: bayesianStruct.relativeSpeedPosterior.addGaussianShapeFromRealTime(speedRatio, 0.02, 2); andrew@20: } andrew@20: andrew@15: void AudioEventMatcher::stopPlaying(){ andrew@15: startedPlaying = false; andrew@52: testDistributionOutput.closeFile(); andrew@37: //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@50: #pragma mark -update andrew@9: void AudioEventMatcher::updatePosition(){ andrew@19: andrew@19: if (startedPlaying){ andrew@50: /* if (!followingLiveInput) andrew@9: recordedTracks.updatePosition(); andrew@19: else andrew@50: */ andrew@9: recordedTracks.updatePositionToMillis(currentAlignmentPosition); andrew@53: updateBestAlignmentPosition(); andrew@9: andrew@53: } else { andrew@50: recordedTracks.updatePosition(); andrew@50: markerPlaybackPosition = recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames); andrew@50: currentAlignmentPosition = markerPlaybackPosition; andrew@19: } andrew@19: andrew@56: if (updateTempoMethodOn){ andrew@56: updateRecordedTempo(); andrew@56: } andrew@9: } andrew@9: andrew@20: void AudioEventMatcher::updateRecordedTempo(){ andrew@20: //tempo of equivalent recorded position is updated andrew@56: andrew@56: if (recordedTempoIndex < recordedTempoData.globalTempoTimes.size()){//if for debug andrew@56: recordedTempo = getRecordedTempoAtMillis(currentAlignmentPosition); andrew@55: andrew@56: double tmpRatio = currentSpeedRatio; andrew@56: andrew@56: currentSpeedRatio = temporal.playingTempo / recordedTempo; andrew@56: if (currentSpeedRatio != tmpRatio) andrew@56: setSpeedRatioDistribution(currentSpeedRatio); andrew@56: andrew@37: }//end if to prevent debug crash andrew@56: andrew@56: temporal.tempoPosterior.addGaussianShape(temporal.tempoPosterior.MAPestimate, temporal.tempoArraySize / 4, 0.5 ); andrew@56: andrew@20: } andrew@56: andrew@55: double AudioEventMatcher::getRecordedTempoAtMillis(const double& millisPosition){ andrew@56: andrew@55: while(currentAlignmentPosition < recordedTempoData.globalTempoTimes[recordedTempoIndex] && recordedTempoIndex > 0){ andrew@56: //this loop never used as sequential, so we expect the alignment time to be ahead of the last recorded tempo point andrew@55: //but just in case andrew@55: recordedTempoIndex--; andrew@55: } andrew@55: andrew@55: while(currentAlignmentPosition > recordedTempoData.globalTempoTimes[recordedTempoIndex]){ andrew@55: recordedTempoIndex++; andrew@55: } andrew@55: andrew@55: return recordedTempoData.globalTempo[recordedTempoIndex]; andrew@55: } andrew@55: 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@45: int newTime = getTimeNow(); 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@32: andrew@50: // printf("updateBestAlignment:: alignment %i:: %i\n", newTime, (int) currentAlignmentPosition); 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@45: int AudioEventMatcher::getTimeNow(){ andrew@45: return ofGetElapsedTimeMillis() - startTime; andrew@45: } andrew@45: andrew@50: #pragma mark -markers andrew@50: void AudioEventMatcher::addMarkerNow(){ andrew@50: if (!startedPlaying) andrew@50: markedPoints.addMarker(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.framesToMillis(recordedTracks.loadedAudioFiles[0].fileLoader.onsetDetect.playPositionFrames)); andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::deleteMarkers(){ andrew@50: markedPoints.markers.clear(); andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::moveToNextMarker(){ andrew@50: int m = 0; andrew@50: while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition) andrew@50: m++; andrew@50: andrew@50: andrew@50: if (markedPoints.markers[m] > currentAlignmentPosition){ andrew@50: setPlaybackPosition(markedPoints.markers[m]); andrew@50: printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition); andrew@50: } andrew@50: andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::moveToPreviousMarker(){ andrew@50: int m = 0; andrew@50: while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition) andrew@50: m++; andrew@50: andrew@51: if (m > 1 && markedPoints.markers[m-1] + 300 > currentAlignmentPosition) andrew@51: setPlaybackPosition(markedPoints.markers[m-2]); andrew@51: else if (m > 0 && markedPoints.markers[m-1] < currentAlignmentPosition){ andrew@50: setPlaybackPosition(markedPoints.markers[m-1]); andrew@50: printf("move to marker %f from current pos %f\n", markedPoints.markers[m], currentAlignmentPosition); andrew@50: } andrew@51: andrew@51: andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::deleteNearestMarker(){ andrew@50: int m = 0; andrew@50: while (m < markedPoints.markers.size() && markedPoints.markers[m] < currentAlignmentPosition) andrew@50: m++; andrew@50: andrew@50: int markerToDelete = m; andrew@50: if (m >= 0 && fabs(markedPoints.markers[m] - currentAlignmentPosition) < fabs(markedPoints.markers[m-1] - currentAlignmentPosition)){ andrew@50: markerToDelete = m-1; andrew@50: } andrew@50: andrew@50: markedPoints.deleteMarker(markerToDelete); andrew@50: andrew@50: andrew@50: } andrew@50: andrew@50: andrew@50: void AudioEventMatcher::setPlaybackPosition(const double& millis){ andrew@50: if (!startedPlaying) andrew@50: recordedTracks.updatePlaybackPositionToMillis(millis); andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::goToMarker(const int& markerID){ andrew@50: if (startedPlaying && markerID >= 0 && markerID < markedPoints.markers.size()){ andrew@50: double markPosition = markedPoints.markers[markerID]; andrew@50: setToPosition(markPosition); andrew@50: } andrew@50: andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::mousePressed(const int& x){ andrew@50: if (!startedPlaying){ andrew@50: double position = (float) x * screenWidthMillis / ofGetWidth(); andrew@50: position += screenStartTimeMillis; andrew@50: setPlaybackPosition(position); andrew@50: } andrew@50: } andrew@50: andrew@50: void AudioEventMatcher::setToPosition(const double& position){ andrew@55: setNewLimits(position); andrew@55: andrew@50: bayesianStruct.posterior.zero(); andrew@53: bayesianStruct.zeroDistributionAtPosition(bayesianStruct.posterior, position); andrew@50: bayesianStruct.posterior.addGaussianShapeFromRealTime(position, 100, 1); andrew@53: andrew@53: bayesianStruct.prior.zero(); andrew@53: bayesianStruct.zeroDistributionAtPosition(bayesianStruct.prior, position); andrew@53: bayesianStruct.prior.addGaussianShapeFromRealTime(position, 100, 1); andrew@53: andrew@50: // bayesianStruct.posterior.addConstant(0.1); andrew@50: // bayesianStruct.prior.zero(); andrew@50: // bayesianStruct.prior.addConstant(1); andrew@50: } andrew@50: andrew@55: andrew@55: void AudioEventMatcher::setNewLimits(const double& position){ andrew@55: //update the distribution to the new limits andrew@55: double difference = position - (bayesianStruct.prior.getIndexInRealTerms(bayesianStruct.prior.length/2)); andrew@55: bayesianStruct.prior.offset += difference; andrew@55: bayesianStruct.likelihood.offset += difference; andrew@55: bayesianStruct.posterior.offset += difference; andrew@55: andrew@55: bayesianStruct.prior.zero(); andrew@55: bayesianStruct.posterior.zero(); andrew@55: bayesianStruct.likelihood.zero(); andrew@55: } andrew@55: andrew@50: #pragma mark -draw andrew@45: andrew@0: void AudioEventMatcher::draw(){ andrew@32: andrew@32: //MAIN DRAW FUNCTION FOR ALL andrew@55: andrew@55: //ofBackground(255,255,255); andrew@32: andrew@6: //draw some outlines in blue andrew@3: ofSetColor(20,200,200); andrew@39: // bayesPositionWindow.drawOutline(); andrew@39: // 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@9: andrew@55: //tempo andrew@55: //temporal.drawTempoArray(bayesLikelihoodWindow); andrew@50: andrew@50: if (printInfo){ andrew@55: drawRecordedTempo(); andrew@55: drawPlayingTempo(); andrew@55: drawAlignmentTimes(); andrew@50: } andrew@20: andrew@50: drawMarkers(); 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@50: andrew@50: if (printInfo){ 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@50: } 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@32: andrew@32: drawPositionWindow(); 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@32: andrew@50: if (drawLikelihoods) andrew@55: drawTrackLikelihoods(); andrew@6: andrew@50: andrew@32: andrew@32: // int priorStartIndex = bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis); andrew@32: // int priorEndIndex = bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis); andrew@32: // ofSetColor(0,200,200);//recent prior andrew@32: // recentPrior.drawConstrainedVector(priorStartIndex, priorEndIndex, 0, ofGetWidth(), bayesPositionWindow); andrew@32: andrew@50: if (printInfo) andrew@50: drawInfo(); andrew@32: andrew@3: andrew@32: } andrew@32: andrew@32: void AudioEventMatcher::drawPositionWindow(){ andrew@32: int startIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenStartTimeMillis); andrew@32: int endIndex = bayesianStruct.posterior.getRealTermsAsIndex(screenEndTimeMillis); andrew@32: string tmpString = "start "+ofToString(screenStartTimeMillis)+" (index "+ofToString(startIndex)+"), end "+ofToString(screenEndTimeMillis); andrew@32: ofDrawBitmapString(tmpString, bayesPositionWindow.x+20, bayesPositionWindow.y+20); andrew@32: andrew@32: //draw posterior in the bayes position window andrew@32: ofSetColor(255,0,255); andrew@32: bayesianStruct.posterior.drawConstrainedVector(startIndex, endIndex, 0, ofGetWidth(), bayesPositionWindow); 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@32: 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@32: andrew@32: ofSetColor(255,0,100);//purple prior andrew@32: bayesianStruct.prior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); andrew@16: andrew@32: ofSetColor(255,0,0);//projected prior in red andrew@32: projectedPrior.drawConstrainedVector(bayesianStruct.prior.getRealTermsAsIndex(screenStartTimeMillis), bayesianStruct.prior.getRealTermsAsIndex(screenEndTimeMillis), 0, ofGetWidth(), bayesPositionWindow); andrew@16: andrew@37: //draw pitch andrew@37: ofSetColor(0,100,255); andrew@37: int index = getScreenWidthIndexOfEventTime(recentPitchEventTime); andrew@37: //this window would be used (recordedTracks.loadedAudioFiles[1].fileLoader.onsetDetect.window); andrew@16: andrew@53: ofSetColor(255, 255, 255); andrew@53: ofDrawBitmapString("curr.speed "+ofToString(synchroniser.smoothedSpeedOutput, 3), 20, ofGetHeight() - 10); andrew@53: andrew@32: } andrew@32: andrew@37: int AudioEventMatcher::getScreenWidthIndexOfEventTime(const double& time){ andrew@53: return (time - screenStartTimeMillis andrew@53: )*ofGetWidth()/screenWidthMillis; andrew@37: } andrew@37: andrew@32: void AudioEventMatcher::drawTrackLikelihoods(){ 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@37: recentPitchEventTime = timeIn; andrew@7: } andrew@53: checkTempo(); andrew@32: } andrew@32: andrew@32: andrew@32: void AudioEventMatcher::newChromaEvent(const int& channel, float* chromaIn, const double& timeIn){ andrew@32: andrew@32: // could add event to the liveInput list? as in pitch event andrew@37: if (printingData){ andrew@37: printf("match chroma channel %i\n", channel); andrew@37: for (int i = 0;i < 12;i++){ andrew@34: printf("chroma in[%i] = %f\n", i, chromaIn[i]); andrew@37: } andrew@34: } andrew@34: andrew@32: matchNewChromaEvent(channel, chromaIn, timeIn);//main pitch matching fn andrew@32: andrew@32: likelihoodVisualisation[channel] = bayesianStruct.likelihood; andrew@32: andrew@53: checkTempo(); andrew@2: } andrew@2: andrew@32: andrew@6: void AudioEventMatcher::newKickEvent(const double& timeIn){ andrew@6: // liveInput.addKickEvent(timeIn); andrew@53: newKickEvent(0, timeIn); andrew@53: // matchNewOnsetEvent(0, timeIn); andrew@53: // 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@53: checkTempo(); andrew@6: } andrew@6: andrew@2: andrew@2: void AudioEventMatcher::newSnareEvent(const double& timeIn){ andrew@53: newSnareEvent(2, timeIn); andrew@53: andrew@53: // matchNewOnsetEvent(2, timeIn); andrew@53: // likelihoodVisualisation[2] = bayesianStruct.likelihood; 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@53: checkTempo(); andrew@2: } andrew@2: andrew@53: void AudioEventMatcher::checkTempo(){ andrew@53: andrew@53: if (synchroniser.speed > 0.92 && synchroniser.speed < 1.08){ andrew@53: // double relativeTempo = 1 + andrew@53: // relativeTempo += 0.4 * (synchroniser.speed - relativeTempo); andrew@53: printf("Speed %f new tempo %f\n\n", synchroniser.speed, synchroniser.smoothedSpeedOutput); andrew@53: setSpeedRatioDistribution(synchroniser.smoothedSpeedOutput); andrew@53: } andrew@53: andrew@53: } andrew@53: andrew@53: andrew@50: #pragma mark -EventMatching 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@2: bayesianStruct.likelihood.offset = bayesianStruct.prior.offset; andrew@2: bayesianStruct.likelihood.zero();//set to zero andrew@36: //double quantity = 1;// andrew@53: double quantity; andrew@53: andrew@53: switch (channel) { andrew@53: case 0: andrew@53: quantity = kickLikelihoodToNoise;// onsetLikelihoodToNoise; andrew@53: //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches; andrew@53: break; andrew@53: case 2: andrew@53: quantity = snareLikelihoodToNoise;// onsetLikelihoodToNoise; andrew@53: //BETTER CHANGE THIS BACK TOO..see below//likelihoodToNoiseRatio / numberOfMatches; andrew@53: break; andrew@53: } andrew@53: andrew@53: andrew@53: andrew@2: int numberOfMatchesFound = 0; andrew@45: double nearestOnsetDistance = 1000; andrew@10: double startMatchingTime = bayesianStruct.likelihood.offset; andrew@10: double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth; andrew@32: double millisTime = -1*INFINITY;//or 0 is fine andrew@32: int checkIndex = 0; andrew@36: if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){ andrew@32: while (millisTime < startMatchingTime) { andrew@32: millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime; andrew@32: checkIndex++; andrew@32: } andrew@32: for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){ andrew@32: 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@45: if (fabs(currentAlignmentPosition - millisTime) < nearestOnsetDistance) andrew@45: nearestOnsetDistance = currentAlignmentPosition - millisTime; andrew@32: }//end if within limits (changed so it now is 4 sure) andrew@2: } andrew@2: } andrew@2: andrew@11: if (numberOfMatchesFound > 0){ andrew@3: // bayesianStruct.likelihood.addConstant((1-likelihoodToNoiseRatio)/bayesianStruct.likelihood.length); andrew@36: // bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-onsetLikelihoodToNoise)/(onsetLikelihoodToNoise*bayesianStruct.likelihood.length)); andrew@53: bayesianStruct.likelihood.addConstant(numberOfMatchesFound*(1-quantity)/(bayesianStruct.likelihood.length));//BETTER CHANGE THIS BACK... 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@45: int timeNow = getTimeNow(); andrew@11: andrew@45: printf("Nearest onset is %.1f time is %i and alignemnt %i time now %i\n", nearestOnsetDistance, (int) timeIn, (int)currentAlignmentPosition, timeNow); 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@32: double totalLikelihoodAdded = 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@56: quantity = getPitchDistance(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].aubioPitch, pitchIn, pitchWidth); andrew@18: andrew@56: bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, pitchLikelihoodWidth, quantity); andrew@3: recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].matched = true; andrew@3: numberOfMatches++; andrew@32: totalLikelihoodAdded += quantity; 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@37: if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match andrew@32: //replacing numberOfMatches with totalLike below... andrew@37: //bug here was that if totaladded = 0, we add then zero likelihood andrew@37: bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-pitchLikelihoodToNoise)/(bayesianStruct.likelihood.length)); andrew@37: // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(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@32: 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@32: //printf("[pitch distance %f vs %f, factor %i = %f\n", pitchOne, pitchTwo, multiplicationFactor, 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@32: if (abs(recordedPitch - livePitch * multiplicationFactor) < pitchCutOff) 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@32: void AudioEventMatcher::matchNewChromaEvent(const int& channel, float* chromaIn, const double& timeIn){ andrew@32: //start at beginning but OPTIMISE later andrew@32: andrew@52: makeQuantisedChroma(chromaIn); andrew@52: andrew@32: bayesianStruct.updateBayesianDistributions(timeIn);//moves the posterior up into prior given the time interval and calculates new offsets andrew@32: andrew@32: //set the likelihoods by matching the pitched note andrew@32: andrew@32: int numberOfMatches = 0; andrew@32: bayesianStruct.likelihood.zero();//set to zero andrew@32: double newOnsetTime; andrew@32: double closestDistance = INFINITY; andrew@32: andrew@32: double quantity = 1; andrew@32: double totalLikelihoodAdded = 0; andrew@32: andrew@32: double startMatchingTime = bayesianStruct.likelihood.offset; andrew@32: double endMatchingTime = bayesianStruct.likelihood.offset + matchWindowWidth; andrew@32: double millisTime = -1*INFINITY;//or 0 is fine andrew@32: andrew@32: int checkIndex = 0; andrew@37: if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){ andrew@37: andrew@32: while (millisTime < startMatchingTime) { andrew@32: millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime; andrew@32: checkIndex++; andrew@32: }//go up to where we need to check from fast andrew@32: andrew@32: for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){ andrew@32: millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; andrew@32: andrew@32: if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){ andrew@35: andrew@52: //for cts chroma andrew@52: /* andrew@35: if (useChromaDotProduct) andrew@35: quantity = getChromaDotProductDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]); andrew@35: else andrew@35: quantity = getChromaEuclideanDistance(chromaIn, &recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].chromaValues[0]); andrew@52: */ andrew@52: // printf("Distance old way %f", quantity); andrew@35: andrew@52: //for quantised chroma andrew@52: quantity = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].getChromaQuantisedDistance(&quantisedChromagramReceived[0]); andrew@52: andrew@52: // printf(" quantised %f\n", quantity); andrew@35: andrew@32: bayesianStruct.likelihood.addGaussianShapeFromRealTime(recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime, chromaLikelihoodWidth, quantity); andrew@32: andrew@32: // bayesianStruct.likelihood.addGaussianShapeFromRealTime(millisTime, onsetLikelihoodWidth, quantity); andrew@32: numberOfMatches++; andrew@32: totalLikelihoodAdded += quantity; andrew@37: andrew@37: //printf("Adding CHROMA Gaussian for onset at time %.1f dist %.3f\n", millisTime, quantity); andrew@32: andrew@32: }//end if within limits (changed so it now is 4 sure) andrew@32: } andrew@32: } andrew@32: andrew@32: andrew@37: if (numberOfMatches > 0 && totalLikelihoodAdded > 0){//no point updating unless there is a match andrew@32: //replacing numberOfMatches with totalLike below... andrew@32: andrew@32: printf("CHROMA HAS %i MATCHES\n", numberOfMatches); andrew@32: andrew@37: bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(bayesianStruct.likelihood.length)); andrew@37: //previous way andrew@37: // bayesianStruct.likelihood.addConstant(totalLikelihoodAdded*(1-chromaLikelihoodToNoise)/(chromaLikelihoodToNoise*bayesianStruct.likelihood.length)); andrew@32: andrew@32: bayesianStruct.calculatePosterior(); andrew@32: lastAlignmentTime = timeIn;//has to use the STAMPED time andrew@32: recentEventTime[channel] = timeIn; andrew@32: andrew@32: recentPriors[channel] = bayesianStruct.prior; andrew@32: projectedPrior = bayesianStruct.prior; andrew@32: andrew@32: temporal.eventTimes[channel].push_back(timeIn); andrew@32: } andrew@32: andrew@32: } andrew@32: andrew@52: void AudioEventMatcher::makeQuantisedChroma(float* chromaIn){ andrew@52: double L_norm = 0; andrew@52: andrew@52: for (int i = 0;i < 12;i++){ andrew@52: L_norm += chromaIn[i]; andrew@52: } andrew@52: andrew@52: if (L_norm > 0){ andrew@52: for (int i = 0;i < 12;i++){ andrew@52: chromaIn[i] /= L_norm;//NB not const fn! andrew@52: quantisedChromagramReceived[i] = 0; andrew@52: andrew@52: if (chromaIn[i] > 0.05) andrew@52: quantisedChromagramReceived[i]++; andrew@52: andrew@52: if (chromaIn[i] > 0.1) andrew@52: quantisedChromagramReceived[i]++; andrew@52: andrew@52: if (chromaIn[i] > 0.2) andrew@52: quantisedChromagramReceived[i]++; andrew@52: andrew@52: if (chromaIn[i] > 0.4) andrew@52: quantisedChromagramReceived[i]++; andrew@52: andrew@52: } andrew@52: } andrew@52: } andrew@32: andrew@35: double AudioEventMatcher::getChromaDotProductDistance(float* chromaOne, float* chromaTwo){ andrew@32: double distance = 0; andrew@32: double total = 0; andrew@32: for (int i = 0;i < 12;i++){ andrew@32: distance += chromaOne[i]*chromaTwo[i]; andrew@32: total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]); andrew@32: } andrew@32: andrew@35: if (total > 0) andrew@35: distance /= sqrt(total); andrew@35: andrew@35: return distance; andrew@35: } andrew@35: andrew@35: double AudioEventMatcher::getChromaEuclideanDistance(float* chromaOne, float* chromaTwo){ andrew@35: double distance = 0; andrew@35: double total = 0; andrew@37: andrew@35: // printf("\n"); andrew@35: for (int i = 0;i < 12;i++){ andrew@35: total += (chromaOne[i] - chromaTwo[i])*(chromaOne[i] - chromaTwo[i]); andrew@35: // printf("chroma1: %.2f; chroma2: %.2f\n", chromaOne[i], chromaTwo[i]); andrew@35: // total += chromaOne[i]*chromaOne[i] + (chromaTwo[i]*chromaTwo[i]); andrew@35: } andrew@35: andrew@37: if (total > euclideanMaximumDistance) andrew@37: euclideanMaximumDistance = total; andrew@37: andrew@37: distance = ((euclideanMaximumDistance - total)/ euclideanMaximumDistance);//i.e. 1 is andrew@37: andrew@37: // if (total > 0) andrew@37: andrew@37: andrew@37: // distance = 1.0/sqrt(total); andrew@35: // printf("DISTANCE : %.3f\n", distance); andrew@32: return distance; andrew@32: } 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@50: bayesLikelihoodWindow.resized(w, h); andrew@3: } andrew@3: andrew@52: void AudioEventMatcher::writeAllDistributions(){ andrew@55: std::string filepath = "../../../data/distributions/priorDistbnOutput.txt"; andrew@53: writeDistribution(bayesianStruct.prior, filepath); andrew@55: filepath = "../../../data/distributions/likelihoodDistbnOutput.txt"; andrew@53: writeDistribution(bayesianStruct.likelihood, filepath); andrew@55: filepath = "../../../data/distributions/posteriorDistbnOutput.txt"; andrew@53: writeDistribution(bayesianStruct.posterior, filepath); andrew@52: andrew@55: //write kick events andrew@55: filepath = "../../../data/distributions/kickEvents.txt"; andrew@55: writeKickEvent(screenStartTimeMillis, screenEndTimeMillis, filepath); andrew@55: andrew@55: ofBackground(255); andrew@52: recordedTracks.drawTracks(); andrew@55: filepath = "../../../data/distributions/screenGraphics.png"; andrew@52: img.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); andrew@52: img.saveImage(filepath); andrew@55: andrew@55: ofBackground(0); andrew@52: } andrew@52: andrew@52: void AudioEventMatcher::writeDistribution(DynamicVector& distribution, std::string filename){ andrew@52: testDistributionOutput.openFile(filename); andrew@52: andrew@52: int minIndex = distribution.getRealTermsAsIndex(screenStartTimeMillis); andrew@52: int maxIndex = distribution.getRealTermsAsIndex(screenEndTimeMillis); andrew@52: int minScreenIndex = 0; andrew@52: int maxScreenIndex = ofGetWidth(); andrew@52: andrew@52: double stepSize = (maxScreenIndex - minScreenIndex) / (double)(maxIndex - minIndex);//step size in pixels per array bin andrew@52: double screenHeight = ofGetHeight(); andrew@52: double maxVal = distribution.getMaximum(); andrew@52: andrew@52: //OPTIMIZE!! XXX could just add stepsize each time andrew@52: //not add minindex each time andrew@52: int i = max(1,minIndex+1); andrew@52: // ofDrawBitmapString("i = "+ofToString(i)+" :: screen min: "+ofToString(minScreenIndex + stepSize*(i-minIndex-1)), 20, 640); andrew@52: andrew@52: while ((minScreenIndex + stepSize*(i-minIndex)) < 0) andrew@52: i++;//only draw what is on the screen andrew@52: andrew@52: for ( ; i < min(maxIndex+1, (int)distribution.array.size());i++){ andrew@52: andrew@55: //as array indices andrew@55: // testDistributionOutput.writeValue(minScreenIndex + (stepSize*(i-minIndex-1)), distribution.array[i-1]); andrew@55: andrew@55: //as millis: andrew@55: testDistributionOutput.writeValue(distribution.getIndexInRealTerms(i), distribution.array[i-1]); andrew@52: } andrew@52: testDistributionOutput.closeFile(); andrew@52: } andrew@52: andrew@55: void AudioEventMatcher::writeKickEvent(const int& startMatchingTime, const int& endMatchingTime, std::string filepath){ andrew@55: andrew@55: int channel = 0;//i.e. kick andrew@55: andrew@55: if (!testDistributionOutput.outputFile.is_open()) andrew@55: testDistributionOutput.closeFile(); andrew@55: andrew@55: testDistributionOutput.outputFile.open(filepath.c_str()); andrew@55: andrew@55: testDistributionOutput.outputFile << startMatchingTime << "\t" << 0 << endl; andrew@55: int checkIndex = 0; andrew@55: double millisTime = 0; andrew@55: if (channel <= recordedTracks.numberOfAudioTracks && checkIndex < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size()){ andrew@55: while (millisTime < startMatchingTime) { andrew@55: millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[checkIndex].millisTime; andrew@55: checkIndex++; andrew@55: } andrew@55: for (int i = checkIndex;i < recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets.size() && millisTime <= endMatchingTime;i++){ andrew@55: millisTime = recordedTracks.loadedAudioFiles[channel].fileLoader.onsetDetect.chromaOnsets[i].millisTime; andrew@55: if (millisTime >= startMatchingTime && millisTime <= endMatchingTime){ andrew@55: andrew@55: testDistributionOutput.outputFile << (int) millisTime - 1 << "\t" << 0 << endl; andrew@55: testDistributionOutput.outputFile << (int) millisTime << "\t" << 1 << endl; andrew@55: testDistributionOutput.outputFile << (int) millisTime + 1 << "\t" << 0 << endl; andrew@55: }//end if within limits (changed so it now is 4 sure) andrew@55: } andrew@55: } andrew@55: andrew@55: testDistributionOutput.outputFile << endMatchingTime << "\t" << 0 << endl; andrew@55: andrew@55: testDistributionOutput.closeFile(); andrew@55: andrew@55: } andrew@55: 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: