Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/engraving/editing/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,10 @@ std::vector<Rest*> Score::setRests(const Fraction& _tick, track_idx_t track, con
f = l;
}

// Don't fill with rests a non-zero voice, *unless* it has links in voice zero
bool emptyNonZeroVoice = track2voice(track) != 0 && !measure->hasVoice(track) && tick == measure->tick();
if (emptyNonZeroVoice && !staff->trackHasLinksInVoiceZero(track)) {
// Don't fill a full measure with rests on a non-zero voice, *unless* it has links in voice zero
bool fullMeasure = tick == measure->tick() && f == measure->stretchedLen(staff);
bool emptyNonZeroVoice = track2voice(track) != 0 && !measure->hasVoice(track);
if (emptyNonZeroVoice && fullMeasure && !staff->trackHasLinksInVoiceZero(track)) {
l -= f;
measure = measure->nextMeasure();
if (!measure) {
Expand All @@ -532,10 +533,9 @@ std::vector<Rest*> Score::setRests(const Fraction& _tick, track_idx_t track, con
}

if ((measure->timesig() == measure->ticks()) // not in pickup measure
&& (measure->tick() == tick)
&& (measure->stretchedLen(staff) == f)
&& fullMeasure
&& !tuplet
&& (useFullMeasureRest)) {
&& useFullMeasureRest) {
Rest* rest = addRest(tick, track, TDuration(DurationType::V_MEASURE), tuplet);
tick += rest->actualTicks();
rests.push_back(rest);
Expand All @@ -558,6 +558,8 @@ std::vector<Rest*> Score::setRests(const Fraction& _tick, track_idx_t track, con
Rest* rest = 0;
for (const TDuration& d : dList) {
rest = addRest(tick, track, d, tuplet);
// If we're filling an empty non-zero voice make these gaps
rest->setGap(emptyNonZeroVoice && !fullMeasure);
rests.push_back(rest);
tick += rest->actualTicks();
}
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rendering/score/restlayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ InterruptionPoints RestLayout::computeInterruptionPoints(const Measure* measure,
if (gapRest || hasMergedRest || invisible) {
for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
interruptionPointSets[voice].insert(segment->rtick());
interruptionPointSets[voice].insert(segment->rtick() + segment->ticks());
interruptionPointSets[voice].insert(segment->rtick() + toChordRest(item)->actualTicks());
}
break;
}
Expand Down
192 changes: 192 additions & 0 deletions src/engraving/tests/voiceswitching_data/voiceswitching-2.mscx
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.60">
<programVersion>4.7.0</programVersion>
<programRevision></programRevision>
<Score>
<eid>sFMlmwzzOnG_ILNRNamr+pG</eid>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="audioComUrl"></metaTag>
<metaTag name="composer">Composer / arranger</metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2025-10-27</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="platform">Linux</metaTag>
<metaTag name="source"></metaTag>
<metaTag name="sourceRevisionId"></metaTag>
<metaTag name="subtitle">Subtitle</metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Untitled score</metaTag>
<Order id="orchestral">
<name>Orchestral</name>
<instrument id="piano">
<family id="keyboards">Keyboards</family>
</instrument>
<section id="woodwind" brackets="true" barLineSpan="true" thinBrackets="true">
<family>flutes</family>
<family>oboes</family>
<family>clarinets</family>
<family>saxophones</family>
<family>bassoons</family>
<unsorted group="woodwinds"/>
</section>
<section id="brass" brackets="true" barLineSpan="true" thinBrackets="true">
<family>horns</family>
<family>trumpets</family>
<family>cornets</family>
<family>flugelhorns</family>
<family>trombones</family>
<family>tubas</family>
</section>
<section id="timpani" brackets="true" barLineSpan="true" thinBrackets="true">
<family>timpani</family>
</section>
<section id="percussion" brackets="true" barLineSpan="true" thinBrackets="true">
<family>keyboard-percussion</family>
<family>drums</family>
<family>unpitched-metal-percussion</family>
<family>unpitched-wooden-percussion</family>
<family>other-percussion</family>
</section>
<family>keyboards</family>
<family>harps</family>
<family>organs</family>
<family>synths</family>
<soloists/>
<section id="voices" brackets="true" barLineSpan="false" thinBrackets="true">
<family>voices</family>
<family>voice-groups</family>
</section>
<section id="strings" brackets="true" barLineSpan="true" thinBrackets="true">
<family>orchestral-strings</family>
</section>
<unsorted/>
</Order>
<Part id="1">
<Staff>
<eid>yLTbtpuYjrL_2Upa4+LsM9L</eid>
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<bracket type="1" span="2" col="2" visible="1"/>
<barLineSpan>1</barLineSpan>
</Staff>
<trackName>Piano</trackName>
<Instrument id="piano">
<longName>Piano</longName>
<shortName>Pno.</shortName>
<trackName>Piano</trackName>
<minPitchP>21</minPitchP>
<maxPitchP>108</maxPitchP>
<minPitchA>21</minPitchA>
<maxPitchA>108</maxPitchA>
<instrumentId>keyboard.piano</instrumentId>
<clef staff="2">F</clef>
<Articulation>
<velocity>100</velocity>
<gateTime>95</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>150</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="sforzatoStaccato">
<velocity>150</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoStaccato">
<velocity>120</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoTenuto">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="0"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<eid>R0Ms9HgYTs_Z6F7QI7s5JN</eid>
<voice>
<KeySig>
<eid>D/xXUPh7WdE_reZf5mJn+rN</eid>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<eid>EFsX1i3AOML_g3rEJvJe0FL</eid>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Chord>
<eid>LhFBK1lGKgE_4Oqi75gCRpL</eid>
<durationType>quarter</durationType>
<Note>
<eid>kEiL+JIyKaB_Br8MHf3MwqC</eid>
<pitch>67</pitch>
<tpc>15</tpc>
</Note>
</Chord>
<Chord>
<eid>NbZC+YdlrQE_aV2BwgrVuDN</eid>
<durationType>quarter</durationType>
<Note>
<eid>BCUbEFHVj2M_gg/VFZrm7sO</eid>
<pitch>67</pitch>
<tpc>15</tpc>
</Note>
</Chord>
<Chord>
<eid>9XshPS74OBP_hssb+Zs/VLI</eid>
<durationType>quarter</durationType>
<Note>
<eid>1Pe/TGT9rzK_VdIu9Juc2F</eid>
<pitch>67</pitch>
<tpc>15</tpc>
</Note>
</Chord>
<Chord>
<eid>UjXt9EC39YL_LJGi/kylO4C</eid>
<durationType>quarter</durationType>
<Note>
<eid>nBCZaNYI51D_PXlNUGn76+N</eid>
<pitch>67</pitch>
<tpc>15</tpc>
</Note>
</Chord>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
29 changes: 29 additions & 0 deletions src/engraving/tests/voiceswitching_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "engraving/dom/chord.h"
#include "engraving/dom/note.h"
#include "engraving/dom/rest.h"

#include "utils/scorerw.h"

Expand Down Expand Up @@ -99,3 +100,31 @@ TEST_F(Engraving_VoiceSwitchingTests, voiceSwitching)

delete score;
}

TEST_F(Engraving_VoiceSwitchingTests, voicesSwitchingGapRests)
{
Score* score = ScoreRW::readScore(VOICESWITCHING_DATA_DIR + "voiceswitching-2.mscx");
EXPECT_TRUE(score);

Segment* segment = score->tick2segment(Fraction(3, 4), true, SegmentType::ChordRest);
EXPECT_TRUE(segment);

//! [GIVEN] A measure with some notes in voice zero
Chord* chord = toChord(segment->element(0));
EXPECT_TRUE(chord);

//! [WHEN] The last note of the measure is selected and moved to voice one
score->select(chord->upNote());
score->startCmd(TranslatableString("undoableAction", "Change voice"));
score->changeSelectedElementsVoice(1);
score->endCmd();

//! [THEN] Voice 1 should be filled with gap rests from the start of the measure
Segment* firstSeg = score->firstSegment(SegmentType::ChordRest);
EXPECT_TRUE(firstSeg);

EngravingItem* item = firstSeg->element(1);
EXPECT_TRUE(item && item->isRest() && toRest(item)->isGap());

delete score;
}
Loading