comparison src/Silvet.cpp @ 321:213a51e197c8 livemode

Shorten duration threshold for live mode; return non-peak-picked pitch distribution from pitch distribution output
author Chris Cannam
date Wed, 29 Apr 2015 10:12:02 +0100
parents 7f9683c8de69
children 6f8fa7fc8fdc
comparison
equal deleted inserted replaced
320:7f9683c8de69 321:213a51e197c8
708 } 708 }
709 } 709 }
710 710
711 for (int i = 0; i < width; ++i) { 711 for (int i = 0; i < width; ++i) {
712 712
713 // This returns a filtered column, and pushes the 713 vector<double> filtered;
714 // up-to-max-polyphony activation column to m_pianoRoll 714
715 vector<double> filtered = postProcess 715 for (int j = 0; j < pack.templateNoteCount; ++j) {
716 (localPitches[i], localBestShifts[i], wantShifts); 716 m_postFilter[j]->push(localPitches[i][j]);
717 filtered.push_back(m_postFilter[j]->get());
718 }
717 719
718 RealTime timestamp = getColumnTimestamp(m_pianoRoll.size() - 1); 720 RealTime timestamp = getColumnTimestamp(m_pianoRoll.size() - 1);
719 float inputGain = getInputGainAt(timestamp); 721 float inputGain = getInputGainAt(timestamp);
720 722
721 Feature f; 723 Feature f;
730 f.values.resize(12); 732 f.values.resize(12);
731 for (int j = 0; j < (int)filtered.size(); ++j) { 733 for (int j = 0; j < (int)filtered.size(); ++j) {
732 f.values[j % 12] += filtered[j] / inputGain; 734 f.values[j % 12] += filtered[j] / inputGain;
733 } 735 }
734 fs[m_chromaOutputNo].push_back(f); 736 fs[m_chromaOutputNo].push_back(f);
737
738 // This pushes the up-to-max-polyphony activation column to
739 // m_pianoRoll
740 postProcess(localPitches[i], localBestShifts[i], wantShifts);
735 741
736 auto events = noteTrack(shiftCount); 742 auto events = noteTrack(shiftCount);
737 743
738 FeatureList noteFeatures = events.first; 744 FeatureList noteFeatures = events.first;
739 for (FeatureList::const_iterator fi = noteFeatures.begin(); 745 for (FeatureList::const_iterator fi = noteFeatures.begin();
894 } 900 }
895 901
896 return out; 902 return out;
897 } 903 }
898 904
899 vector<double> 905 void
900 Silvet::postProcess(const vector<double> &pitches, 906 Silvet::postProcess(const vector<double> &pitches,
901 const vector<int> &bestShifts, 907 const vector<int> &bestShifts,
902 bool wantShifts) 908 bool wantShifts)
903 { 909 {
904 const InstrumentPack &pack(getPack(m_instrument)); 910 const InstrumentPack &pack(getPack(m_instrument));
905 911
906 vector<double> filtered; 912 // Threshold for level and reduce number of candidate pitches
913
914 typedef std::multimap<double, int> ValueIndexMap;
915
916 ValueIndexMap strengths;
907 917
908 for (int j = 0; j < pack.templateNoteCount; ++j) { 918 for (int j = 0; j < pack.templateNoteCount; ++j) {
909 m_postFilter[j]->push(pitches[j]); 919
910 filtered.push_back(m_postFilter[j]->get()); 920 double strength = pitches[j];
911 } 921 if (strength < pack.levelThreshold) continue;
912 922
913 if (m_mode == LiveMode) {
914 // In live mode with only a 12-bpo CQ, we are very likely to 923 // In live mode with only a 12-bpo CQ, we are very likely to
915 // get clusters of two or three high scores at a time for 924 // get clusters of two or three high scores at a time for
916 // neighbouring semitones. Eliminate these by picking only the 925 // neighbouring semitones. Eliminate these by picking only the
917 // peaks. This means we can't recognise actual semitone chords 926 // peaks. This means we can't recognise actual semitone chords
918 // if they ever appear, but it's not as if live mode is good 927 // if they ever appear, but it's not as if live mode is good
919 // enough for that to be a big deal anyway. 928 // enough for that to be a big deal anyway.
920 for (int j = 0; j < pack.templateNoteCount; ++j) { 929 if (m_mode == LiveMode) {
921 if (j > 0 && j + 1 < pack.templateNoteCount && 930 if (j == 0 || j + 1 == pack.templateNoteCount ||
922 filtered[j] >= filtered[j-1] && 931 pitches[j] < pitches[j-1] ||
923 filtered[j] >= filtered[j+1]) { 932 pitches[j] < pitches[j+1]) {
924 } else { 933 continue;
925 filtered[j] = 0.0;
926 } 934 }
927 } 935 }
928 } 936
929
930 // Threshold for level and reduce number of candidate pitches
931
932 typedef std::multimap<double, int> ValueIndexMap;
933
934 ValueIndexMap strengths;
935
936 for (int j = 0; j < pack.templateNoteCount; ++j) {
937 double strength = filtered[j];
938 if (strength < pack.levelThreshold) continue;
939 strengths.insert(ValueIndexMap::value_type(strength, j)); 937 strengths.insert(ValueIndexMap::value_type(strength, j));
940 } 938 }
941 939
942 ValueIndexMap::const_iterator si = strengths.end(); 940 ValueIndexMap::const_iterator si = strengths.end();
943 941
962 960
963 if (wantShifts) { 961 if (wantShifts) {
964 m_pianoRollShifts.push_back(activeShifts); 962 m_pianoRollShifts.push_back(activeShifts);
965 } 963 }
966 964
967 return filtered; 965 return;
968 } 966 }
969 967
970 pair<Vamp::Plugin::FeatureList, Vamp::Plugin::FeatureList> 968 pair<Vamp::Plugin::FeatureList, Vamp::Plugin::FeatureList>
971 Silvet::noteTrack(int shiftCount) 969 Silvet::noteTrack(int shiftCount)
972 { 970 {
982 const map<int, double> &active = m_pianoRoll[width]; 980 const map<int, double> &active = m_pianoRoll[width];
983 981
984 double columnDuration = 1.0 / m_colsPerSec; 982 double columnDuration = 1.0 / m_colsPerSec;
985 983
986 // only keep notes >= 100ms or thereabouts 984 // only keep notes >= 100ms or thereabouts
987 int durationThreshold = floor(0.1 / columnDuration); // columns 985 double durationThreshSec = 0.1;
986 if (m_mode == LiveMode) durationThreshSec = 0.07;
987 int durationThreshold = floor(durationThreshSec / columnDuration); // in cols
988 if (durationThreshold < 1) durationThreshold = 1; 988 if (durationThreshold < 1) durationThreshold = 1;
989 989
990 FeatureList noteFeatures, onsetFeatures; 990 FeatureList noteFeatures, onsetFeatures;
991 991
992 if (width < durationThreshold + 1) { 992 if (width < durationThreshold + 1) {