Skip to content

Commit

Permalink
Fix GH18940: Prevent local time signature paste crash
Browse files Browse the repository at this point in the history
Backport of musescore#20277
  • Loading branch information
miiizen authored and Jojo-Schmitz committed Dec 6, 2023
1 parent 7a88317 commit c65ae8c
Show file tree
Hide file tree
Showing 6 changed files with 471 additions and 10 deletions.
8 changes: 7 additions & 1 deletion libmscore/duration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,15 @@ Fraction DurationElement::globalTicks() const
// actualTicks
//---------------------------------------------------------

Fraction DurationElement::actualTicksAt(const Fraction& tick) const
{
// Use when tick() is unreliable, for example when pasting
return globalTicks() / staff()->timeStretch(tick);
}

Fraction DurationElement::actualTicks() const
{
return globalTicks() / staff()->timeStretch(tick());
return actualTicksAt(tick());
}

//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions libmscore/duration.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class DurationElement : public Element {
Tuplet* topTuplet() const;
virtual Beam* beam() const { return 0; }

Fraction actualTicksAt(const Fraction& tick) const;
Fraction actualTicks() const;

//Length expressed as a fraction of a whole note
Expand Down
20 changes: 11 additions & 9 deletions libmscore/paste.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "lyrics.h"
#include "hairpin.h"
#include "tie.h"
#include "timesig.h"
#include "tuplet.h"
#include "utils.h"
#include "xml.h"
Expand Down Expand Up @@ -239,7 +240,7 @@ bool Score::pasteStaff(XmlReader& e, Segment* dst, int dstStaff, Fraction scale)
else {
if (tuplet)
cr->readAddTuplet(tuplet);
e.incTick(cr->actualTicks());
e.incTick(cr->actualTicksAt(tick));
if (doScale) {
Fraction d = cr->durationTypeTicks();
cr->setTicks(cr->ticks() * scale);
Expand Down Expand Up @@ -577,7 +578,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
transposeChord(toChord(cr), srcTranspose, tick);
if (toChord(cr)->tremolo() && toChord(cr)->tremolo()->twoNotes())
twoNoteTremoloFactor = 2;
else if (cr->durationTypeTicks() == (cr->actualTicks() * 2)) {
else if (cr->durationTypeTicks() == (cr->actualTicksAt(tick) * 2)) {
// this could be the 2nd note of a two-note tremolo
// check previous CR on same track, if it has a two-note tremolo, then set twoNoteTremoloFactor to 2
Segment* seg = measure->undoGetSegment(SegmentType::ChordRest, tick);
Expand Down Expand Up @@ -606,18 +607,18 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
if (cr->isRepeatMeasure())
partialCopy = toRepeatMeasure(cr)->actualTicks() != measure->ticks();
else if (!isGrace && !cr->tuplet())
partialCopy = cr->durationTypeTicks() != (cr->actualTicks() * twoNoteTremoloFactor);
partialCopy = cr->durationTypeTicks() != (cr->actualTicksAt(tick) * twoNoteTremoloFactor);

// if note is too long to fit in measure, split it up with a tie across the barline
// exclude tuplets from consideration
// we have already disallowed a tuplet from crossing the barline, so there is no problem here
// but due to rounding, it might appear from actualTicks() that the last note is too long by a couple of ticks

if (!isGrace && !cr->tuplet() && (tick + cr->actualTicks() > measureEnd || partialCopy || convertMeasureRest)) {
if (!isGrace && !cr->tuplet() && (tick + cr->actualTicksAt(tick) > measureEnd || partialCopy || convertMeasureRest)) {
if (cr->isChord()) {
// split Chord
Chord* c = toChord(cr);
Fraction rest = c->actualTicks();
Fraction rest = c->actualTicksAt(tick);
bool firstpart = true;
while (rest.isNotZero()) {
measure = tick2measure(tick);
Expand All @@ -627,10 +628,11 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
Fraction mlen = measure->tick() + measure->ticks() - tick;
Fraction len = mlen > rest ? rest : mlen;
std::vector<TDuration> dl = toRhythmicDurationList(len, false, tick - measure->tick(), sigmap()->timesig(tick).nominal(), measure, MAX_DOTS);
Fraction c2Tick(tick + c->tick());
TDuration d = dl[0];
c2->setDurationType(d);
c2->setTicks(d.fraction());
rest -= c2->actualTicks();
rest -= c2->actualTicksAt(c2Tick);
undoAddCR(c2, measure, tick);

std::vector<Note*> nl1 = c->notes();
Expand All @@ -653,7 +655,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
}
c = c2;
firstpart = false;
tick += c->actualTicks();
tick += c->actualTicksAt(c2Tick);
}
}
else if (cr->isRest()) {
Expand All @@ -673,7 +675,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
r2->setTicks(d.isMeasure() ? measure->ticks() : d.fraction());
undoAddCR(r2, measure, tick);
rest -= r2->ticks();
tick += r2->actualTicks();
tick += r2->actualTicksAt(tick);
firstpart = false;
}
}
Expand All @@ -695,7 +697,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t, const Interval& src
r2->setDurationType(d);
undoAddCR(r2, measure, tick);
rest -= d.fraction();
tick += r2->actualTicks();
tick += r2->actualTicksAt(tick);
}
delete r;
}
Expand Down
234 changes: 234 additions & 0 deletions mtest/libmscore/copypaste/copypaste27-ref.mscx
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="3.02">
<Score>
<Division>480</Division>
<Style>
<Spatium>1.74978</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer">Composer / arranger</metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="source"></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>
<unsorted group="brass"/>
</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>
<unsorted group="pitched-percussion"/>
<family>drums</family>
<family>unpitched-metal-percussion</family>
<family>unpitched-wooden-percussion</family>
<family>other-percussion</family>
<unsorted group="unpitched-percussion"/>
</section>
<family>keyboards</family>
<family>harps</family>
<family>organs</family>
<family>synths</family>
<unsorted/>
<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>
</Order>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<bracket type="1" span="2" col="0" visible="1"/>
<barLineSpan>1</barLineSpan>
</Staff>
<Staff id="2">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<defaultClef>F</defaultClef>
</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>
<Channel>
<program value="0"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>3</sigN>
<sigD>2</sigD>
<stretchN>3</stretchN>
<stretchD>2</stretchD>
</TimeSig>
<Rest>
<durationType>measure</durationType>
<duration>3/2</duration>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<TimeSig>
<sigN>3</sigN>
<sigD>8</sigD>
</TimeSig>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>71</pitch>
<tpc>19</tpc>
</Note>
</Chord>
<Chord>
<durationType>eighth</durationType>
<Note>
<pitch>71</pitch>
<tpc>19</tpc>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Rest>
<durationType>measure</durationType>
<duration>3/8</duration>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>71</pitch>
<tpc>19</tpc>
</Note>
</Chord>
<Chord>
<durationType>eighth</durationType>
<Note>
<pitch>71</pitch>
<tpc>19</tpc>
</Note>
</Chord>
</voice>
</Measure>
</Staff>
<Staff id="2">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<TimeSig>
<sigN>3</sigN>
<sigD>8</sigD>
</TimeSig>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
</Note>
</Chord>
<Chord>
<durationType>eighth</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Rest>
<durationType>measure</durationType>
<duration>3/8</duration>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
</Note>
</Chord>
<Chord>
<durationType>eighth</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
</Note>
</Chord>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
Loading

0 comments on commit c65ae8c

Please sign in to comment.