diff --git a/src/engraving/dom/noteentry.cpp b/src/engraving/dom/noteentry.cpp index e3f14f763e167..7fc0795bdec73 100644 --- a/src/engraving/dom/noteentry.cpp +++ b/src/engraving/dom/noteentry.cpp @@ -450,6 +450,33 @@ Ret Score::putNote(const Position& p, bool replace) ChordRest* cr = m_is.cr(); + // If there's an overlapping ChordRest at the current input position, shorten it... + if (!cr) { + MasterScore* ms = masterScore(); + ChordRest* prevCr = m_is.segment()->nextChordRest(m_is.track(), /*backwards*/ true, /*stopAtMeasureBoundary*/ true); + if (prevCr && prevCr->endTick() > m_is.tick()) { + const Fraction overlapDuration = prevCr->endTick() - m_is.tick(); + const Fraction desiredDuration = prevCr->ticks() - overlapDuration; + + const InputState inputStateToRestore = m_is; // because changeCRlen will alter the input state + ms->changeCRlen(prevCr, desiredDuration, /*fillWithRest*/ false); + + // Fill the difference with tied notes if necessary... + const Fraction difference = desiredDuration - prevCr->ticks(); + if (prevCr->isChord() && difference.isNotZero()) { + Fraction startTick = prevCr->endTick(); + Chord* prevChord = toChord(prevCr); + const std::vector durationList = toDurationList(difference, true); + for (const TDuration& dur : durationList) { + prevChord = ms->addChord(startTick, dur, prevChord, /*genTie*/ bool(prevChord), prevChord->tuplet()); + startTick += dur.fraction(); + } + } + + m_is = inputStateToRestore; + } + } + auto checkTied = [&](){ if (!cr || !cr->isChord()) { return false; diff --git a/src/engraving/dom/segment.cpp b/src/engraving/dom/segment.cpp index 45b150802ceff..723f45630d5c4 100644 --- a/src/engraving/dom/segment.cpp +++ b/src/engraving/dom/segment.cpp @@ -585,15 +585,23 @@ Segment* Segment::nextCR(track_idx_t track, bool sameStaff) const // get the next ChordRest, start at this segment //--------------------------------------------------------- -ChordRest* Segment::nextChordRest(track_idx_t track, bool backwards) const +ChordRest* Segment::nextChordRest(track_idx_t track, bool backwards, bool stopAtMeasureBoundary) const { - for (const Segment* seg = this; seg; seg = backwards ? seg->prev1() : seg->next1()) { + const Segment* seg = this; + while (seg) { EngravingItem* el = seg->element(track); if (el && el->isChordRest()) { return toChordRest(el); } + + if (backwards) { + seg = stopAtMeasureBoundary ? seg->prev() : seg->prev1(); + continue; + } + + seg = stopAtMeasureBoundary ? seg->next() : seg->next1(); } - return 0; + return nullptr; } EngravingItem* Segment::element(track_idx_t track) const diff --git a/src/engraving/dom/segment.h b/src/engraving/dom/segment.h index ceb15329a5558..0d679055d7c87 100644 --- a/src/engraving/dom/segment.h +++ b/src/engraving/dom/segment.h @@ -138,7 +138,7 @@ class Segment final : public EngravingItem Segment* nextCR(track_idx_t track = muse::nidx, bool sameStaff = false) const; - ChordRest* nextChordRest(track_idx_t track, bool backwards = false) const; + ChordRest* nextChordRest(track_idx_t track, bool backwards = false, bool stopAtMeasureBoundary = false) const; EngravingItem* element(track_idx_t track) const; diff --git a/src/notation/internal/notationnoteinput.cpp b/src/notation/internal/notationnoteinput.cpp index 915563ecfd9a7..3fdeb12dd6e8a 100644 --- a/src/notation/internal/notationnoteinput.cpp +++ b/src/notation/internal/notationnoteinput.cpp @@ -454,6 +454,20 @@ void NotationNoteInput::setCurrentVoice(voice_idx_t voiceIndex) } mu::engraving::InputState& inputState = score()->inputState(); + + // TODO: Inserting notes to a new voice in the middle of a tuplet is not yet supported. In this case + // we'll move the input to the start of the tuplet... + if (const Segment* prevSeg = inputState.segment()) { + const ChordRest* prevCr = prevSeg->cr(inputState.track()); + //! NOTE: if there's an existing ChordRest at the new voiceIndex, we don't need to move the cursor + if (prevCr && prevCr->topTuplet() && !prevSeg->cr(voiceIndex)) { + Segment* newSeg = score()->tick2segment(prevCr->topTuplet()->tick()); + if (newSeg) { + inputState.setSegment(newSeg); + } + } + } + inputState.setVoice(voiceIndex); notifyAboutStateChanged(); }