From 472cb6bfb5e1bedd95e20d701d2fd850d1e02f76 Mon Sep 17 00:00:00 2001 From: Matt McClinch Date: Mon, 7 Oct 2019 07:00:22 -0400 Subject: [PATCH] fix #294085: all elements set to normal position if all rests in voices other than voice 1 are deleted This factors out the inner workings of Measure::checkMultiVoices() into a variant of Measure::hasVoices() that takes a start tick and a length in addition to a staff index. Co-authored-by: Howard-C --- libmscore/beam.cpp | 17 ++++++++++-- libmscore/beam.h | 1 + libmscore/chord.cpp | 8 +++--- libmscore/fingering.cpp | 4 +-- libmscore/layout.cpp | 2 +- libmscore/measure.cpp | 61 ++++++++++++++++++----------------------- libmscore/measure.h | 2 +- libmscore/rest.cpp | 4 +-- libmscore/slur.cpp | 4 +-- libmscore/tie.cpp | 4 +-- 10 files changed, 56 insertions(+), 51 deletions(-) diff --git a/libmscore/beam.cpp b/libmscore/beam.cpp index d1e6144efa..59b0492238 100644 --- a/libmscore/beam.cpp +++ b/libmscore/beam.cpp @@ -396,7 +396,7 @@ void Beam::layout1() Measure* m = c1->measure(); if (c1->stemDirection() != Direction::AUTO) _up = c1->stemDirection() == Direction::UP; - else if (m->hasVoices(c1->staffIdx())) + else if (m->hasVoices(c1->staffIdx(), tick(), ticks())) _up = !(c1->voice() % 2); else if (!twoBeamedNotes()) { // highest or lowest note determines stem direction @@ -483,7 +483,7 @@ void Beam::layoutGraceNotes() ChordRest* cr = _elements[0]; Measure* m = cr->measure(); - if (m->hasVoices(cr->staffIdx())) + if (m->hasVoices(cr->staffIdx(), tick(), ticks())) _up = !(cr->voice() % 2); else _up = true; @@ -2493,6 +2493,19 @@ Fraction Beam::rtick() const return _elements.empty() ? Fraction(0, 1) : _elements.front()->segment()->rtick(); } +//--------------------------------------------------------- +// ticks +// calculate the ticks of all chords and rests connected by the beam +//--------------------------------------------------------- + +Fraction Beam::ticks() const + { + Fraction ticks = Fraction(0, 1); + for (ChordRest* cr : _elements) + ticks += cr->actualTicks(); + return ticks; + } + //--------------------------------------------------------- // iconType //--------------------------------------------------------- diff --git a/libmscore/beam.h b/libmscore/beam.h index 813dd21235..50494a3599 100644 --- a/libmscore/beam.h +++ b/libmscore/beam.h @@ -92,6 +92,7 @@ class Beam final : public Element { Fraction tick() const override; Fraction rtick() const override; + Fraction ticks() const; void write(XmlWriter& xml) const override; void read(XmlReader&) override; diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index a11cc1076a..981cd34a83 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -868,7 +868,7 @@ void Chord::computeUp() // if no stems or stem beside staves if (tab->stemless() || !tab->stemThrough()) { // if measure has voices, set stem direction according to voice - if (measure()->hasVoices(staffIdx())) + if (measure()->hasVoices(staffIdx(), tick(), actualTicks())) _up = !(track() % 2); else // if only voice 1, // unconditionally set to down if not stems or according to TAB stem direction otherwise @@ -889,14 +889,14 @@ void Chord::computeUp() // // stem direction for grace notes // - if (measure()->hasVoices(staffIdx())) + if (measure()->hasVoices(staffIdx(), tick(), actualTicks())) _up = !(track() % 2); else _up = true; } else if (staffMove()) _up = staffMove() > 0; - else if (measure()->hasVoices(staffIdx())) + else if (measure()->hasVoices(staffIdx(), tick(), actualTicks())) _up = !(track() % 2); else { int dnMaxLine = staff()->middleLine(tick()); @@ -3401,7 +3401,7 @@ void Chord::layoutArticulations() Articulation* prevArticulation = nullptr; for (Articulation* a : _articulations) { if (a->anchor() == ArticulationAnchor::CHORD) { - if (measure()->hasVoices(a->staffIdx())) + if (measure()->hasVoices(a->staffIdx(), tick(), actualTicks())) a->setUp(up()); // if there are voices place articulation at stem else if (a->symId() >= SymId::articMarcatoAbove && a->symId() <= SymId::articMarcatoTenutoBelow) a->setUp(true); // Gould, p. 117: strong accents above staff diff --git a/libmscore/fingering.cpp b/libmscore/fingering.cpp index db809011df..d30c8d001f 100644 --- a/libmscore/fingering.cpp +++ b/libmscore/fingering.cpp @@ -79,7 +79,7 @@ Placement Fingering::calculatePlacement() const Staff* staff = chord->staff(); Part* part = staff->part(); int nstaves = part->nstaves(); - bool voices = chord->measure()->hasVoices(staff->idx()); + bool voices = chord->measure()->hasVoices(staff->idx(), chord->tick(), chord->actualTicks()); bool below = voices ? !chord->up() : (nstaves > 1) && (staff->rstaff() == nstaves - 1); return below ? Placement::BELOW : Placement::ABOVE; } @@ -105,7 +105,7 @@ void Fingering::layout() if (autoplace() && note()) { Note* n = note(); Chord* chord = n->chord(); - bool voices = chord->measure()->hasVoices(chord->staffIdx()); + bool voices = chord->measure()->hasVoices(chord->staffIdx(), chord->tick(), chord->actualTicks()); bool tight = voices && chord->notes().size() == 1 && !chord->beam() && tid() != Tid::STRING_NUMBER; qreal headWidth = n->bboxRightPos(); diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 30267d99ef..c40f72a66e 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -128,7 +128,7 @@ static bool vUp(Chord* chord) up = false; else if (chord->track() > chord->beam()->track()) up = true; - else if (chord->measure()->hasVoices(chord->staffIdx())) + else if (chord->measure()->hasVoices(chord->staffIdx(), chord->tick(), chord->actualTicks())) up = !(chord->track() % 2); else up = !chord->staff()->isTop(); diff --git a/libmscore/measure.cpp b/libmscore/measure.cpp index e802e7c339..b4ccdb4232 100644 --- a/libmscore/measure.cpp +++ b/libmscore/measure.cpp @@ -2681,20 +2681,35 @@ void Measure::exchangeVoice(int strack, int dtrack, int staffIdx) //--------------------------------------------------------- void Measure::checkMultiVoices(int staffIdx) + { + if (hasVoices(staffIdx, tick(), ticks())) + _mstaves[staffIdx]->setHasVoices(true); + else + _mstaves[staffIdx]->setHasVoices(false); + } + +//--------------------------------------------------------- +// hasVoices +//--------------------------------------------------------- + +bool Measure::hasVoices(int staffIdx, Fraction stick, Fraction len) const { int strack = staffIdx * VOICES + 1; int etrack = staffIdx * VOICES + VOICES; - _mstaves[staffIdx]->setHasVoices(false); + Fraction etick = stick + len; for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) { + if (s->tick() >= etick) + break; for (int track = strack; track < etrack; ++track) { - Element* e = s->element(track); - if (e) { - bool v; - if (e->isChord()) { - v = false; + ChordRest* cr = toChordRest(s->element(track)); + if (cr) { + if (cr->tick() + cr->actualTicks() <= stick) + continue; + bool v = false; + if (cr->isChord()) { // consider chord visible if any note is visible - Chord* c = toChord(e); + Chord* c = toChord(cr); for (Note* n : c->notes()) { if (n->visible()) { v = true; @@ -2702,15 +2717,14 @@ void Measure::checkMultiVoices(int staffIdx) } } } - else - v = e->visible(); - if (v) { - _mstaves[staffIdx]->setHasVoices(true); - return; - } + else if (cr->isRest()) + v = cr->visible() && !toRest(cr)->isGap(); + if (v) + return true; } } } + return false; } //--------------------------------------------------------- @@ -2878,27 +2892,6 @@ bool Measure::isOnlyDeletedRests(int track) const return true; } -//--------------------------------------------------------- -// isOnlyDeletedRests -//--------------------------------------------------------- - -bool Measure::isOnlyDeletedRests(int track, const Fraction& stick, const Fraction& etick) const - { - static const SegmentType st { SegmentType::ChordRest }; - for (const Segment* s = first(st); s; s = s->next(st)) { - if (s->segmentType() != st || !s->element(track)) - continue; - ChordRest* cr = toChordRest(s->element(track)); - if (cr->tick() + cr->globalTicks() <= stick) - continue; - if (cr->tick() >= etick) - return true; - if (!cr->isRest() || !toRest(cr)->isGap()) - return false; - } - return true; - } - //--------------------------------------------------------- // stretchedLen //--------------------------------------------------------- diff --git a/libmscore/measure.h b/libmscore/measure.h index 1793f25c79..4891cc2c99 100644 --- a/libmscore/measure.h +++ b/libmscore/measure.h @@ -117,6 +117,7 @@ class Measure final : public MeasureBase { void spatiumChanged(qreal oldValue, qreal newValue) override; System* system() const { return (System*)parent(); } + bool hasVoices(int staffIdx, Fraction stick, Fraction len) const; bool hasVoices(int staffIdx) const; void setHasVoices(int staffIdx, bool v); @@ -227,7 +228,6 @@ class Measure final : public MeasureBase { bool empty() const; bool isOnlyRests(int track) const; bool isOnlyDeletedRests(int track) const; - bool isOnlyDeletedRests(int track, const Fraction& stick, const Fraction& etick) const; int playbackCount() const { return _playbackCount; } void setPlaybackCount(int val) { _playbackCount = val; } diff --git a/libmscore/rest.cpp b/libmscore/rest.cpp index 80aba4401d..3ac07de4f8 100644 --- a/libmscore/rest.cpp +++ b/libmscore/rest.cpp @@ -480,7 +480,7 @@ int Rest::getDotline(TDuration::DurationType durationType) int Rest::computeLineOffset(int lines) { Segment* s = segment(); - bool offsetVoices = s && measure() && measure()->hasVoices(staffIdx()); + bool offsetVoices = s && measure() && measure()->hasVoices(staffIdx(), tick(), actualTicks()); if (offsetVoices && voice() == 0) { // do not offset voice 1 rest if there exists a matching invisible rest in voice 2; Element* e = s->element(track() + 1); @@ -490,8 +490,6 @@ int Rest::computeLineOffset(int lines) offsetVoices = false; } } - else if (measure()->isOnlyDeletedRests(track() + 1, tick(), tick() + globalTicks())) - offsetVoices = false; } #if 0 if (offsetVoices && staff()->mergeMatchingRests()) { diff --git a/libmscore/slur.cpp b/libmscore/slur.cpp index 1e1037ea41..46459ff86c 100644 --- a/libmscore/slur.cpp +++ b/libmscore/slur.cpp @@ -1050,7 +1050,7 @@ SpannerSegment* Slur::layoutSystem(System* system) // but grace notes are exceptions _up = true; } - else if (m1->hasVoices(startCR()->staffIdx()) && c1 && !c1->isGrace()) { + else if (m1->hasVoices(startCR()->staffIdx(), tick(), ticks()) && c1 && !c1->isGrace()) { // in polyphonic passage, slurs go on the stem side _up = startCR()->up(); } @@ -1172,7 +1172,7 @@ void Slur::layout() // but grace notes are exceptions _up = true; } - else if (m1->hasVoices(startCR()->staffIdx()) && c1 && c1->noteType() == NoteType::NORMAL) { + else if (m1->hasVoices(startCR()->staffIdx(), tick(), ticks()) && c1 && c1->noteType() == NoteType::NORMAL) { // in polyphonic passage, slurs go on the stem side _up = startCR()->up(); } diff --git a/libmscore/tie.cpp b/libmscore/tie.cpp index b4282a5bbd..addebce4d1 100644 --- a/libmscore/tie.cpp +++ b/libmscore/tie.cpp @@ -544,7 +544,7 @@ void Tie::calculateDirection() if (_slurDirection == Direction::AUTO) { std::vector notes = c1->notes(); size_t n = notes.size(); - if (m1->hasVoices(c1->staffIdx()) || m2->hasVoices(c2->staffIdx())) { + if (m1->hasVoices(c1->staffIdx(), c1->tick(), c1->actualTicks()) || m2->hasVoices(c2->staffIdx(), c2->tick(), c2->actualTicks())) { // in polyphonic passage, ties go on the stem side _up = c1->up(); } @@ -619,7 +619,7 @@ TieSegment* Tie::layoutFor(System* system) } Chord* c1 = startNote()->chord(); if (_slurDirection == Direction::AUTO) { - if (c1->measure()->hasVoices(c1->staffIdx())) { + if (c1->measure()->hasVoices(c1->staffIdx(), c1->tick(), c1->actualTicks())) { // in polyphonic passage, ties go on the stem side _up = c1->up(); }