diff --git a/importexport/musicxml/exportxml.cpp b/importexport/musicxml/exportxml.cpp index cb7e2182df807..e0623bdc099e6 100644 --- a/importexport/musicxml/exportxml.cpp +++ b/importexport/musicxml/exportxml.cpp @@ -2824,6 +2824,26 @@ void ExportMusicXml::chordAttributes(Chord* chord, Notations& notations, Technic } } +//--------------------------------------------------------- +// findArpeggio +//--------------------------------------------------------- + +static Arpeggio* findArpeggio(Note* note) + { + if (note->chord()->arpeggio()) return note->chord()->arpeggio(); + + // Check if there is an arpeggio in any voice that intersects the note on the y-axis + for (int i = staff2track(note->staffIdx()); i < staff2track(note->staffIdx() + 1); ++i) { + Element* elem = note->chord()->segment()->elist()[i]; + if (elem && elem->isChord() + && toChord(elem)->arpeggio() + && note->pageBoundingRect().top() + note->headHeight() >= toChord(elem)->arpeggio()->pageBoundingRect().top() + && note->pageBoundingRect().top() + note->headHeight() <= toChord(elem)->arpeggio()->pageBoundingRect().bottom()) + return toChord(elem)->arpeggio(); + } + return 0; + } + //--------------------------------------------------------- // arpeggiate //--------------------------------------------------------- @@ -3464,8 +3484,8 @@ void ExportMusicXml::chord(Chord* chord, int staff, const std::vector* } technical.etag(_xml); - if (chord->arpeggio()) { - arpeggiate(chord->arpeggio(), note == nl.front(), note == nl.back(), _xml, notations); + if (Arpeggio* arp = findArpeggio(note)) { + arpeggiate(arp, note == nl.front(), note == nl.back(), _xml, notations); } for (Spanner* spanner : note->spannerFor()) if (spanner->type() == ElementType::GLISSANDO) { diff --git a/importexport/musicxml/importmxmlpass2.cpp b/importexport/musicxml/importmxmlpass2.cpp index f7351db941840..dd674dc1a5da8 100644 --- a/importexport/musicxml/importmxmlpass2.cpp +++ b/importexport/musicxml/importmxmlpass2.cpp @@ -1627,6 +1627,8 @@ void MusicXMLParserPass2::scorePartwise() auto lm = _score->lastMeasure(); if (lm && lm->endBarLineType() == BarLineType::NORMAL) lm->setEndBarLineType(BarLineType::NORMAL, 0); + + _score->connectArpeggios(); } //--------------------------------------------------------- diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 308f4cfa28a47..6db0667ab90f9 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -11,6 +11,7 @@ //============================================================================= #include "accidental.h" +#include "arpeggio.h" #include "barline.h" #include "beam.h" #include "box.h" @@ -1525,6 +1526,56 @@ void Score::connectTies(bool silent) } } +//--------------------------------------------------------- +// connectArpeggios +// Fake cross-voice arpeggios by hiding all but the first +// and extending the first to cover the others. +// Retains the other properties of the first arpeggio. +//--------------------------------------------------------- + +void Score::connectArpeggios() + { + for (auto segment = firstSegment(SegmentType::ChordRest); segment; segment = segment->next1(SegmentType::ChordRest)) { + for (int staff = 0; staff < nstaves(); ++staff) { + qreal minTop = 10000; + qreal maxBottom = -10000; + int firstArpeggio = -1; + bool multipleArpeggios = false; + for (int i = staff2track(staff); i < staff2track(staff + 1); ++i) { + if (segment->elist()[i] && segment->elist()[i]->isChord()) { + Chord* chord = toChord(segment->elist()[i]); + if (chord->arpeggio() && chord->arpeggio()->visible()) { + if (chord->pagePos() == QPointF(0, 0)) doLayout(); + qreal localTop = chord->arpeggio()->pageBoundingRect().top(); + qreal localBottom = chord->arpeggio()->pageBoundingRect().bottom(); + minTop = qMin(localTop, minTop); + maxBottom = qMax(localBottom, maxBottom); + if (firstArpeggio == -1) + // Leave arpeggio, adjust height after collecting + firstArpeggio = i; + else { + // Hide arpeggio; firstArpeggio will be extended to cover it. + chord->arpeggio()->setVisible(false); + multipleArpeggios = true; + } + } + } + } + if (firstArpeggio != -1 && multipleArpeggios) { + // Stretch first arpeggio to cover deleted + Chord* firstArpeggioChord = toChord(segment->elist()[firstArpeggio]); + Arpeggio* arpeggio = firstArpeggioChord->arpeggio(); + qreal topDiff = minTop - arpeggio->pageBoundingRect().top(); + qreal bottomDiff = maxBottom - arpeggio->pageBoundingRect().bottom(); + arpeggio->setUserLen1(topDiff); + arpeggio->setUserLen2(bottomDiff); + arpeggio->setPropertyFlags(Pid::ARP_USER_LEN1, PropertyFlags::UNSTYLED); + arpeggio->setPropertyFlags(Pid::ARP_USER_LEN2, PropertyFlags::UNSTYLED); + } + } + } + } + //--------------------------------------------------------- // checkDivider //--------------------------------------------------------- diff --git a/libmscore/score.h b/libmscore/score.h index e410332a8b840..df88342f9cf80 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -1035,6 +1035,7 @@ class Score : public QObject, public ScoreElement { Segment* lastSegmentMM() const; void connectTies(bool silent=false); + void connectArpeggios(); qreal point(const Spatium sp) const { return sp.val() * spatium(); } diff --git a/mtest/musicxml/io/testConnectedArpeggios.pdf b/mtest/musicxml/io/testConnectedArpeggios.pdf new file mode 100644 index 0000000000000..9b8bad3484272 Binary files /dev/null and b/mtest/musicxml/io/testConnectedArpeggios.pdf differ diff --git a/mtest/musicxml/io/testConnectedArpeggios.xml b/mtest/musicxml/io/testConnectedArpeggios.xml new file mode 100644 index 0000000000000..83b866c53cc6e --- /dev/null +++ b/mtest/musicxml/io/testConnectedArpeggios.xml @@ -0,0 +1,645 @@ + + + + + Connected Arpeggios + + + Henry Ives + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + 7 + 40 + + + 1697.14 + 1200 + + 85.7143 + 85.7143 + 85.7143 + 85.7143 + + + 85.7143 + 85.7143 + 85.7143 + 85.7143 + + + + + + + title + Connected Arpeggios + + + subtitle + MuseScore Testcase + + + composer + Henry Ives + + + + brace + + + Piano + Pno. + + Piano + + + + 1 + 1 + 78.7402 + 0 + + + + + + + + + 50.00 + 0.00 + + 170.00 + + + + 1 + + 0 + + + + G + 2 + + + + + C + 5 + + 1 + 1 + quarter + up + + + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + E + 5 + + 1 + 1 + quarter + up + + + + G + 5 + + 1 + 1 + quarter + up + + + 4 + + + + F + 4 + + 4 + 2 + whole + + + + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + D + 5 + + 1 + 1 + quarter + up + + + + + G + 5 + + 1 + 1 + quarter + up + + + + F + 5 + + 1 + 1 + quarter + up + + + + B + 4 + + 1 + 1 + quarter + up + + + + + D + 5 + + 1 + 1 + quarter + up + + + 4 + + + + G + 4 + + 4 + 2 + whole + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + A + 4 + + 1 + 1 + quarter + up + + + + + C + 5 + + 1 + 1 + quarter + up + + + + D + 5 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + A + 5 + + 1 + 1 + quarter + up + + + 4 + + + + A + 4 + + 4 + 2 + whole + + + + + + B + 4 + + 1 + 1 + quarter + up + + + + A + 5 + + 1 + 1 + quarter + up + + + + D + 5 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + E + 5 + + 1 + 1 + quarter + up + + + 4 + + + + C + 5 + + 4 + 2 + whole + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + + B + 5 + + 1 + 1 + quarter + up + + + + + + + 1 + 1 + quarter + + + + E + 5 + + 1 + 1 + quarter + up + + + + 1 + 1 + quarter + + + 4 + + + + E + 4 + + 4 + 2 + whole + + + + + + D + 5 + + 1 + 1 + quarter + up + + + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + D + 5 + + 1 + 1 + quarter + up + + + + A + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + 4 + + + + F + 4 + + 4 + 2 + whole + + + + + + + + + F + 5 + + 1 + 1 + quarter + up + + + + + + + B + 4 + + 1 + 1 + quarter + up + + + + A + 4 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + E + 5 + + 1 + 1 + quarter + up + + + + + G + 5 + + 1 + 1 + quarter + up + + + 4 + + + + G + 4 + + 4 + 2 + whole + + + + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testConnectedArpeggios_ref.mscx b/mtest/musicxml/io/testConnectedArpeggios_ref.mscx new file mode 100644 index 0000000000000..58cedb91e4a2f --- /dev/null +++ b/mtest/musicxml/io/testConnectedArpeggios_ref.mscx @@ -0,0 +1,535 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + Henry Ives + + + + + + + + + Connected Arpeggios + + + + stdNormal + + 3 + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + F + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + + + + + + 12.5 + + + + Connected Arpeggios + + + + + MuseScore Testcase + + + + right,top + + Henry Ives + + + + + + G + G + + + 4 + 4 + + + quarter + up + + 72 + 14 + + + 76 + 18 + + + 0 + 2.10812 + + + + quarter + up + + 72 + 14 + + + + quarter + up + + 72 + 14 + + + 76 + 18 + + + + quarter + up + + 79 + 15 + + + + + + whole + + 65 + 13 + + + 0 + 0 + + + + + + + + quarter + up + + 72 + 14 + + + + quarter + up + + 72 + 14 + + + 74 + 16 + + + 79 + 15 + + + + quarter + up + + 77 + 13 + + + + quarter + up + + 71 + 19 + + + 74 + 16 + + + + + + whole + + 67 + 15 + + + + + + + + quarter + up + + 72 + 14 + + + + quarter + up + + 69 + 17 + + + 72 + 14 + + + + quarter + up + + 74 + 16 + + + 77 + 13 + + + + quarter + up + + 72 + 14 + + + 81 + 17 + + + + + + whole + + 69 + 17 + + + + + + + + quarter + up + + 71 + 19 + + + + quarter + up + + 81 + 17 + + + + quarter + up + + 74 + 16 + + + 77 + 13 + + + + quarter + up + + 76 + 18 + + + + + + whole + + 72 + 14 + + + + + + + + quarter + up + + 76 + 18 + + + 83 + 19 + + + 0 + + + + quarter + + + quarter + up + + 76 + 18 + + + + quarter + + + + + whole + + 64 + 18 + + + + + + + + quarter + up + + 74 + 16 + + + 76 + 18 + + + 0 + 2.10812 + + + + quarter + up + + 74 + 16 + + + + quarter + up + + 81 + 17 + + + + quarter + up + + 72 + 14 + + + + + + whole + + 65 + 13 + + + 0 + 0 + + + + + + + + quarter + up + + 77 + 13 + + + 0 + 2.98812 + + + + quarter + up + + 71 + 19 + + + + quarter + up + + 69 + 17 + + + 77 + 13 + + + + quarter + up + + 76 + 18 + + + 79 + 15 + + + + end + + + + + whole + + 67 + 15 + + + 0 + 0 + + + + + + + diff --git a/mtest/musicxml/io/testConnectedArpeggios_ref.xml b/mtest/musicxml/io/testConnectedArpeggios_ref.xml new file mode 100644 index 0000000000000..64c0528911c59 --- /dev/null +++ b/mtest/musicxml/io/testConnectedArpeggios_ref.xml @@ -0,0 +1,597 @@ + + + + + Connected Arpeggios + + + Henry Ives + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Piano + Pno. + + Piano + + + + 1 + 1 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + C + 5 + + 1 + 1 + quarter + up + + + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + E + 5 + + 1 + 1 + quarter + up + + + + G + 5 + + 1 + 1 + quarter + up + + + 4 + + + + F + 4 + + 4 + 2 + whole + + + + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + D + 5 + + 1 + 1 + quarter + up + + + + + G + 5 + + 1 + 1 + quarter + up + + + + F + 5 + + 1 + 1 + quarter + up + + + + B + 4 + + 1 + 1 + quarter + up + + + + + D + 5 + + 1 + 1 + quarter + up + + + 4 + + + + G + 4 + + 4 + 2 + whole + + + + + + C + 5 + + 1 + 1 + quarter + up + + + + A + 4 + + 1 + 1 + quarter + up + + + + + C + 5 + + 1 + 1 + quarter + up + + + + D + 5 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + + + A + 5 + + 1 + 1 + quarter + up + + + 4 + + + + A + 4 + + 4 + 2 + whole + + + + + + B + 4 + + 1 + 1 + quarter + up + + + + A + 5 + + 1 + 1 + quarter + up + + + + D + 5 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + E + 5 + + 1 + 1 + quarter + up + + + 4 + + + + C + 5 + + 4 + 2 + whole + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + + B + 5 + + 1 + 1 + quarter + up + + + + + + + 1 + 1 + quarter + + + + E + 5 + + 1 + 1 + quarter + up + + + + 1 + 1 + quarter + + + 4 + + + + E + 4 + + 4 + 2 + whole + + + + + + D + 5 + + 1 + 1 + quarter + up + + + + + + + + E + 5 + + 1 + 1 + quarter + up + + + + + + + D + 5 + + 1 + 1 + quarter + up + + + + A + 5 + + 1 + 1 + quarter + up + + + + C + 5 + + 1 + 1 + quarter + up + + + 4 + + + + F + 4 + + 4 + 2 + whole + + + + + + + + + F + 5 + + 1 + 1 + quarter + up + + + + + + + B + 4 + + 1 + 1 + quarter + up + + + + A + 4 + + 1 + 1 + quarter + up + + + + + F + 5 + + 1 + 1 + quarter + up + + + + E + 5 + + 1 + 1 + quarter + up + + + + + G + 5 + + 1 + 1 + quarter + up + + + 4 + + + + G + 4 + + 4 + 2 + whole + + + + + + light-heavy + + + + diff --git a/mtest/musicxml/io/tst_mxml_io.cpp b/mtest/musicxml/io/tst_mxml_io.cpp index c76ec05289ba9..cb7035329198a 100644 --- a/mtest/musicxml/io/tst_mxml_io.cpp +++ b/mtest/musicxml/io/tst_mxml_io.cpp @@ -86,6 +86,8 @@ private slots: void clefs1() { mxmlIoTest("testClefs1"); } void clefs2() { mxmlIoTest("testClefs2"); } void completeMeasureRests() { mxmlIoTest("testCompleteMeasureRests"); } + void connectedArpeggios1() { mxmlImportTestRef("testConnectedArpeggios"); } + void connectedArpeggios2() { mxmlIoTestRef("testConnectedArpeggios"); } void cueNotes() { mxmlIoTest("testCueNotes"); } void cueNotes2() { mxmlMscxExportTestRef("testCueNotes2"); } void cueNotes3() { mxmlImportTestRef("testCueNotes3"); }