@@ -146,20 +146,45 @@ void InputState::setVoice(voice_idx_t v)
146
146
}
147
147
148
148
const track_idx_t newTrack = (m_track / VOICES) * VOICES + v;
149
+ Segment* currSeg = segment ();
150
+ if (!currSeg || currSeg->cr (newTrack)) {
151
+ setTrack (newTrack);
152
+ return ;
153
+ }
149
154
150
- // TODO: Inserting notes to a new voice in the middle of a tuplet is not yet supported. In this case
151
- // we'll move the input to the start of the tuplet...
152
- if (const Segment* prevSeg = segment ()) {
153
- const ChordRest* prevCr = prevSeg->cr (track ());
154
- // ! NOTE: if there's an existing ChordRest at the new voiceIndex, we don't need to move the cursor
155
- if (prevCr && prevCr->topTuplet () && !prevSeg->cr (newTrack)) {
156
- Segment* newSeg = score->tick2segment (prevCr->topTuplet ()->tick ());
157
- if (newSeg) {
158
- setSegment (newSeg);
159
- }
155
+ // If we haven't returned early - it means that currSeg doesn't have a valid ChordRest for the desired voice. If
156
+ // tuplets are involved, we may need to move the input position backwards to the last valid ChordRest...
157
+ Segment* candidateSeg = currSeg;
158
+
159
+ // First thing to check - is currSeg part of a tuplet? If so, move candidateSeg to the start of that tuplet...
160
+ const ChordRest* currCR = currSeg->cr (track ());
161
+ const Tuplet* currTuplet = currCR ? currCR->topTuplet () : nullptr ;
162
+ if (currTuplet) {
163
+ candidateSeg = score->tick2segment (currTuplet->tick ());
164
+ IF_ASSERT_FAILED (candidateSeg) {
165
+ setSegment (currSeg->measure ()->first ());
166
+ setTrack (newTrack);
167
+ return ;
168
+ }
169
+ }
170
+
171
+ // If candidateSeg still doesn't have a valid ChordRest for the desired voice, we'll now check whether it is
172
+ // within the range of a tuplet at our desired voice. If so, move candidateSeg to the start of that tuplet...
173
+ const ChordRest* nextCR = candidateSeg->nextChordRest (newTrack, /* backwards*/ true , /* stopAtMeasureBoundary*/ true );
174
+ const Tuplet* nextTuplet = nextCR ? nextCR->topTuplet () : nullptr ;
175
+ if (!candidateSeg->cr (newTrack) && nextTuplet) {
176
+ candidateSeg = score->tick2segment (nextTuplet->tick ());
177
+ IF_ASSERT_FAILED (candidateSeg) {
178
+ setSegment (currSeg->measure ()->first ());
179
+ setTrack (newTrack);
180
+ return ;
160
181
}
161
182
}
162
183
184
+ if (candidateSeg != currSeg) {
185
+ setSegment (candidateSeg);
186
+ }
187
+
163
188
setTrack (newTrack);
164
189
}
165
190
0 commit comments