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 <howardc@pku.edu.cn>
This commit is contained in:
Matt McClinch 2019-10-07 07:00:22 -04:00
parent 4708ea20fb
commit 472cb6bfb5
10 changed files with 56 additions and 51 deletions

View file

@ -396,7 +396,7 @@ void Beam::layout1()
Measure* m = c1->measure(); Measure* m = c1->measure();
if (c1->stemDirection() != Direction::AUTO) if (c1->stemDirection() != Direction::AUTO)
_up = c1->stemDirection() == Direction::UP; _up = c1->stemDirection() == Direction::UP;
else if (m->hasVoices(c1->staffIdx())) else if (m->hasVoices(c1->staffIdx(), tick(), ticks()))
_up = !(c1->voice() % 2); _up = !(c1->voice() % 2);
else if (!twoBeamedNotes()) { else if (!twoBeamedNotes()) {
// highest or lowest note determines stem direction // highest or lowest note determines stem direction
@ -483,7 +483,7 @@ void Beam::layoutGraceNotes()
ChordRest* cr = _elements[0]; ChordRest* cr = _elements[0];
Measure* m = cr->measure(); Measure* m = cr->measure();
if (m->hasVoices(cr->staffIdx())) if (m->hasVoices(cr->staffIdx(), tick(), ticks()))
_up = !(cr->voice() % 2); _up = !(cr->voice() % 2);
else else
_up = true; _up = true;
@ -2493,6 +2493,19 @@ Fraction Beam::rtick() const
return _elements.empty() ? Fraction(0, 1) : _elements.front()->segment()->rtick(); 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 // iconType
//--------------------------------------------------------- //---------------------------------------------------------

View file

@ -92,6 +92,7 @@ class Beam final : public Element {
Fraction tick() const override; Fraction tick() const override;
Fraction rtick() const override; Fraction rtick() const override;
Fraction ticks() const;
void write(XmlWriter& xml) const override; void write(XmlWriter& xml) const override;
void read(XmlReader&) override; void read(XmlReader&) override;

View file

@ -868,7 +868,7 @@ void Chord::computeUp()
// if no stems or stem beside staves // if no stems or stem beside staves
if (tab->stemless() || !tab->stemThrough()) { if (tab->stemless() || !tab->stemThrough()) {
// if measure has voices, set stem direction according to voice // if measure has voices, set stem direction according to voice
if (measure()->hasVoices(staffIdx())) if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
_up = !(track() % 2); _up = !(track() % 2);
else // if only voice 1, else // if only voice 1,
// unconditionally set to down if not stems or according to TAB stem direction otherwise // 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 // stem direction for grace notes
// //
if (measure()->hasVoices(staffIdx())) if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
_up = !(track() % 2); _up = !(track() % 2);
else else
_up = true; _up = true;
} }
else if (staffMove()) else if (staffMove())
_up = staffMove() > 0; _up = staffMove() > 0;
else if (measure()->hasVoices(staffIdx())) else if (measure()->hasVoices(staffIdx(), tick(), actualTicks()))
_up = !(track() % 2); _up = !(track() % 2);
else { else {
int dnMaxLine = staff()->middleLine(tick()); int dnMaxLine = staff()->middleLine(tick());
@ -3401,7 +3401,7 @@ void Chord::layoutArticulations()
Articulation* prevArticulation = nullptr; Articulation* prevArticulation = nullptr;
for (Articulation* a : _articulations) { for (Articulation* a : _articulations) {
if (a->anchor() == ArticulationAnchor::CHORD) { 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 a->setUp(up()); // if there are voices place articulation at stem
else if (a->symId() >= SymId::articMarcatoAbove && a->symId() <= SymId::articMarcatoTenutoBelow) else if (a->symId() >= SymId::articMarcatoAbove && a->symId() <= SymId::articMarcatoTenutoBelow)
a->setUp(true); // Gould, p. 117: strong accents above staff a->setUp(true); // Gould, p. 117: strong accents above staff

View file

@ -79,7 +79,7 @@ Placement Fingering::calculatePlacement() const
Staff* staff = chord->staff(); Staff* staff = chord->staff();
Part* part = staff->part(); Part* part = staff->part();
int nstaves = part->nstaves(); 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); bool below = voices ? !chord->up() : (nstaves > 1) && (staff->rstaff() == nstaves - 1);
return below ? Placement::BELOW : Placement::ABOVE; return below ? Placement::BELOW : Placement::ABOVE;
} }
@ -105,7 +105,7 @@ void Fingering::layout()
if (autoplace() && note()) { if (autoplace() && note()) {
Note* n = note(); Note* n = note();
Chord* chord = n->chord(); 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; bool tight = voices && chord->notes().size() == 1 && !chord->beam() && tid() != Tid::STRING_NUMBER;
qreal headWidth = n->bboxRightPos(); qreal headWidth = n->bboxRightPos();

View file

@ -128,7 +128,7 @@ static bool vUp(Chord* chord)
up = false; up = false;
else if (chord->track() > chord->beam()->track()) else if (chord->track() > chord->beam()->track())
up = true; up = true;
else if (chord->measure()->hasVoices(chord->staffIdx())) else if (chord->measure()->hasVoices(chord->staffIdx(), chord->tick(), chord->actualTicks()))
up = !(chord->track() % 2); up = !(chord->track() % 2);
else else
up = !chord->staff()->isTop(); up = !chord->staff()->isTop();

View file

@ -2681,20 +2681,35 @@ void Measure::exchangeVoice(int strack, int dtrack, int staffIdx)
//--------------------------------------------------------- //---------------------------------------------------------
void Measure::checkMultiVoices(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 strack = staffIdx * VOICES + 1;
int etrack = staffIdx * VOICES + VOICES; 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)) { for (Segment* s = first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
if (s->tick() >= etick)
break;
for (int track = strack; track < etrack; ++track) { for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track); ChordRest* cr = toChordRest(s->element(track));
if (e) { if (cr) {
bool v; if (cr->tick() + cr->actualTicks() <= stick)
if (e->isChord()) { continue;
v = false; bool v = false;
if (cr->isChord()) {
// consider chord visible if any note is visible // consider chord visible if any note is visible
Chord* c = toChord(e); Chord* c = toChord(cr);
for (Note* n : c->notes()) { for (Note* n : c->notes()) {
if (n->visible()) { if (n->visible()) {
v = true; v = true;
@ -2702,15 +2717,14 @@ void Measure::checkMultiVoices(int staffIdx)
} }
} }
} }
else else if (cr->isRest())
v = e->visible(); v = cr->visible() && !toRest(cr)->isGap();
if (v) { if (v)
_mstaves[staffIdx]->setHasVoices(true); return true;
return;
}
} }
} }
} }
return false;
} }
//--------------------------------------------------------- //---------------------------------------------------------
@ -2878,27 +2892,6 @@ bool Measure::isOnlyDeletedRests(int track) const
return true; 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 // stretchedLen
//--------------------------------------------------------- //---------------------------------------------------------

View file

@ -117,6 +117,7 @@ class Measure final : public MeasureBase {
void spatiumChanged(qreal oldValue, qreal newValue) override; void spatiumChanged(qreal oldValue, qreal newValue) override;
System* system() const { return (System*)parent(); } System* system() const { return (System*)parent(); }
bool hasVoices(int staffIdx, Fraction stick, Fraction len) const;
bool hasVoices(int staffIdx) const; bool hasVoices(int staffIdx) const;
void setHasVoices(int staffIdx, bool v); void setHasVoices(int staffIdx, bool v);
@ -227,7 +228,6 @@ class Measure final : public MeasureBase {
bool empty() const; bool empty() const;
bool isOnlyRests(int track) const; bool isOnlyRests(int track) const;
bool isOnlyDeletedRests(int track) const; bool isOnlyDeletedRests(int track) const;
bool isOnlyDeletedRests(int track, const Fraction& stick, const Fraction& etick) const;
int playbackCount() const { return _playbackCount; } int playbackCount() const { return _playbackCount; }
void setPlaybackCount(int val) { _playbackCount = val; } void setPlaybackCount(int val) { _playbackCount = val; }

View file

@ -480,7 +480,7 @@ int Rest::getDotline(TDuration::DurationType durationType)
int Rest::computeLineOffset(int lines) int Rest::computeLineOffset(int lines)
{ {
Segment* s = segment(); Segment* s = segment();
bool offsetVoices = s && measure() && measure()->hasVoices(staffIdx()); bool offsetVoices = s && measure() && measure()->hasVoices(staffIdx(), tick(), actualTicks());
if (offsetVoices && voice() == 0) { if (offsetVoices && voice() == 0) {
// do not offset voice 1 rest if there exists a matching invisible rest in voice 2; // do not offset voice 1 rest if there exists a matching invisible rest in voice 2;
Element* e = s->element(track() + 1); Element* e = s->element(track() + 1);
@ -490,8 +490,6 @@ int Rest::computeLineOffset(int lines)
offsetVoices = false; offsetVoices = false;
} }
} }
else if (measure()->isOnlyDeletedRests(track() + 1, tick(), tick() + globalTicks()))
offsetVoices = false;
} }
#if 0 #if 0
if (offsetVoices && staff()->mergeMatchingRests()) { if (offsetVoices && staff()->mergeMatchingRests()) {

View file

@ -1050,7 +1050,7 @@ SpannerSegment* Slur::layoutSystem(System* system)
// but grace notes are exceptions // but grace notes are exceptions
_up = true; _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 // in polyphonic passage, slurs go on the stem side
_up = startCR()->up(); _up = startCR()->up();
} }
@ -1172,7 +1172,7 @@ void Slur::layout()
// but grace notes are exceptions // but grace notes are exceptions
_up = true; _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 // in polyphonic passage, slurs go on the stem side
_up = startCR()->up(); _up = startCR()->up();
} }

View file

@ -544,7 +544,7 @@ void Tie::calculateDirection()
if (_slurDirection == Direction::AUTO) { if (_slurDirection == Direction::AUTO) {
std::vector<Note*> notes = c1->notes(); std::vector<Note*> notes = c1->notes();
size_t n = notes.size(); 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 // in polyphonic passage, ties go on the stem side
_up = c1->up(); _up = c1->up();
} }
@ -619,7 +619,7 @@ TieSegment* Tie::layoutFor(System* system)
} }
Chord* c1 = startNote()->chord(); Chord* c1 = startNote()->chord();
if (_slurDirection == Direction::AUTO) { 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 // in polyphonic passage, ties go on the stem side
_up = c1->up(); _up = c1->up();
} }