comparison src/Silvet.cpp @ 343:460cabb27bf7

Make the onset/offset output consistent with the notes output in terms of restarting notes when a shift changes
author Chris Cannam
date Wed, 12 Aug 2015 14:50:30 +0100
parents 705d807ca2ca
children c9a0015413e2
comparison
equal deleted inserted replaced
342:ad45b18427e0 343:460cabb27bf7
1081 } 1081 }
1082 1082
1083 if (active.find(note) == active.end()) { 1083 if (active.find(note) == active.end()) {
1084 // the note was playing but just ended 1084 // the note was playing but just ended
1085 m_current.erase(note); 1085 m_current.erase(note);
1086 emitNote(start, end, note, noteFeatures); 1086 emitNoteAndOffset(start, end, note, noteFeatures, onOffsetFeatures);
1087 emitOffset(start, end, note, onOffsetFeatures);
1088 } else { // still playing 1087 } else { // still playing
1089 // repeated note detection: if level is greater than this 1088 // repeated note detection: if level is greater than this
1090 // multiple of its previous value, then we end the note and 1089 // multiple of its previous value, then we end the note and
1091 // restart it with the same pitch 1090 // restart it with the same pitch
1092 double restartFactor = 1.5; 1091 double restartFactor = 1.5;
1093 if (duration >= durationThreshold * 2 && 1092 if (duration >= durationThreshold * 2 &&
1094 (active.find(note)->second > 1093 (active.find(note)->second >
1095 restartFactor * m_pianoRoll[width-1][note])) { 1094 restartFactor * m_pianoRoll[width-1][note])) {
1096 m_current.erase(note); 1095 m_current.erase(note);
1097 emitNote(start, end-1, note, noteFeatures); 1096 emitNoteAndOffset(start, end-1, note, noteFeatures, onOffsetFeatures);
1098 emitOffset(start, end-1, note, onOffsetFeatures);
1099 // and remove this so that we start counting the new 1097 // and remove this so that we start counting the new
1100 // note's duration from the current position 1098 // note's duration from the current position
1101 m_pianoRoll[width-1].erase(note); 1099 m_pianoRoll[width-1].erase(note);
1102 } 1100 }
1103 } 1101 }
1107 1105
1108 return { noteFeatures, onsetFeatures, onOffsetFeatures }; 1106 return { noteFeatures, onsetFeatures, onOffsetFeatures };
1109 } 1107 }
1110 1108
1111 void 1109 void
1112 Silvet::emitNote(int start, int end, int note, FeatureList &noteFeatures) 1110 Silvet::emitNoteAndOffset(int start, int end, int note,
1113 { 1111 FeatureList &noteFeatures,
1112 FeatureList &onOffsetFeatures)
1113 {
1114 // Emit the complete note-event feature, and its offset. We have
1115 // already emitted the note onset when it started -- that process
1116 // is separated out in order to get a faster response during live
1117 // tracking. However, if the note shift changes within the note
1118 // (which can happen only if we have fine-tuning switched on), we
1119 // emit an offset and then a new onset with the new shift.
1120
1114 int partStart = start; 1121 int partStart = start;
1115 int partShift = 0; 1122 int partShift = 0;
1116 double partStrength = 0; 1123 double partStrength = 0;
1117 1124
1125 // NB this *must* be less than durationThreshold above
1118 int partThreshold = floor(0.05 * m_colsPerSec); 1126 int partThreshold = floor(0.05 * m_colsPerSec);
1119 1127
1120 for (int i = start; i != end; ++i) { 1128 for (int i = start; i != end; ++i) {
1121 1129
1122 double strength = m_pianoRoll[i][note]; 1130 double strength = m_pianoRoll[i][note];
1130 if (i == partStart) { 1138 if (i == partStart) {
1131 partShift = shift; 1139 partShift = shift;
1132 } 1140 }
1133 1141
1134 if (i > partStart + partThreshold && shift != partShift) { 1142 if (i > partStart + partThreshold && shift != partShift) {
1135
1136 // cerr << "i = " << i << ", partStart = " << partStart << ", shift = " << shift << ", partShift = " << partShift << endl;
1137 1143
1138 // pitch has changed, emit an intermediate note 1144 // pitch has changed, emit an intermediate note
1139 noteFeatures.push_back(makeNoteFeature(partStart, 1145 noteFeatures.push_back(makeNoteFeature(partStart,
1140 i, 1146 i,
1141 note, 1147 note,
1142 partShift, 1148 partShift,
1143 partStrength)); 1149 partStrength));
1150
1151 onOffsetFeatures.push_back(makeOffsetFeature(i,
1152 note,
1153 partShift));
1154
1144 partStart = i; 1155 partStart = i;
1145 partShift = shift; 1156 partShift = shift;
1157
1158 onOffsetFeatures.push_back(makeOnsetFeature(i,
1159 note,
1160 partShift,
1161 partStrength));
1162
1146 partStrength = 0; 1163 partStrength = 0;
1147 } 1164 }
1148 } 1165 }
1149 1166
1150 if (strength > partStrength) { 1167 if (strength > partStrength) {
1151 partStrength = strength; 1168 partStrength = strength;
1152 } 1169 }
1153 } 1170 }
1154 1171
1155 if (end >= partStart + partThreshold) { 1172 if (end >= partStart + partThreshold) {
1173
1156 noteFeatures.push_back(makeNoteFeature(partStart, 1174 noteFeatures.push_back(makeNoteFeature(partStart,
1157 end, 1175 end,
1158 note, 1176 note,
1159 partShift, 1177 partShift,
1160 partStrength)); 1178 partStrength));
1179
1180 onOffsetFeatures.push_back(makeOffsetFeature(end,
1181 note,
1182 partShift));
1161 } 1183 }
1162 } 1184 }
1163 1185
1164 void 1186 void
1165 Silvet::emitOnset(int start, int note, FeatureList &onOffsetFeatures) 1187 Silvet::emitOnset(int start, int note, FeatureList &onOffsetFeatures)
1184 1206
1185 onOffsetFeatures.push_back(makeOnsetFeature(start, 1207 onOffsetFeatures.push_back(makeOnsetFeature(start,
1186 note, 1208 note,
1187 shift, 1209 shift,
1188 onsetStrength)); 1210 onsetStrength));
1189 }
1190
1191 void
1192 Silvet::emitOffset(int start, int end, int note, FeatureList &onOffsetFeatures)
1193 {
1194 int shift = 0;
1195 if (getShiftCount() > 1) {
1196 shift = m_pianoRollShifts[start][note];
1197 }
1198
1199 onOffsetFeatures.push_back(makeOffsetFeature(end,
1200 note,
1201 shift));
1202 } 1211 }
1203 1212
1204 RealTime 1213 RealTime
1205 Silvet::getColumnTimestamp(int column) 1214 Silvet::getColumnTimestamp(int column)
1206 { 1215 {