comparison jnmr/midiEventHolder.cpp @ 50:158f5f38e9d3

outputting exact difference for annotations, comparison with match annotations is now working over all rwc files
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Thu, 29 Mar 2012 13:41:59 +0100
parents 3ce6dadd8167
children 13194a9dca77
comparison
equal deleted inserted replaced
49:3ce6dadd8167 50:158f5f38e9d3
33 33
34 useTempoPrior = false;//puts sine wave round tempo 34 useTempoPrior = false;//puts sine wave round tempo
35 confidenceWeightingUsed = true; 35 confidenceWeightingUsed = true;
36 newOptimalMethod = true; 36 newOptimalMethod = true;
37 37
38 matchWindowWidth = 16000;//window size for matching in ms 38 matchWindowWidth = 20000;//window size for matching in ms
39 interNoteRange = 1600;//preferred duration 39 interNoteRange = 1600;//preferred duration
40 //so max here is really four 40 //so max here is really four
41 41
42 42
43 likelihoodWidth = 100;//using 100 is good 43 likelihoodWidth = 100;//using 100 is good
44 likelihoodToNoiseRatio = 0.20;//was 0.02 on 18/11/11, changing to give more weight to observations 44 likelihoodToNoiseRatio = 0.20;//was 0.02 on 18/11/11, changing to give more weight to observations
45 //was 0.08 on 11/12/11 but need more for tempo varn in rwc database 45 //was 0.08 on 11/12/11 but need more for tempo varn in rwc database
46 46
47 bayesStruct.speedLikelihoodNoise = 0.1;//was 0.05 47 bayesStruct.speedLikelihoodNoise = 0.2;//changed from 0.1, was 0.05
48 bayesStruct.speedDecayWidth = 40; 48 bayesStruct.speedDecayWidth = 40;
49 bayesStruct.speedDecayAmount = 10; 49 bayesStruct.speedDecayAmount = 10;
50 50
51 drawTempoMode = false; 51 drawTempoMode = false;
52 //there is option to use MAP estinate or integral in beayesianarraystricture class 52 //there is option to use MAP estinate or integral in beayesianarraystricture class
129 recordedTotalNoteCounterByPitch.assign(127,0); 129 recordedTotalNoteCounterByPitch.assign(127,0);
130 totalNoteCounterIndex = 0; 130 totalNoteCounterIndex = 0;
131 131
132 interNoteIntervals.clear(); 132 interNoteIntervals.clear();
133 133
134 smoothIndex = 0; 134 outputIndex = 0;
135 smoothPlayPosition = 0.0; 135 smoothPlayPosition = 0.0;
136 causalPlayPosition = 0; 136 causalPlayPosition = 0;
137 lastCausalUpdateTime = getTimeNow(0); 137 lastCausalUpdateTime = getTimeNow(0);
138 138
139 // relativeSpeedForSmooth = 1.0; 139 // relativeSpeedForSmooth = 1.0;
153 updatePeriodValue(0);// periodValues[0][2]; 153 updatePeriodValue(0);// periodValues[0][2];
154 printf("Resetting period to %f , size is %i\n", period, (int)periodValues.size()); 154 printf("Resetting period to %f , size is %i\n", period, (int)periodValues.size());
155 } 155 }
156 */ 156 */
157 //period = 500.0; 157 //period = 500.0;
158 }
159
160 void midiEventHolder::testSpeedPriorSetting(){
161 if (speedPriorValue > 2){
162 bayesStruct.resetSpeedSize(speedPriorValue * 200);
163 bayesStruct.setRelativeSpeedScalar(0.01);
164 bayesStruct.relativeSpeedPrior.getMaximum();
165 printf("SPEED SIZE EXCEEDS MAXIMUM!!! RESETTING TO SIXE %i\n", (int)(speedPriorValue * 200));
166 }
167 else{
168 bayesStruct.resetSpeedSize(200);
169 bayesStruct.setRelativeSpeedScalar(0.01);
170 bayesStruct.relativeSpeedPrior.getMaximum();
171 }
172
158 } 173 }
159 174
160 void midiEventHolder::setMatchedNotesBackToFalse(){ 175 void midiEventHolder::setMatchedNotesBackToFalse(){
161 for (int i = 0;i < noteOnMatches.size();i++) 176 for (int i = 0;i < noteOnMatches.size();i++)
162 noteOnMatches[i] = false; 177 noteOnMatches[i] = false;
307 322
308 } 323 }
309 324
310 void midiEventHolder::updateTempo(){ 325 void midiEventHolder::updateTempo(){
311 //having found matches we have matches for new note and matches for previous notes 326 //having found matches we have matches for new note and matches for previous notes
312 if (newOptimalMethod) 327 if (newOptimalMethod)//now true
313 findOptimumTempoPairsToCurrentBestMatch(); 328 findOptimumTempoPairsToCurrentBestMatch();
314 else if (!confidenceWeightingUsed) 329 else if (!confidenceWeightingUsed)
315 findLocalTempoPairs(); 330 findLocalTempoPairs();
316 else 331 else
317 findLocalTempoPairsWeightedForConfidence(); 332 findLocalTempoPairsWeightedForConfidence();
318
319 333
320 //bayesStruct.addGaussianNoiseToSpeedPosterior(10); 334 //bayesStruct.addGaussianNoiseToSpeedPosterior(10);
321 } 335 }
322 336
323 double midiEventHolder::getTimeNow(double eventTime){ 337 double midiEventHolder::getTimeNow(double eventTime){
374 int startIndex = 0; 388 int startIndex = 0;
375 389
376 if (recordedEventTimes.size() > 0){ 390 if (recordedEventTimes.size() > 0){
377 391
378 //get to the right range of events to check in 392 //get to the right range of events to check in
393 //OPTIMIZE!
379 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime) 394 while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime)
380 startIndex++; 395 startIndex++;
381 396
382 } 397 }
383 398
394 //so startIndex is registered as a match 409 //so startIndex is registered as a match
395 410
396 double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]); 411 double eventConfidence = bayesStruct.posterior.getValueAtMillis(recordedEventTimes[startIndex]);
397 if (eventConfidence > minimumConfidence){ 412 if (eventConfidence > minimumConfidence){
398 minimumConfidence = eventConfidence; 413 minimumConfidence = eventConfidence;
399 bestMatchIndex = startIndex; 414 bestMatchIndex = startIndex;//could change this to minimumMatchError below
400 } 415 }
401 d.push_back(eventConfidence); 416 d.push_back(eventConfidence);
402 417
403 double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX); 418 double confidence = eventConfidence;//bayesStruct.posterior.getValueAtMillis(mouseX);
404 // recordedEventTimes[startIndex]); 419 // recordedEventTimes[startIndex]);
406 421
407 if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){ 422 if (abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate) < tmpError){
408 //record the error between expected and observed times 423 //record the error between expected and observed times
409 tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate); 424 tmpError = abs(recordedEventTimes[startIndex] - bayesStruct.bestEstimate);
410 minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate; 425 minimumMatchError = tmpError;//recordedEventTimes[startIndex] - bayesStruct.bestEstimate;
426 // bestMatchIndex = startIndex;
411 } 427 }
412 428
413 } 429 }
414 startIndex++; 430 startIndex++;
415 } 431 }
792 } 808 }
793 809
794 //did just update smooth to current if it was less 810 //did just update smooth to current if it was less
795 811
796 if (smoothPlayPosition < bayesStruct.bestEstimate){ 812 if (smoothPlayPosition < bayesStruct.bestEstimate){
797 updateSmoothPositionTo(bayesStruct.bestEstimate); 813 // updateOutputPositionTo(bayesStruct.bestEstimate);
798 //smoothPlayPosition = bayesStruct.bestEstimate; 814 smoothPlayPosition = bayesStruct.bestEstimate;
799 } 815 }
800 816
801 817 updateOutputPositionTo(causalPlayPosition); //need it outputting before the update
802 818
803 updateCausalPlayPosition(getTimeNow(bayesStruct.lastBestEstimateUpdateTime)); 819 updateCausalPlayPosition(getTimeNow(bayesStruct.lastBestEstimateUpdateTime));
804 820
805 /* 821
822
823 //can choose to output either the smooth position (i.e. forwards)
824 //or causal play position which aims toward our current smooth position in near future
825
826
827
828 /*
806 //now we try updating it to a causal path that tries to match into the future 829 //now we try updating it to a causal path that tries to match into the future
807 if (smoothPlayPosition < causalPlayPosition){ 830 if (smoothPlayPosition < causalPlayPosition){
808 updateSmoothPositionTo(causalPlayPosition); 831 updateSmoothPositionTo(causalPlayPosition);
809 } 832 }
810 */ 833 */
820 843
821 updateNoteCounter(); 844 updateNoteCounter();
822 845
823 } 846 }
824 847
825 void midiEventHolder::updateSmoothPositionTo(const double& newPosition){ 848 void midiEventHolder::updateOutputPositionTo(const double& newPosition){
826 //smooth play position was where we last outputted notes from. 849 //smooth play position was where we last outputted notes from.
827 //checking index is there to make sense. 850 //checking index is there to make sense.
828 while (smoothIndex > 0 && recordedEventTimes[smoothIndex] > smoothPlayPosition){ 851 // double checkPosition = smoothPlayPosition;
829 smoothIndex--; 852 double checkPosition = lastUpdatePosition;
830 //printf("going backewaers on smooth, "); 853
831 } 854
832 while (smoothIndex < recordedEventTimes.size()-1 && recordedEventTimes[smoothIndex] < smoothPlayPosition){ 855 while (outputIndex > 0 && recordedEventTimes[outputIndex] > checkPosition){
833 smoothIndex++; 856 outputIndex--;
834 //printf("outputting smooth\n "); 857 // printf("going backewards, smooth time %f, ", recordedEventTimes[outputIndex]);
835 } 858 }
836 859 while (outputIndex < recordedEventTimes.size()-1 && recordedEventTimes[outputIndex] < checkPosition){
860 outputIndex++;
861 // printf("outputting smooth forwards time %f\n ", recordedEventTimes[outputIndex], checkPosition);
862 }
863
864 // printf("last output position %f, new position %f\n", checkPosition, newPosition);
865 // printf("causal pos %.0f, smooth pos %.0f, best est %.0f\n", causalPlayPosition, smoothPlayPosition, bayesStruct.bestEstimate);
866
867 outputPosition = recordedEventTimes[outputIndex];
837 868
838 double playingTime = ofGetElapsedTimeMillis(); 869 double playingTime = ofGetElapsedTimeMillis();
839 playingTime -= startPlayingTime; 870 playingTime -= startPlayingTime;
840 //now at the last one 871 //now at the last one
841 872
842 float smoothLocation = beatPositions[smoothIndex]; 873 float smoothLocation = beatPositions[outputIndex];
843 int currentNote = recordedNoteOnMatrix[smoothIndex][1]; 874 int currentNote = recordedNoteOnMatrix[outputIndex][1];
844 875
845 while (smoothIndex < recordedEventTimes.size() && recordedEventTimes[smoothIndex] < newPosition){ 876 while (outputIndex < recordedEventTimes.size() && recordedEventTimes[outputIndex] < newPosition){
846 float annotationTime = 0; 877 float annotationTime = 0;
847 float annotationLocation = 0; 878 float annotationLocation = 0;
848 int annotationTick = 0; 879 int annotationTick = 0;
849 int annotationNote = 0; 880 int annotationNote = 0;
850 float difference = 10000;//very big 881 float difference = 10000;//very big
851 float currentLocationDifference = 1.0; 882 //float currentLocationDifference = 1.0;
883
884 double amountSinceLastUpdate = 0.0;//between 0 and 1, the exact position of this event since last update
885 if (newPosition > lastUpdatePosition){
886 amountSinceLastUpdate = (recordedEventTimes[outputIndex] - lastUpdatePosition)/(newPosition - lastUpdatePosition);
887 }
888
852 float range = 1.0; 889 float range = 1.0;
853 if (smoothIndex < myNotation.rwcAnnotations.size()){ 890 if (outputIndex < myNotation.rwcAnnotations.size()){
854 //add in test here to find closest matching note 891 //add in test here to find closest matching note
855 892
856 893
857 annotationTime = myNotation.rwcAnnotations[smoothIndex].eventTime; 894 annotationTime = myNotation.rwcAnnotations[outputIndex].eventTime;
858 annotationNote = myNotation.rwcAnnotations[smoothIndex].midiNote; 895 annotationNote = myNotation.rwcAnnotations[outputIndex].midiNote;
859 annotationLocation = myNotation.rwcAnnotations[smoothIndex].beatLocation; 896 annotationLocation = myNotation.rwcAnnotations[outputIndex].beatLocation;
860 annotationTick = round(annotationLocation*480.0); 897 annotationTick = round(annotationLocation*480.0);
861 }else{ 898 }else{
862 printf("No annotaion size %i\n", (int)myNotation.rwcAnnotations.size()); 899 printf("No annotaion size %i\n", (int)myNotation.rwcAnnotations.size());
863 } 900 }
864 901
902 double exactPlayingTime = amountSinceLastUpdate*playingTime + ((1 - amountSinceLastUpdate)*lastUpdatePlayingTime);
865 difference = playingTime - (annotationTime*1000.0); 903 difference = playingTime - (annotationTime*1000.0);
866 904 double exactDifference = exactPlayingTime - (annotationTime*1000.0);
867 if ((*fileOutput).is_open()){ 905 /*
868 (*fileOutput) << fixed << beatPositions[smoothIndex] <<",\t" << recordedNoteOnMatrix[smoothIndex][1] << ",\t"; 906 //NO LONGER NEEDED ALLO
907 if ((*fileOutput).is_open()){
908 (*fileOutput) << fixed << beatPositions[outputIndex] <<",\t" << recordedNoteOnMatrix[outputIndex][1] << ",\t";
869 (*fileOutput) << playingTime ; 909 (*fileOutput) << playingTime ;
870 910
871 if ( recordedNoteOnMatrix[smoothIndex][1] == annotationNote){ 911 if ( recordedNoteOnMatrix[outputIndex][1] == annotationNote){
872 (*fileOutput) << " corresponds to " << annotationTime; 912 (*fileOutput) << " corresponds to " << annotationTime;
873 } 913 }
874 (*fileOutput) << " \n"; 914 (*fileOutput) << " \n";
875 915
876 } 916 }
877 917 */
878 printf("annotations: rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n", 918
879 recordedNoteOnMatrix[smoothIndex][0], annotationTick, recordedNoteOnMatrix[smoothIndex][1], 919 //useful printing stuff
880 beatPositions[smoothIndex], playingTime, 920 // printf("playing time %.1f, annotation time %.1f, diff %.1f\n", playingTime, (annotationTime*1000.0), difference);
881 annotationNote, annotationLocation, annotationTime, difference); 921
882 922 // printf("last posn %.1f, amount since %.2f \n" lastUpdatePosition, amountSinceLastUpdate);
883 // assert(annotationNote == recordedNoteOnMatrix[smoothIndex][1]); 923
884 assert(annotationTick == recordedNoteOnMatrix[smoothIndex][0]); 924 // printf("annotations:Diff %f rec tick time %i vs %i midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",
925 // difference, recordedNoteOnMatrix[outputIndex][0], annotationTick, recordedNoteOnMatrix[outputIndex][1],
926 // beatPositions[outputIndex], playingTime,
927 // annotationNote, annotationLocation, annotationTime, difference);
928
929 // we use exact difference as it more accurately predicts where we scheduled the note
930 // printf("diff %.1f, exact diff %.1f\n", difference, exactDifference);
931
932
933 //assert(annotationNote == recordedNoteOnMatrix[outputIndex][1]);
934 assert(annotationTick == recordedNoteOnMatrix[outputIndex][0]);
885 935
886 smoothDifference = difference; 936 smoothDifference = difference;
887 937
888 if ((*differenceOutput).is_open()){ 938 if ((*differenceOutput).is_open()){
889 (*differenceOutput) << beatPositions[smoothIndex] << "," << difference << "," << playingTime << "," << (annotationTime*1000.0) << "\n"; 939 (*differenceOutput) << beatPositions[outputIndex] << "," << exactDifference << "," << playingTime << "," << (annotationTime*1000.0) << annotationNote << difference << "\n";
890 // printf("midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n", 940 // printf("midi %i beat pos %f playing time now at %f :: annotaion %i loc % f time %f diff \t%f ms\n",
891 // recordedNoteOnMatrix[smoothIndex][1], 941 // recordedNoteOnMatrix[outputIndex][1],
892 // beatPositions[smoothIndex], playingTime, 942 // beatPositions[outputIndex], playingTime,
893 // annotationNote, annotationLocation, annotationTime, difference); 943 // annotationNote, annotationLocation, annotationTime, difference);
894 }else{ 944 }else{
895 printf("file not open\n"); 945 printf("file not open\n");
896 } 946 }
897 947
898 smoothIndex++; 948 outputIndex++;
899 } 949 }
900 950
901 951 lastUpdatePosition = newPosition;
902 smoothPlayPosition = newPosition; 952 lastUpdatePlayingTime = playingTime;
903
904 } 953 }
905 954
906 void midiEventHolder::updateCausalPlayPosition(const double& timeNow){ 955 void midiEventHolder::updateCausalPlayPosition(const double& timeNow){
907 //projected position 956 //projected position
908 957
958 //first update the speed
959 updateCausalSpeed();
960
961 causalPlayPosition += causalSpeed * (timeNow - lastCausalUpdateTime);
962 lastCausalUpdateTime = timeNow;
963
964 }
965
966 void midiEventHolder::updateCausalSpeed(){
909 double difference = bayesStruct.bestEstimate - causalPlayPosition; 967 double difference = bayesStruct.bestEstimate - causalPlayPosition;
910 causalSpeed = bayesStruct.speedEstimate; 968 causalSpeed = bayesStruct.speedEstimate;
911 causalSpeed += (difference/timeProjectionToMeet); 969 causalSpeed += (difference/timeProjectionToMeet);
912 970
913 if (causalSpeed < 0) 971 if (causalSpeed < 0)
914 causalSpeed = 0; 972 causalSpeed = 0;
915 973
916 causalPlayPosition += causalSpeed * (timeNow - lastCausalUpdateTime); 974 }
917 lastCausalUpdateTime = timeNow; 975
918
919 }
920 /* 976 /*
921 void midiEventHolder::updatePeriodValue(const double& millis){ 977 void midiEventHolder::updatePeriodValue(const double& millis){
922 978
923 double tmp = period; 979 double tmp = period;
924 980
979 1035
980 ofSetColor(255,255,255); 1036 ofSetColor(255,255,255);
981 if (checkIfMatchedNote(tmpIndex)) 1037 if (checkIfMatchedNote(tmpIndex))
982 ofSetColor(100,100,100);//0,0,255); 1038 ofSetColor(100,100,100);//0,0,255);
983 else if(noteOnMatches[tmpIndex]){ 1039 else if(noteOnMatches[tmpIndex]){
984 ofSetColor(255,0,255);//dark grey 1040 ofSetColor(255,0,255);//pink
985 } 1041 }
986 else{ 1042 else{
987 ofSetColor(255,255,255);//255,255,255); 1043 ofSetColor(255,255,255);//255,255,255);
988 } 1044 }
989 1045
1009 //orange line at best estimate 1065 //orange line at best estimate
1010 xLocation = getLocationFromMillis(bayesStruct.bestEstimate); 1066 xLocation = getLocationFromMillis(bayesStruct.bestEstimate);
1011 ofSetColor(250,250,20);//250,100,0); 1067 ofSetColor(250,250,20);//250,100,0);
1012 ofLine(xLocation, 0, xLocation, (*screenHeight)); 1068 ofLine(xLocation, 0, xLocation, (*screenHeight));
1013 1069
1070
1071 /*
1072 //cyan blue - smooth position
1014 xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate 1073 xLocation = getLocationFromMillis(smoothPlayPosition);//bayesStruct.tmpBestEstimate
1015 ofSetColor(0,250,0);//250,150, 250,100,0); 1074 ofSetColor(0,250,250);//250,150, 250,100,0);
1016 // ofLine(xLocation, 0, xLocation, (*screenHeight)); 1075 ofLine(xLocation, 0, xLocation, (*screenHeight));
1017 1076 */
1077 //bright green is the causal play position
1018 xLocation = getLocationFromMillis(causalPlayPosition);//bayesStruct.tmpBestEstimate 1078 xLocation = getLocationFromMillis(causalPlayPosition);//bayesStruct.tmpBestEstimate
1019 ofSetColor(0,250,0);//250,150, 250,100,0); 1079 ofSetColor(0,250,0);//250,150, 250,100,0);
1020 ofLine(xLocation, 0, xLocation, (*screenHeight)); 1080 ofLine(xLocation, 0, xLocation, (*screenHeight));
1021 1081
1022 //lines where matching window start and end are 1082 //lines where matching window start and end are
1047 } 1107 }
1048 1108
1049 //ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20); 1109 //ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20);
1050 ofSetColor(255,255,255); 1110 ofSetColor(255,255,255);
1051 ofDrawBitmapString(timeString, 20, 60); 1111 ofDrawBitmapString(timeString, 20, 60);
1052 ofDrawBitmapString("diff "+ofToString(smoothDifference), 20, 140); 1112 string diffString = "diff "+ofToString(smoothDifference);
1053 1113 diffString += "\ncausal posn: "+ofToString(causalPlayPosition, 0);
1054 //last played piutch 1114 diffString += "\nsmooth posn: "+ofToString(smoothPlayPosition, 0);
1115 diffString += "\noutput posn: "+ofToString(outputPosition, 0);
1116 diffString += "\nbest est: "+ofToString(bayesStruct.bestEstimate, 0);
1117 diffString += "\nlast best est: "+ofToString(bayesStruct.lastBestEstimateUpdateTime, 0);
1118
1119 ofDrawBitmapString(diffString, 20, 140);
1120
1121 //last played pitch
1055 ofSetColor(0,200,0,50); 1122 ofSetColor(0,200,0,50);
1056 int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); 1123 int yLocation = (*screenHeight) - ((lastPlayedPitch - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum));
1057 ofRect(0,yLocation, 100, noteHeight); 1124 ofRect(0,yLocation, 100, noteHeight);
1058 1125
1059 1126
1446 */ 1513 */
1447 1514
1448 /* 1515 /*
1449 JUNK SMOOTH StuffHex 1516 JUNK SMOOTH StuffHex
1450 /* 1517 /*
1451 int testIndex = smoothIndex; 1518 int testIndex = outputIndex;
1452 while (testIndex >= 0 && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){ 1519 while (testIndex >= 0 && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){
1453 1520
1454 if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){ 1521 if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){
1455 if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){ 1522 if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){
1456 currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation); 1523 currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation);
1461 } 1528 }
1462 } 1529 }
1463 testIndex--; 1530 testIndex--;
1464 } 1531 }
1465 1532
1466 testIndex = smoothIndex; 1533 testIndex = outputIndex;
1467 while (testIndex >= 0 && testIndex < myNotation.rwcAnnotations.size() && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){ 1534 while (testIndex >= 0 && testIndex < myNotation.rwcAnnotations.size() && abs(smoothLocation - myNotation.rwcAnnotations[testIndex].beatLocation) < range){
1468 1535
1469 if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){ 1536 if (myNotation.rwcAnnotations[testIndex].midiNote == currentNote){
1470 if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){ 1537 if (abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation) < currentLocationDifference){
1471 currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation); 1538 currentLocationDifference = abs(myNotation.rwcAnnotations[testIndex].beatLocation - smoothLocation);