Skip to content

Commit c6fb008

Browse files
committed
Smarter handling of tuplets when switching voices
1 parent 26e0eba commit c6fb008

File tree

1 file changed

+35
-10
lines changed

1 file changed

+35
-10
lines changed

src/engraving/dom/input.cpp

+35-10
Original file line numberDiff line numberDiff line change
@@ -146,20 +146,45 @@ void InputState::setVoice(voice_idx_t v)
146146
}
147147

148148
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+
}
149154

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;
160181
}
161182
}
162183

184+
if (candidateSeg != currSeg) {
185+
setSegment(candidateSeg);
186+
}
187+
163188
setTrack(newTrack);
164189
}
165190

0 commit comments

Comments
 (0)