Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent local time signature paste crash #20277

Merged
merged 1 commit into from
Dec 1, 2023
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
8 changes: 7 additions & 1 deletion src/engraving/dom/durationelement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,15 @@ float DurationElement::timeStretchFactor() 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 src/engraving/dom/durationelement.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class DurationElement : public EngravingItem
Tuplet* topTuplet() const;
virtual Beam* beam() const { return nullptr; }

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

// Length expressed as a fraction of a whole note
Expand Down
18 changes: 10 additions & 8 deletions src/engraving/dom/paste.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "sig.h"
#include "staff.h"
#include "tie.h"
#include "timesig.h"
#include "tremolo.h"
#include "tuplet.h"
#include "undo.h"
Expand Down Expand Up @@ -124,7 +125,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
transposeChord(toChord(cr), 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 @@ -167,19 +168,19 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
if (cr->isMeasureRepeat()) {
partialCopy = toMeasureRepeat(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 @@ -192,9 +193,10 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
std::vector<TDuration> dl = toRhythmicDurationList(len, false, tick - measure->tick(), sigmap()->timesig(
tick).nominal(), measure, MAX_DOTS);
TDuration d = dl[0];
Fraction c2Tick(tick + c->tick());
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 @@ -219,7 +221,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
}
c = c2;
firstpart = false;
tick += c->actualTicks();
tick += c->actualTicksAt(c2Tick);
}
} else if (cr->isRest()) {
// split Rest
Expand All @@ -239,7 +241,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
r2->setTicks(d.isMeasure() ? measure->ticks() : d.fraction());
undoAddCR(r2, measure, tick);
rest -= r2->ticks();
tick += r2->actualTicks();
tick += r2->actualTicksAt(tick);
firstpart = false;
}
} else if (cr->isMeasureRepeat()) {
Expand All @@ -260,7 +262,7 @@ void Score::pasteChordRest(ChordRest* cr, const Fraction& t)
r2->setDurationType(d);
undoAddCR(r2, measure, tick);
rest -= d.fraction();
tick += r2->actualTicks();
tick += r2->actualTicksAt(tick);
}
delete r;
}
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read410/read410.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ bool Read410::pasteStaff(XmlReader& e, Segment* dst, staff_idx_t dstStaff, Fract
if (tuplet) {
cr->readAddTuplet(tuplet);
}
ctx.incTick(cr->actualTicks());
ctx.incTick(cr->actualTicksAt(tick));
if (doScale) {
Fraction d = cr->durationTypeTicks();
cr->setTicks(cr->ticks() * scale);
Expand Down
234 changes: 234 additions & 0 deletions src/engraving/tests/copypaste_data/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="4.20">
<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