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

Fix arpeggio cross stave collisions #19734

Merged
merged 14 commits into from
Nov 14, 2023

Conversation

miiizen
Copy link
Contributor

@miiizen miiizen commented Oct 16, 2023

Resolves: #19668
Resolves: #14359

  • Arpeggios can now span from a voice to any other voice.
  • Accidentals across all staves the arpeggio spans are taken into consideration for proper placement with no collisions.
  • Slurs do not collide with arpeggios except for outside slurs ending on the arpeggio start or end chord.
  • The top and bottom handle can be dragged to change the start/end position of the arpeggio
  • Deleting the top note an arpeggio is attached to moves the arpeggio down to the next available chord
  • Arpeggio handles are shown on drop from palette
    image
  • I signed the CLA
  • The title of the PR describes the problem it addresses
  • Each commit's message describes its purpose and effects, and references the issue it resolves
  • If changes are extensive, there is a sequence of easily reviewable commits
  • The code in the PR follows the coding rules
  • There are no unnecessary changes
  • The code compiles and runs on my machine, preferably after each commit individually
  • I created a unit test or vtest to verify the changes I made (if applicable)

@miiizen miiizen force-pushed the arpeggio-overhaul branch 2 times, most recently from 6873adc to e603857 Compare October 30, 2023 16:25
@oktophonie oktophonie added the vtests This PR produces approved changes to vtest results label Oct 30, 2023
@@ -1771,7 +1771,8 @@ void TRead::read(Arpeggio* a, XmlReader& e, ReadContext& ctx)
} else if (tag == "userLen2") {
a->setUserLen2(e.readDouble() * a->spatium());
} else if (tag == "span") {
a->setSpan(e.readInt());
// Span now refers to number of voices spanned, not staves
a->setSpan((e.readInt() - 1) * VOICES + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this way, the arpeggio will only span the first voice of the bottom staff. Would it make sense to span all voices by default? Or is spanning only the first voice the closest to the old behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arpeggios used to span to the same voice on the bottom stave as the arpeggio was added to on the upper stave. This preserves this when opening old scores, so an arpeggio added to voice 1 will span to voice 1 on the bottom staff, an arpeggio on voice 2 will span to voice 2 etc.

src/engraving/dom/arpeggio.cpp Outdated Show resolved Hide resolved
src/engraving/dom/arpeggio.cpp Outdated Show resolved Hide resolved
src/engraving/dom/arpeggio.h Outdated Show resolved Hide resolved
src/engraving/rendering/dev/arpeggiolayout.cpp Outdated Show resolved Hide resolved
src/engraving/dom/arpeggio.cpp Outdated Show resolved Hide resolved
src/engraving/dom/arpeggio.cpp Outdated Show resolved Hide resolved
src/engraving/dom/arpeggio.cpp Outdated Show resolved Hide resolved
Comment on lines 176 to 177
bool aboveStart = chord->vStaffIdx() <= item->vStaffIdx() && chord->line() < item->chord()->line();
bool belowEnd = chord->vStaffIdx() >= endChord->vStaffIdx() && chord->line() > endChord->line();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you want to use upLine and downLine explicitly, instead of just line which decides based on the stem direction (which seems irrelevant to me here)?

Also, shouldn't the logic be like this:

Suggested change
bool aboveStart = chord->vStaffIdx() <= item->vStaffIdx() && chord->line() < item->chord()->line();
bool belowEnd = chord->vStaffIdx() >= endChord->vStaffIdx() && chord->line() > endChord->line();
bool aboveStart = chord->vStaffIdx() < item->vStaffIdx() ||(chord->vStaffIdx() == item->vStaffIdx() && chord->line() < item->chord()->line());
bool belowEnd = chord->vStaffIdx() > endChord->vStaffIdx() || (chord->vStaffIdx() == endChord->vStaffIdx() && chord->line() > endChord->line());

which might be written more concisely as

Suggested change
bool aboveStart = chord->vStaffIdx() <= item->vStaffIdx() && chord->line() < item->chord()->line();
bool belowEnd = chord->vStaffIdx() >= endChord->vStaffIdx() && chord->line() > endChord->line();
bool aboveStart = std::make_pair(chord->vStaffIdx(), chord->line()) < std::make_pair(item->vStaffIdx(), item->chord()->line());
bool belowEnd = std::make_pair(chord->vStaffIdx(), chord->line()) > std::make_pair(endChord->vStaffIdx(), endChord->line());

Comment on lines 186 to 187
bool aboveStart = item->vStaffIdx() <= spanArp->vStaffIdx() && item->line() < spanArp->chord()->line();
bool belowEnd = item->vStaffIdx() >= endChord->vStaffIdx() && item->line() > endChord->line();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above about upLine/downLine vs line

@miiizen miiizen force-pushed the arpeggio-overhaul branch 4 times, most recently from e8b67cc to 38338ca Compare November 9, 2023 14:40
@miiizen miiizen force-pushed the arpeggio-overhaul branch 2 times, most recently from ebb6dfb to 155527b Compare November 10, 2023 13:13
Chord* chord = toChord(linkedObject);
Score* score = chord->score();
if (score) {
score->undo(new ChangeSpanArpeggio(chord, a));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a itself, shouldn't we use the Arpeggio that is linked to a in the same score as chord?

// insetDistance
//---------------------------------------------------------

double ArpeggioLayout::insetDistance(Arpeggio* item, LayoutContext& ctx, double mag_, Chord* chord, std::vector<Accidental*> accidentals)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const std::vector<Accidental*>&

@@ -96,7 +96,7 @@ void ScoreRenderer::layoutText1(TextBase* item, bool base)
void ScoreRenderer::layoutOnEdit(Arpeggio* item)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this method doesn't do much anymore, can we get rid of it?

@miiizen miiizen force-pushed the arpeggio-overhaul branch 2 times, most recently from 4b16c5e to 2934183 Compare November 10, 2023 16:10
if (downnote->line() > firstLedgerBelow || upnote->line() < firstLedgerAbove) {
gapSize = arpeggioLedgerDistance + ctx.conf().styleS(Sid::ledgerLineLength).val() * item->spatium();
}
} else if (leftNote->line() > firstLedgerBelow || leftNote->line() < firstLedgerAbove) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need a null check?

Suggested change
} else if (leftNote->line() > firstLedgerBelow || leftNote->line() < firstLedgerAbove) {
} else if (leftNote && (leftNote->line() > firstLedgerBelow || leftNote->line() < firstLedgerAbove)) {

@@ -198,7 +202,11 @@ void ChordLayout::layoutPitched(Chord* item, LayoutContext& ctx)

double gapSize = arpeggioNoteDistance;

if (downnote->line() > firstLedgerBelow || upnote->line() < firstLedgerAbove) {
if (leftNote && leftNote->x() == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps RealIsNull(leftNote->x()) is more reliable (from realfn.h)

}
}

void Arpeggio::rebaseStartAnchor(int direction)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to use enum instead of int (rebaseStartAnchor/rebaseEndAnchor)

@@ -40,6 +40,7 @@ class Arpeggio final : public EngravingItem

public:

~Arpeggio();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

override

double chordX = -chordShape.left();
double diff = chordX - arpX;

if (diff != 0.0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use RealIsNull

// Arpeggio doesn't start on this staff so move to last note and extend upwards
curArpShape.translate(PointF(0.0, endChord->downNote()->pagePos().y() - item->pagePos().y()));
curArpShape.addBBox(RectF(curArpShape.bbox().topLeft().x(), curArpShape.bbox().topLeft().y() - 10000,
curArpShape.bbox().width(), 10000));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a named constant instead of this magic number (same for other places where you use it)

}
}

if (_accidentals.size() == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (_accidentals.empty())

// insetDistance
//---------------------------------------------------------

double ArpeggioLayout::insetDistance(Arpeggio* item, LayoutContext& ctx, double mag_, Chord* chord,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item, ctx and chord should be const

}

//---------------------------------------------------------
// insetDistance
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this comment (and other similar comments)

|| type == ArpeggioType::BRACKET;

Accidental* furthestAccidental = nullptr;
for (auto accidental : accidentals) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use const Accidental* instead of auto

@@ -91,6 +91,7 @@ void ChordLayout::layout(Chord* item, LayoutContext& ctx)

void ChordLayout::layoutPitched(Chord* item, LayoutContext& ctx)
{
PaddingTable paddingTable = item->score()->paddingTable();
Copy link
Contributor

@RomanPudashkin RomanPudashkin Nov 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Please declare this closer to the place where it's used
  2. It should be const PaddingTable & paddingTable

if (item->arpeggio()) {
item->arpeggio()->findAndAttachToChords();
item->arpeggio()->mutldata()->maxChordPad = 0.0;
item->arpeggio()->mutldata()->minChordX = 10000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number


const Segment* seg = item->chord()->segment();
Chord* endChord = item->chord();
const PaddingTable paddingTable = item->score()->paddingTable();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget &

return 0.0;
}

if (accidentals.size() == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (accidentals.empty())

|| type == ArpeggioType::BRACKET;

Accidental* furthestAccidental = nullptr;
for (Accidental* accidental : accidentals) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const Accidental*

lll += extraX;
}
// _arpeggio->layout() called in layoutArpeggio2()
if (chordAccidentals.size()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!chordAccidentals.empty())

@RomanPudashkin RomanPudashkin merged commit 9e57b69 into musescore:master Nov 14, 2023
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vtests This PR produces approved changes to vtest results
Projects
None yet
4 participants