From 2b5061fb8255db20378839cd8d31d8110b71d6af Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Tue, 25 Mar 2025 20:01:16 +0100 Subject: [PATCH 01/23] import accidentals on turn and mordents set parent --- .../internal/import/importmusicxmlpass2.cpp | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 6a29b5685df66..2d26c7b057721 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1317,6 +1317,8 @@ static void addTapToChord(const Notation& notation, ChordRest* cr) static void addMordentToChord(const Notation& notation, ChordRest* cr) { const String name = notation.name(); + const String accidAbove = notation.attribute(u"above"); + const String accidBelow = notation.attribute(u"below"); const String attrLong = notation.attribute(u"long"); const String attrAppr = notation.attribute(u"approach"); const String attrDep = notation.attribute(u"departure"); @@ -1359,6 +1361,18 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); + if (!accidAbove.empty()) { + Accidental* accidental = Factory::createAccidental(mordent); + accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); + accidental->setParent(mordent); + mordent->setAccidentalAbove(accidental); + } + if (!accidBelow.empty()) { + Accidental* accidental = Factory::createAccidental(mordent); + accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); + accidental->setParent(mordent); + mordent->setAccidentalBelow(accidental); + } cr->add(mordent); } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", @@ -1376,7 +1390,9 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) static void addTurnToChord(const Notation& notation, ChordRest* cr) { - SymId turnSym = notation.symId(); + const SymId turnSym = notation.symId(); + const String accidAbove = notation.attribute(u"above"); + const String accidBelow = notation.attribute(u"below"); const String place = notation.attribute(u"placement"); if (notation.attribute(u"slash") == "yes") { // TODO: currently this is the only available SMuFL turn with a slash @@ -1393,6 +1409,18 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) } turn->setVisible(notation.visible()); colorItem(turn, Color::fromString(notation.attribute(u"color"))); + if (!accidAbove.empty()) { + Accidental* accidental = Factory::createAccidental(turn); + accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); + accidental->setParent(turn); + turn->setAccidentalAbove(accidental); + } + if (!accidBelow.empty()) { + Accidental* accidental = Factory::createAccidental(turn); + accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); + accidental->setParent(turn); + turn->setAccidentalBelow(accidental); + } cr->add(turn); } @@ -8597,6 +8625,11 @@ void MusicXmlParserNotations::ornaments() notation.setVisible(m_visible); m_notations.push_back(notation); m_e.skipCurrentElement(); // skip but don't log + } else if (m_e.name() == "accidental-mark") { + Notation lastNotation = m_notations.back(); + if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { + lastNotation.addAttribute(m_e.attribute("placement"), m_e.readText()); + } } else { skipLogCurrElem(); } From 4ac49afb4c08643be5ab0af0bd99f7bee989c3c0 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Wed, 26 Mar 2025 14:03:54 +0100 Subject: [PATCH 02/23] add test --- .../tests/data/testOrnamentAccids.xml | 184 ++++++++++++++++++ .../musicxml/tests/musicxml_tests.cpp | 3 + 2 files changed, 187 insertions(+) create mode 100644 src/importexport/musicxml/tests/data/testOrnamentAccids.xml diff --git a/src/importexport/musicxml/tests/data/testOrnamentAccids.xml b/src/importexport/musicxml/tests/data/testOrnamentAccids.xml new file mode 100644 index 0000000000000..35dac2a76d290 --- /dev/null +++ b/src/importexport/musicxml/tests/data/testOrnamentAccids.xml @@ -0,0 +1,184 @@ + + + + + Untitled score + + + Composer / arranger + + MuseScore Studio 4.6.0 + 2025-03-25 + + + + + + + + 2025-03-25 + Apple Macintosh + Subtitle + + + + + Flute + Fl. + + Flute + wind.flutes.flute + + + + 1 + 74 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + G + 2 + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + sharp + + + + + + + + B + 4 + + 4 + 1 + whole + + + + sharp + sharp + + + + + light-heavy + + + + diff --git a/src/importexport/musicxml/tests/musicxml_tests.cpp b/src/importexport/musicxml/tests/musicxml_tests.cpp index cc0a0e7f7b8e3..d120c9fa35546 100644 --- a/src/importexport/musicxml/tests/musicxml_tests.cpp +++ b/src/importexport/musicxml/tests/musicxml_tests.cpp @@ -1048,6 +1048,9 @@ TEST_F(MusicXml_Tests, numerals) { TEST_F(MusicXml_Tests, ornaments) { musicXmlIoTest("testOrnaments"); } +TEST_F(MusicXml_Tests, ornamentAccids) { + musicXmlIoTest("testOrnamentAccids"); +} TEST_F(MusicXml_Tests, overlappingSpanners) { musicXmlIoTest("testOverlappingSpanners"); } From bf0b87cb97bcbe843335ebb39f7433f5ab68991b Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Wed, 26 Mar 2025 14:07:41 +0100 Subject: [PATCH 03/23] logging --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 2d26c7b057721..5732bf9aad57a 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1362,12 +1362,14 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); if (!accidAbove.empty()) { + LOGD("try to add accidental above"); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { + LOGD("try to add accidental below"); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(mordent); @@ -1410,12 +1412,14 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) turn->setVisible(notation.visible()); colorItem(turn, Color::fromString(notation.attribute(u"color"))); if (!accidAbove.empty()) { + LOGD("try to add accidental above"); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { + LOGD("try to add accidental below"); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(turn); @@ -8626,9 +8630,13 @@ void MusicXmlParserNotations::ornaments() m_notations.push_back(notation); m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "accidental-mark") { + LOGD("found accidental-amrk"); Notation lastNotation = m_notations.back(); if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { + LOGD("last ornament was %s", muPrintable(lastNotation.name())); lastNotation.addAttribute(m_e.attribute("placement"), m_e.readText()); + } else { + m_e.skipCurrentElement(); // skip but don't log } } else { skipLogCurrElem(); From 4aa9e75c591cedf7dd646ce52030a774093e5814 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Wed, 26 Mar 2025 15:27:01 +0100 Subject: [PATCH 04/23] update last ornament --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 5732bf9aad57a..097204c507edf 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1362,14 +1362,12 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); if (!accidAbove.empty()) { - LOGD("try to add accidental above"); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { - LOGD("try to add accidental below"); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(mordent); @@ -1412,14 +1410,12 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) turn->setVisible(notation.visible()); colorItem(turn, Color::fromString(notation.attribute(u"color"))); if (!accidAbove.empty()) { - LOGD("try to add accidental above"); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { - LOGD("try to add accidental below"); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(turn); @@ -8630,11 +8626,11 @@ void MusicXmlParserNotations::ornaments() m_notations.push_back(notation); m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "accidental-mark") { - LOGD("found accidental-amrk"); Notation lastNotation = m_notations.back(); if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { LOGD("last ornament was %s", muPrintable(lastNotation.name())); lastNotation.addAttribute(m_e.attribute("placement"), m_e.readText()); + m_notations.back() = lastNotation; } else { m_e.skipCurrentElement(); // skip but don't log } From 857ec49345c646201823e1abc17b1a2d6b0e461a Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Thu, 27 Mar 2025 11:41:19 +0100 Subject: [PATCH 05/23] loggit --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 097204c507edf..942f2f533d8c2 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1317,8 +1317,6 @@ static void addTapToChord(const Notation& notation, ChordRest* cr) static void addMordentToChord(const Notation& notation, ChordRest* cr) { const String name = notation.name(); - const String accidAbove = notation.attribute(u"above"); - const String accidBelow = notation.attribute(u"below"); const String attrLong = notation.attribute(u"long"); const String attrAppr = notation.attribute(u"approach"); const String attrDep = notation.attribute(u"departure"); @@ -1361,13 +1359,17 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); + const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { + LOGD("upper accid is %s", muPrintable(accidAbove)); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); } + const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { + LOGD("lower accid is %s", muPrintable(accidBelow)); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(mordent); @@ -1410,12 +1412,14 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) turn->setVisible(notation.visible()); colorItem(turn, Color::fromString(notation.attribute(u"color"))); if (!accidAbove.empty()) { + LOGD("upper accid is %s", muPrintable(accidAbove)); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { + LOGD("lower accid is %s", muPrintable(accidBelow)); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(turn); From f27ed987cbbecd5e8b4eafe52270251950b8701b Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Thu, 27 Mar 2025 12:28:27 +0100 Subject: [PATCH 06/23] split reading attribute and content --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 942f2f533d8c2..9c483610eb816 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -8633,7 +8633,8 @@ void MusicXmlParserNotations::ornaments() Notation lastNotation = m_notations.back(); if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { LOGD("last ornament was %s", muPrintable(lastNotation.name())); - lastNotation.addAttribute(m_e.attribute("placement"), m_e.readText()); + const String attr = m_e.attribute("placement"); + lastNotation.addAttribute(attr, m_e.readText()); m_notations.back() = lastNotation; } else { m_e.skipCurrentElement(); // skip but don't log From a417610b7b4ca025a7824e12395955d7c91cd74b Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Sat, 29 Mar 2025 12:14:13 +0100 Subject: [PATCH 07/23] more logs --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 9c483610eb816..2d39ff4095866 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -8634,8 +8634,10 @@ void MusicXmlParserNotations::ornaments() if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { LOGD("last ornament was %s", muPrintable(lastNotation.name())); const String attr = m_e.attribute("placement"); + LOGD("attribute is %s", muPrintable(attr)); lastNotation.addAttribute(attr, m_e.readText()); m_notations.back() = lastNotation; + LOGD("set attribute value %s", muPrintable(m_notations.back().attribute(attr))); } else { m_e.skipCurrentElement(); // skip but don't log } From 20d87a83340e9cef6abb74c28b7da36241a0f67d Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Tue, 1 Apr 2025 13:37:22 +0200 Subject: [PATCH 08/23] add accidentals after ornament --- .../internal/import/importmusicxmlpass2.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 2d39ff4095866..a86d45e91d50e 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1359,9 +1359,10 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); + cr->add(mordent); + const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { - LOGD("upper accid is %s", muPrintable(accidAbove)); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(mordent); @@ -1369,13 +1370,11 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { - LOGD("lower accid is %s", muPrintable(accidBelow)); Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(mordent); mordent->setAccidentalBelow(accidental); } - cr->add(mordent); } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", muPrintable(name), muPrintable(attrLong), muPrintable(attrAppr), muPrintable(attrDep)); // TODO @@ -1411,21 +1410,20 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) } turn->setVisible(notation.visible()); colorItem(turn, Color::fromString(notation.attribute(u"color"))); + cr->add(turn); + if (!accidAbove.empty()) { - LOGD("upper accid is %s", muPrintable(accidAbove)); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { - LOGD("lower accid is %s", muPrintable(accidBelow)); Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); accidental->setParent(turn); turn->setAccidentalBelow(accidental); } - cr->add(turn); } //--------------------------------------------------------- @@ -8632,12 +8630,9 @@ void MusicXmlParserNotations::ornaments() } else if (m_e.name() == "accidental-mark") { Notation lastNotation = m_notations.back(); if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { - LOGD("last ornament was %s", muPrintable(lastNotation.name())); const String attr = m_e.attribute("placement"); - LOGD("attribute is %s", muPrintable(attr)); lastNotation.addAttribute(attr, m_e.readText()); m_notations.back() = lastNotation; - LOGD("set attribute value %s", muPrintable(m_notations.back().attribute(attr))); } else { m_e.skipCurrentElement(); // skip but don't log } From 80f4c9d9f324d34f62dc5ecef4bec881517667e7 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Tue, 1 Apr 2025 13:46:43 +0200 Subject: [PATCH 09/23] adjust test --- .../musicxml/tests/data/testOrnamentAccids.xml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/importexport/musicxml/tests/data/testOrnamentAccids.xml b/src/importexport/musicxml/tests/data/testOrnamentAccids.xml index 35dac2a76d290..b95eb1979c326 100644 --- a/src/importexport/musicxml/tests/data/testOrnamentAccids.xml +++ b/src/importexport/musicxml/tests/data/testOrnamentAccids.xml @@ -2,24 +2,19 @@ - Untitled score + Ornaments with accidentals - Composer / arranger + Klaus Rettinghaus - MuseScore Studio 4.6.0 - 2025-03-25 + MuseScore 0.7.0 + 2007-09-10 - - 2025-03-25 - Apple Macintosh - Subtitle - @@ -27,7 +22,6 @@ Fl. Flute - wind.flutes.flute From d8c127919daad3eee9756d012f7708df1807bfe7 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Tue, 1 Apr 2025 14:15:12 +0200 Subject: [PATCH 10/23] fix --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index a86d45e91d50e..22ebb62c21d09 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1391,7 +1391,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) static void addTurnToChord(const Notation& notation, ChordRest* cr) { - const SymId turnSym = notation.symId(); + SymId turnSym = notation.symId(); const String accidAbove = notation.attribute(u"above"); const String accidBelow = notation.attribute(u"below"); const String place = notation.attribute(u"placement"); From 737fbeb7a910f3a6a8c31fe5aeaff0edc43152c2 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Tue, 1 Apr 2025 17:08:44 +0200 Subject: [PATCH 11/23] reorder --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 22ebb62c21d09..638c5095829ea 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1394,6 +1394,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) SymId turnSym = notation.symId(); const String accidAbove = notation.attribute(u"above"); const String accidBelow = notation.attribute(u"below"); + const Color color = Color::fromString(notation.attribute(u"color")); const String place = notation.attribute(u"placement"); if (notation.attribute(u"slash") == "yes") { // TODO: currently this is the only available SMuFL turn with a slash @@ -1412,12 +1413,14 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) colorItem(turn, Color::fromString(notation.attribute(u"color"))); cr->add(turn); + const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } + const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); From 1108fe5983c6428d9658ef53a856054c0c73c57a Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Wed, 2 Apr 2025 10:25:32 +0200 Subject: [PATCH 12/23] add default param --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 8 ++++---- .../musicxml/internal/shared/musicxmlsupport.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 638c5095829ea..982b8cae6bfc8 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1364,14 +1364,14 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); + accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); + accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); accidental->setParent(mordent); mordent->setAccidentalBelow(accidental); } @@ -1416,14 +1416,14 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove, String())); + accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow, String())); + accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); accidental->setParent(turn); turn->setAccidentalBelow(accidental); } diff --git a/src/importexport/musicxml/internal/shared/musicxmlsupport.h b/src/importexport/musicxml/internal/shared/musicxmlsupport.h index 02cea2212cf09..bae850a0f310c 100644 --- a/src/importexport/musicxml/internal/shared/musicxmlsupport.h +++ b/src/importexport/musicxml/internal/shared/musicxmlsupport.h @@ -56,7 +56,7 @@ extern muse::String accSymId2MusicXmlString(const engraving::SymId id); extern muse::String accSymId2SmuflMusicXmlString(const engraving::SymId id); extern muse::String accidentalType2MusicXmlString(const engraving::AccidentalType type); extern muse::String accidentalType2SmuflMusicXmlString(const engraving::AccidentalType type); -extern engraving::AccidentalType musicXmlString2accidentalType(const muse::String mxmlName, const muse::String smufl); +extern engraving::AccidentalType musicXmlString2accidentalType(const muse::String mxmlName, const muse::String smufl = {}); extern muse::String musicXmlAccidentalTextToChar(const muse::String mxmlName); extern engraving::SymId musicXmlString2accSymId(const muse::String mxmlName, const muse::String smufl = {}); extern engraving::AccidentalType microtonalGuess(double val); From 0663a069c423644a57e7497f14cc7b816f2daa6a Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Mon, 28 Jul 2025 14:26:31 +0200 Subject: [PATCH 13/23] add log --- .../internal/import/importmusicxmlpass2.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 982b8cae6bfc8..be600e2f1adb1 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1363,18 +1363,29 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidAbove); + if (type == AccidentalType::NONE) { + LOGD("MusicXml::import: no accidental type for above accidental in mordent"); + } Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); + accidental->setAccidentalType(type); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidBelow); + if (type == AccidentalType::NONE) { + LOGD("MusicXml::import: no accidental type for below accidental in mordent"); + } Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); + accidental->setAccidentalType(type); accidental->setParent(mordent); mordent->setAccidentalBelow(accidental); } + if (!mordent->accidentalAbove() || !mordent->accidentalBelow()) { + LOGD("MusicXml::import: no accidental above or below in mordent"); + } } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", muPrintable(name), muPrintable(attrLong), muPrintable(attrAppr), muPrintable(attrDep)); // TODO From 888d56961b2aec74c2189ed96b3e6c3d5f433554 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Mon, 28 Jul 2025 20:12:00 +0200 Subject: [PATCH 14/23] immer mehr --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index be600e2f1adb1..5d1744e58d5e6 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1363,6 +1363,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { + LOGD("upper accid is %s", muPrintable(accidAbove)); const AccidentalType type = musicXmlString2accidentalType(accidAbove); if (type == AccidentalType::NONE) { LOGD("MusicXml::import: no accidental type for above accidental in mordent"); @@ -1371,9 +1372,13 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) accidental->setAccidentalType(type); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); + if (!mordent->accidentalAbove()) { + LOGD("MusicXml::import: no accidental above in mordent"); + } } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { + LOGD("lower accid is %s", muPrintable(accidBelow)); const AccidentalType type = musicXmlString2accidentalType(accidBelow); if (type == AccidentalType::NONE) { LOGD("MusicXml::import: no accidental type for below accidental in mordent"); @@ -1382,9 +1387,9 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) accidental->setAccidentalType(type); accidental->setParent(mordent); mordent->setAccidentalBelow(accidental); - } - if (!mordent->accidentalAbove() || !mordent->accidentalBelow()) { - LOGD("MusicXml::import: no accidental above or below in mordent"); + if (!mordent->accidentalBelow()) { + LOGD("MusicXml::import: no accidental below in mordent"); + } } } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", From 904f5e7a6d8783323d817cb46e2afd57592e9efa Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Sat, 20 Sep 2025 12:45:01 +0200 Subject: [PATCH 15/23] later alligator --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 5d1744e58d5e6..743444378d5a4 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1359,7 +1359,6 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); - cr->add(mordent); const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { @@ -1391,6 +1390,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) LOGD("MusicXml::import: no accidental below in mordent"); } } + cr->add(mordent); } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", muPrintable(name), muPrintable(attrLong), muPrintable(attrAppr), muPrintable(attrDep)); // TODO From 1383bc713f79db15486114607050b5e5ef16d01d Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Sat, 20 Sep 2025 13:18:45 +0200 Subject: [PATCH 16/23] fix --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 743444378d5a4..e668f70bbd454 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1429,14 +1429,12 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) colorItem(turn, Color::fromString(notation.attribute(u"color"))); cr->add(turn); - const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } - const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); From 4f3101c87e5360d0b0e6f5be586a8a9a403af8f6 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Fri, 10 Oct 2025 13:12:15 +0200 Subject: [PATCH 17/23] track it --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index e668f70bbd454..ee84336d140d3 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1369,6 +1369,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); + accidental->setTrack(mordent->track()); accidental->setParent(mordent); mordent->setAccidentalAbove(accidental); if (!mordent->accidentalAbove()) { @@ -1384,6 +1385,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); + accidental->setTrack(mordent->track()); accidental->setParent(mordent); mordent->setAccidentalBelow(accidental); if (!mordent->accidentalBelow()) { @@ -1432,12 +1434,14 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) if (!accidAbove.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); + accidental->setTrack(turn->track()); accidental->setParent(turn); turn->setAccidentalAbove(accidental); } if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); + accidental->setTrack(turn->track()); accidental->setParent(turn); turn->setAccidentalBelow(accidental); } From 9d42be9f83878434ce48371242c7e5e50bfe030e Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Fri, 10 Oct 2025 15:53:33 +0200 Subject: [PATCH 18/23] shit --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index ee84336d140d3..14b23ffe4d311 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -65,6 +65,7 @@ #include "engraving/dom/measure.h" #include "engraving/dom/mscore.h" #include "engraving/dom/note.h" +#include "engraving/dom/ornament.h" #include "engraving/dom/ottava.h" #include "engraving/dom/part.h" #include "engraving/dom/pedal.h" @@ -1437,6 +1438,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) accidental->setTrack(turn->track()); accidental->setParent(turn); turn->setAccidentalAbove(accidental); + turn->add(accidental); } if (!accidBelow.empty()) { Accidental* accidental = Factory::createAccidental(turn); @@ -1444,6 +1446,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) accidental->setTrack(turn->track()); accidental->setParent(turn); turn->setAccidentalBelow(accidental); + turn->add(accidental); } } From 0f4df4dd468a990e39da1d60304f318b15b02e89 Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Fri, 6 Feb 2026 09:43:31 +0100 Subject: [PATCH 19/23] reorder --- .../musicxml/internal/import/importmusicxmlpass2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 14b23ffe4d311..26e169a84bf4a 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -8653,8 +8653,8 @@ void MusicXmlParserNotations::ornaments() m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "accidental-mark") { Notation lastNotation = m_notations.back(); - if (lastNotation.parent() == u"ornaments" && !m_e.attribute("placement").empty()) { - const String attr = m_e.attribute("placement"); + const String attr = m_e.attribute("placement"); + if (lastNotation.parent() == u"ornaments" && !attr.empty()) { lastNotation.addAttribute(attr, m_e.readText()); m_notations.back() = lastNotation; } else { From 9b22852ba8d2895f457ea25e31cc0846c4fd8331 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:26:02 +0000 Subject: [PATCH 20/23] Import MusicXML accidental marks on ornaments - Fixed `MusicXmlParserNotations::ornaments()` to correctly associate `` with preceding ornaments, including ``. - Added robust heuristic for default placement of accidental marks if the `placement` attribute is missing. - Added support for the `smufl` attribute on ``. - Updated `addMordentToChord`, `addTurnToChord`, and `addOtherOrnamentToChord` to correctly create, type, and add `Accidental` items as children to ornaments. - Ensured ornaments are added to the score before their children are processed for better architectural consistency. Co-authored-by: rettinghaus <7693447+rettinghaus@users.noreply.github.com> --- .../internal/import/importmusicxmlpass2.cpp | 144 +++++++++++++----- 1 file changed, 103 insertions(+), 41 deletions(-) diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 26e169a84bf4a..3b49f4f79c058 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1360,40 +1360,44 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) } mordent->setVisible(notation.visible()); colorItem(mordent, Color::fromString(notation.attribute(u"color"))); + cr->add(mordent); const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { LOGD("upper accid is %s", muPrintable(accidAbove)); - const AccidentalType type = musicXmlString2accidentalType(accidAbove); + const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); if (type == AccidentalType::NONE) { LOGD("MusicXml::import: no accidental type for above accidental in mordent"); - } - Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(type); - accidental->setTrack(mordent->track()); - accidental->setParent(mordent); - mordent->setAccidentalAbove(accidental); - if (!mordent->accidentalAbove()) { - LOGD("MusicXml::import: no accidental above in mordent"); + } else { + Accidental* accidental = Factory::createAccidental(mordent); + accidental->setAccidentalType(type); + accidental->setTrack(mordent->track()); + accidental->setParent(mordent); + mordent->setAccidentalAbove(accidental); + mordent->add(accidental); + if (!mordent->accidentalAbove()) { + LOGD("MusicXml::import: no accidental above in mordent"); + } } } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { LOGD("lower accid is %s", muPrintable(accidBelow)); - const AccidentalType type = musicXmlString2accidentalType(accidBelow); + const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); if (type == AccidentalType::NONE) { LOGD("MusicXml::import: no accidental type for below accidental in mordent"); - } - Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(type); - accidental->setTrack(mordent->track()); - accidental->setParent(mordent); - mordent->setAccidentalBelow(accidental); - if (!mordent->accidentalBelow()) { - LOGD("MusicXml::import: no accidental below in mordent"); + } else { + Accidental* accidental = Factory::createAccidental(mordent); + accidental->setAccidentalType(type); + accidental->setTrack(mordent->track()); + accidental->setParent(mordent); + mordent->setAccidentalBelow(accidental); + mordent->add(accidental); + if (!mordent->accidentalBelow()) { + LOGD("MusicXml::import: no accidental below in mordent"); + } } } - cr->add(mordent); } else { LOGD("unknown ornament: name '%s' long '%s' approach '%s' departure '%s'", muPrintable(name), muPrintable(attrLong), muPrintable(attrAppr), muPrintable(attrDep)); // TODO @@ -1433,20 +1437,26 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) cr->add(turn); if (!accidAbove.empty()) { - Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(musicXmlString2accidentalType(accidAbove)); - accidental->setTrack(turn->track()); - accidental->setParent(turn); - turn->setAccidentalAbove(accidental); - turn->add(accidental); + const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); + if (type != AccidentalType::NONE) { + Accidental* accidental = Factory::createAccidental(turn); + accidental->setAccidentalType(type); + accidental->setTrack(turn->track()); + accidental->setParent(turn); + turn->setAccidentalAbove(accidental); + turn->add(accidental); + } } if (!accidBelow.empty()) { - Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(musicXmlString2accidentalType(accidBelow)); - accidental->setTrack(turn->track()); - accidental->setParent(turn); - turn->setAccidentalBelow(accidental); - turn->add(accidental); + const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); + if (type != AccidentalType::NONE) { + Accidental* accidental = Factory::createAccidental(turn); + accidental->setAccidentalType(type); + accidental->setTrack(turn->track()); + accidental->setParent(turn); + turn->setAccidentalBelow(accidental); + turn->add(accidental); + } } } @@ -1471,6 +1481,31 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) ornam->setVisible(notation.visible()); colorItem(ornam, Color::fromString(notation.attribute(u"color"))); cr->add(ornam); + + const String accidAbove = notation.attribute(u"above"); + if (!accidAbove.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); + if (type != AccidentalType::NONE) { + Accidental* accidental = Factory::createAccidental(ornam); + accidental->setAccidentalType(type); + accidental->setTrack(ornam->track()); + accidental->setParent(ornam); + ornam->setAccidentalAbove(accidental); + ornam->add(accidental); + } + } + const String accidBelow = notation.attribute(u"below"); + if (!accidBelow.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); + if (type != AccidentalType::NONE) { + Accidental* accidental = Factory::createAccidental(ornam); + accidental->setAccidentalType(type); + accidental->setTrack(ornam->track()); + accidental->setParent(ornam); + ornam->setAccidentalBelow(accidental); + ornam->add(accidental); + } + } } else { LOGD("unknown ornament: name '%s': '%s'.", muPrintable(name), muPrintable(symname)); } @@ -8617,6 +8652,9 @@ void MusicXmlParserNotations::ornaments() m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "trill-mark") { trillMark = true; + Notation notation = Notation::notationWithAttributes(u"trill-mark", m_e.attributes(), u"ornaments", SymId::ornamentTrill); + notation.setVisible(m_visible); + m_notations.push_back(notation); m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "wavy-line") { bool wavyLineTypeWasStart = (m_wavyLineType == "start"); @@ -8652,11 +8690,29 @@ void MusicXmlParserNotations::ornaments() m_notations.push_back(notation); m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "accidental-mark") { - Notation lastNotation = m_notations.back(); - const String attr = m_e.attribute("placement"); - if (lastNotation.parent() == u"ornaments" && !attr.empty()) { - lastNotation.addAttribute(attr, m_e.readText()); - m_notations.back() = lastNotation; + if (!m_notations.empty()) { + Notation& lastNotation = m_notations.back(); + String placement = m_e.attribute("placement"); + String smufl = m_e.attribute("smufl"); + if (lastNotation.parent() == u"ornaments") { + if (placement.empty()) { + if (lastNotation.name() == u"turn" || lastNotation.name() == u"inverted-turn") { + if (lastNotation.attribute(u"above").empty()) { + placement = u"above"; + } else { + placement = u"below"; + } + } else { + placement = (lastNotation.name() == u"mordent" ? u"below" : u"above"); + } + } + lastNotation.addAttribute(placement, m_e.readText()); + if (!smufl.empty()) { + lastNotation.addAttribute(placement + u"-smufl", smufl); + } + } else { + m_e.skipCurrentElement(); + } } else { m_e.skipCurrentElement(); // skip but don't log } @@ -8666,11 +8722,17 @@ void MusicXmlParserNotations::ornaments() } // note that mscore wavy line already implicitly includes a trillsym - // so don't add an additional one - if (trillMark && m_wavyLineType != "start" && m_wavyLineType != "startstop") { - Notation ornament = Notation::notationWithAttributes(u"trill-mark", m_e.attributes(), u"ornaments", SymId::ornamentTrill); - ornament.setVisible(m_visible); - m_notations.push_back(ornament); + // so remove it if it was added + if (trillMark && (m_wavyLineType == "start" || m_wavyLineType == "startstop")) { + for (auto it = m_notations.begin(); it != m_notations.end(); ++it) { + if (it->name() == u"trill-mark") { + // but only remove it if it doesn't have accidental marks! + if (it->attribute(u"above").empty() && it->attribute(u"below").empty()) { + m_notations.erase(it); + } + break; + } + } } } From 47c32184fa38767e7c93fe5d0111b81e7197ee60 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:11:53 +0000 Subject: [PATCH 21/23] Fix MusicXML ornament accidental import by implementing add() overrides - Implemented `Ornament::add(EngravingItem*)` to correctly register accidental children and set their internal pointers. - Implemented `Trill::add(EngravingItem*)` to handle accidental children for line trills. - Updated MusicXML importer to set accidental placement before calling `add()`. - Simplified accidental creation logic in `addMordentToChord`, `addTurnToChord`, and `addOtherOrnamentToChord`. - This ensures accidentals are correctly associated with ornaments in the MuseScore object tree, resolving unit test failures. Co-authored-by: rettinghaus <7693447+rettinghaus@users.noreply.github.com> --- src/engraving/dom/ornament.cpp | 23 +++++++++++++ src/engraving/dom/ornament.h | 1 + src/engraving/dom/trill.cpp | 10 ++++++ src/engraving/dom/trill.h | 1 + .../internal/import/importmusicxmlpass2.cpp | 34 +++++-------------- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/engraving/dom/ornament.cpp b/src/engraving/dom/ornament.cpp index cedba8937589e..473fe2629d4ee 100644 --- a/src/engraving/dom/ornament.cpp +++ b/src/engraving/dom/ornament.cpp @@ -83,6 +83,29 @@ Ornament::~Ornament() m_cueNoteChord = nullptr; } +void Ornament::add(EngravingItem* e) +{ + if (e->isAccidental()) { + Accidental* acc = toAccidental(e); + if (acc->placement() == PlacementV::ABOVE) { + setAccidentalAbove(acc); + } else if (acc->placement() == PlacementV::BELOW) { + setAccidentalBelow(acc); + } else { + if (hasIntervalAbove() && !accidentalAbove()) { + acc->setPlacement(PlacementV::ABOVE); + setAccidentalAbove(acc); + } else if (hasIntervalBelow() && !accidentalBelow()) { + acc->setPlacement(PlacementV::BELOW); + setAccidentalBelow(acc); + } + } + e->added(); + } else { + Articulation::add(e); + } +} + void Ornament::remove(EngravingItem* e) { if (e->isAccidental()) { diff --git a/src/engraving/dom/ornament.h b/src/engraving/dom/ornament.h index 564b264476668..d19baa5fdcc8c 100644 --- a/src/engraving/dom/ornament.h +++ b/src/engraving/dom/ornament.h @@ -55,6 +55,7 @@ class Ornament final : public Articulation void scanElements(std::function func) override; + void add(EngravingItem*) override; void remove(EngravingItem* e) override; Chord* cueNoteChord() const { return m_cueNoteChord; } diff --git a/src/engraving/dom/trill.cpp b/src/engraving/dom/trill.cpp index 4d3582b31a6e1..060ef5903343d 100644 --- a/src/engraving/dom/trill.cpp +++ b/src/engraving/dom/trill.cpp @@ -221,6 +221,16 @@ EngravingItem* Trill::linkedClone() // remove //--------------------------------------------------------- +void Trill::add(EngravingItem* e) +{ + if (e->isAccidental()) { + m_accidental = toAccidental(e); + e->added(); + } else { + SLine::add(e); + } +} + void Trill::remove(EngravingItem* e) { if (e == m_accidental) { diff --git a/src/engraving/dom/trill.h b/src/engraving/dom/trill.h index e762fc5b18961..2e98a02ab2f35 100644 --- a/src/engraving/dom/trill.h +++ b/src/engraving/dom/trill.h @@ -85,6 +85,7 @@ class Trill final : public SLine EngravingItem* linkedClone() override; LineSegment* createLineSegment(System* parent) override; + void add(EngravingItem*) override; void remove(EngravingItem*) override; void setTrack(track_idx_t n) override; diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 3b49f4f79c058..754cefcfe9c83 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1364,38 +1364,24 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) const String accidAbove = notation.attribute(u"above"); if (!accidAbove.empty()) { - LOGD("upper accid is %s", muPrintable(accidAbove)); const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); - if (type == AccidentalType::NONE) { - LOGD("MusicXml::import: no accidental type for above accidental in mordent"); - } else { + if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); accidental->setTrack(mordent->track()); - accidental->setParent(mordent); - mordent->setAccidentalAbove(accidental); + accidental->setPlacement(PlacementV::ABOVE); mordent->add(accidental); - if (!mordent->accidentalAbove()) { - LOGD("MusicXml::import: no accidental above in mordent"); - } } } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { - LOGD("lower accid is %s", muPrintable(accidBelow)); const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); - if (type == AccidentalType::NONE) { - LOGD("MusicXml::import: no accidental type for below accidental in mordent"); - } else { + if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); accidental->setTrack(mordent->track()); - accidental->setParent(mordent); - mordent->setAccidentalBelow(accidental); + accidental->setPlacement(PlacementV::BELOW); mordent->add(accidental); - if (!mordent->accidentalBelow()) { - LOGD("MusicXml::import: no accidental below in mordent"); - } } } } else { @@ -1442,8 +1428,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(type); accidental->setTrack(turn->track()); - accidental->setParent(turn); - turn->setAccidentalAbove(accidental); + accidental->setPlacement(PlacementV::ABOVE); turn->add(accidental); } } @@ -1453,8 +1438,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(type); accidental->setTrack(turn->track()); - accidental->setParent(turn); - turn->setAccidentalBelow(accidental); + accidental->setPlacement(PlacementV::BELOW); turn->add(accidental); } } @@ -1489,8 +1473,7 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) Accidental* accidental = Factory::createAccidental(ornam); accidental->setAccidentalType(type); accidental->setTrack(ornam->track()); - accidental->setParent(ornam); - ornam->setAccidentalAbove(accidental); + accidental->setPlacement(PlacementV::ABOVE); ornam->add(accidental); } } @@ -1501,8 +1484,7 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) Accidental* accidental = Factory::createAccidental(ornam); accidental->setAccidentalType(type); accidental->setTrack(ornam->track()); - accidental->setParent(ornam); - ornam->setAccidentalBelow(accidental); + accidental->setPlacement(PlacementV::BELOW); ornam->add(accidental); } } From 9cc61bfec6fc9006049fb6c7546a28f158852846 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:33:14 +0000 Subject: [PATCH 22/23] fix(musicxml): fix import of accidental marks on ornaments This commit fixes the import of `` elements associated with ornaments (mordents, turns, trills) in MusicXML. Key changes: - Modified `MusicXmlParserNotations::ornaments()` to correctly associate trailing `` elements with their preceding ornaments, including support for implicit placements. - Implemented `add(EngravingItem*)` in `Ornament` and `Trill` classes to handle accidental children correctly. - Updated `Ornament::updateAccidentalsAboveAndBelow` to respect `AccidentalRole::USER`, preventing manually added accidentals from being deleted during layout recomputation. - Updated MusicXML importer to set `AccidentalRole::USER` on all imported ornament accidentals and use the new `add()` method. - Added support for the `smufl` attribute on `` elements in `musicXmlString2accidentalType`. These changes ensure that accidentals on ornaments are correctly imported and persist through MuseScore's layout and export cycles, satisfying the requirements for MusicXML interoperability. Co-authored-by: rettinghaus <7693447+rettinghaus@users.noreply.github.com> --- src/engraving/dom/ornament.cpp | 5 +++++ .../musicxml/internal/import/importmusicxmlpass2.cpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/engraving/dom/ornament.cpp b/src/engraving/dom/ornament.cpp index 473fe2629d4ee..d68e24a37ea45 100644 --- a/src/engraving/dom/ornament.cpp +++ b/src/engraving/dom/ornament.cpp @@ -393,6 +393,11 @@ void Ornament::updateAccidentalsAboveAndBelow() Note* note = m_notesAboveAndBelow[i]; Accidental* accidental = note ? note->accidental() : nullptr; Accidental*& curAccidental = m_accidentalsAboveAndBelow[i]; + + if (curAccidental && curAccidental->role() == AccidentalRole::USER) { + continue; + } + if (showCueNote() || !accidental) { if (curAccidental) { delete curAccidental; diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 754cefcfe9c83..40e9207ec8020 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -1368,6 +1368,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(mordent->track()); accidental->setPlacement(PlacementV::ABOVE); mordent->add(accidental); @@ -1379,6 +1380,7 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(mordent); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(mordent->track()); accidental->setPlacement(PlacementV::BELOW); mordent->add(accidental); @@ -1427,6 +1429,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(turn->track()); accidental->setPlacement(PlacementV::ABOVE); turn->add(accidental); @@ -1437,6 +1440,7 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(turn); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(turn->track()); accidental->setPlacement(PlacementV::BELOW); turn->add(accidental); @@ -1472,6 +1476,7 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(ornam); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(ornam->track()); accidental->setPlacement(PlacementV::ABOVE); ornam->add(accidental); @@ -1483,6 +1488,7 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) if (type != AccidentalType::NONE) { Accidental* accidental = Factory::createAccidental(ornam); accidental->setAccidentalType(type); + accidental->setRole(AccidentalRole::USER); accidental->setTrack(ornam->track()); accidental->setPlacement(PlacementV::BELOW); ornam->add(accidental); From 54d3bafe853fe676ee0ff99ef7e4f9ced917d86b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:07:27 +0000 Subject: [PATCH 23/23] fix(musicxml): fix accidental mark import without core changes This commit fixes the import of accidental marks on ornaments (mordents, turns, trills) in MusicXML using a non-invasive approach that stays within the musicxml directory. Key changes: - Reverted previous changes to ornament.cpp/h and trill.cpp/h. - Implemented `setOrnamentIntervalFromAccidental` in `importmusicxmlpass2.cpp` to map accidental marks to explicit `OrnamentInterval` properties. - Set `showAccidental` property to `ALWAYS` for imported ornaments with accidentals, ensuring they appear correctly in the score. - Modified `MusicXmlParserNotations` to correctly associate trailing `` elements with preceding ornaments, and handle the redundant `trill-mark` association with `wavy-line` start. - Supported the `smufl` attribute on `` for better mapping in `musicXmlString2accidentalType`. This approach ensures that imported accidentals persist through MuseScore's layout engine without requiring modifications to the core DOM or layout logic. Co-authored-by: rettinghaus <7693447+rettinghaus@users.noreply.github.com> --- src/engraving/dom/ornament.cpp | 28 ---- src/engraving/dom/ornament.h | 1 - src/engraving/dom/trill.cpp | 10 -- src/engraving/dom/trill.h | 1 - .../internal/import/importmusicxmlpass2.cpp | 152 +++++++++++++----- .../internal/import/importmusicxmlpass2.h | 4 + 6 files changed, 113 insertions(+), 83 deletions(-) diff --git a/src/engraving/dom/ornament.cpp b/src/engraving/dom/ornament.cpp index d68e24a37ea45..cedba8937589e 100644 --- a/src/engraving/dom/ornament.cpp +++ b/src/engraving/dom/ornament.cpp @@ -83,29 +83,6 @@ Ornament::~Ornament() m_cueNoteChord = nullptr; } -void Ornament::add(EngravingItem* e) -{ - if (e->isAccidental()) { - Accidental* acc = toAccidental(e); - if (acc->placement() == PlacementV::ABOVE) { - setAccidentalAbove(acc); - } else if (acc->placement() == PlacementV::BELOW) { - setAccidentalBelow(acc); - } else { - if (hasIntervalAbove() && !accidentalAbove()) { - acc->setPlacement(PlacementV::ABOVE); - setAccidentalAbove(acc); - } else if (hasIntervalBelow() && !accidentalBelow()) { - acc->setPlacement(PlacementV::BELOW); - setAccidentalBelow(acc); - } - } - e->added(); - } else { - Articulation::add(e); - } -} - void Ornament::remove(EngravingItem* e) { if (e->isAccidental()) { @@ -393,11 +370,6 @@ void Ornament::updateAccidentalsAboveAndBelow() Note* note = m_notesAboveAndBelow[i]; Accidental* accidental = note ? note->accidental() : nullptr; Accidental*& curAccidental = m_accidentalsAboveAndBelow[i]; - - if (curAccidental && curAccidental->role() == AccidentalRole::USER) { - continue; - } - if (showCueNote() || !accidental) { if (curAccidental) { delete curAccidental; diff --git a/src/engraving/dom/ornament.h b/src/engraving/dom/ornament.h index d19baa5fdcc8c..564b264476668 100644 --- a/src/engraving/dom/ornament.h +++ b/src/engraving/dom/ornament.h @@ -55,7 +55,6 @@ class Ornament final : public Articulation void scanElements(std::function func) override; - void add(EngravingItem*) override; void remove(EngravingItem* e) override; Chord* cueNoteChord() const { return m_cueNoteChord; } diff --git a/src/engraving/dom/trill.cpp b/src/engraving/dom/trill.cpp index 060ef5903343d..4d3582b31a6e1 100644 --- a/src/engraving/dom/trill.cpp +++ b/src/engraving/dom/trill.cpp @@ -221,16 +221,6 @@ EngravingItem* Trill::linkedClone() // remove //--------------------------------------------------------- -void Trill::add(EngravingItem* e) -{ - if (e->isAccidental()) { - m_accidental = toAccidental(e); - e->added(); - } else { - SLine::add(e); - } -} - void Trill::remove(EngravingItem* e) { if (e == m_accidental) { diff --git a/src/engraving/dom/trill.h b/src/engraving/dom/trill.h index 2e98a02ab2f35..e762fc5b18961 100644 --- a/src/engraving/dom/trill.h +++ b/src/engraving/dom/trill.h @@ -85,7 +85,6 @@ class Trill final : public SLine EngravingItem* linkedClone() override; LineSegment* createLineSegment(System* parent) override; - void add(EngravingItem*) override; void remove(EngravingItem*) override; void setTrack(track_idx_t n) override; diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp index 40e9207ec8020..7e300891297b0 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp @@ -119,6 +119,53 @@ static std::shared_ptr configuration( return muse::modularity::globalIoc()->resolve("iex_musicxml"); } +static void setOrnamentIntervalFromAccidental(Ornament* ornam, Note* mainNote, AccidentalType accType, bool above) +{ + if (!mainNote) { + return; + } + + // Desired alter value + AccidentalVal desiredAlter = Accidental::subtype2value(accType); + + // Try different interval types + // MAJOR, MINOR, PERFECT, AUGMENTED, DIMINISHED + static const std::vector types = { + IntervalType::MAJOR, IntervalType::MINOR, + IntervalType::AUGMENTED, IntervalType::DIMINISHED, + IntervalType::PERFECT + }; + + for (IntervalType it : types) { + OrnamentInterval oi; + oi.type = it; + oi.step = IntervalStep::SECOND; + + Interval interval = Interval::fromOrnamentInterval(oi); + if (!above) { + interval.flip(); + } + + int tpc = mainNote->tpc(); + int transposedTpc = Transpose::transposeTpc(tpc, interval, true); + if (tpcIsValid(transposedTpc)) { + if (tpc2alter(transposedTpc) == desiredAlter) { + if (above) { + ornam->setIntervalAbove(oi); + } else { + ornam->setIntervalBelow(oi); + } + ornam->setShowAccidental(OrnamentShowAccidental::ALWAYS); + return; + } + } + } + + // Fallback: if no match found with SECOND step, try UNISON for unusual accidentals? + // Or just force the accidental visibility anyway. + ornam->setShowAccidental(OrnamentShowAccidental::ALWAYS); +} + static std::shared_ptr engravingFonts() { return muse::modularity::globalIoc()->resolve("iex_musicxml"); @@ -1366,24 +1413,18 @@ static void addMordentToChord(const Notation& notation, ChordRest* cr) if (!accidAbove.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(mordent->track()); - accidental->setPlacement(PlacementV::ABOVE); - mordent->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(mordent, mainNote, type, true); } } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(mordent); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(mordent->track()); - accidental->setPlacement(PlacementV::BELOW); - mordent->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(mordent, mainNote, type, false); } } } else { @@ -1427,23 +1468,17 @@ static void addTurnToChord(const Notation& notation, ChordRest* cr) if (!accidAbove.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(turn->track()); - accidental->setPlacement(PlacementV::ABOVE); - turn->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(turn, mainNote, type, true); } } if (!accidBelow.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(turn); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(turn->track()); - accidental->setPlacement(PlacementV::BELOW); - turn->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(turn, mainNote, type, false); } } } @@ -1474,24 +1509,18 @@ static void addOtherOrnamentToChord(const Notation& notation, ChordRest* cr) if (!accidAbove.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidAbove, notation.attribute(u"above-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(ornam); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(ornam->track()); - accidental->setPlacement(PlacementV::ABOVE); - ornam->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(ornam, mainNote, type, true); } } const String accidBelow = notation.attribute(u"below"); if (!accidBelow.empty()) { const AccidentalType type = musicXmlString2accidentalType(accidBelow, notation.attribute(u"below-smufl")); if (type != AccidentalType::NONE) { - Accidental* accidental = Factory::createAccidental(ornam); - accidental->setAccidentalType(type); - accidental->setRole(AccidentalRole::USER); - accidental->setTrack(ornam->track()); - accidental->setPlacement(PlacementV::BELOW); - ornam->add(accidental); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + setOrnamentIntervalFromAccidental(ornam, mainNote, type, false); } } } else { @@ -8629,6 +8658,8 @@ void MusicXmlParserNotations::articulations() void MusicXmlParserNotations::ornaments() { bool trillMark = false; + String trillAccidAbove, trillAccidBelow, trillAccidAboveSmufl, trillAccidBelowSmufl; + // while (m_e.readNextStartElement()) { SymId id { SymId::noSym }; @@ -8661,6 +8692,13 @@ void MusicXmlParserNotations::ornaments() if (wavyLineTypeWasStart && m_wavyLineType == u"stop") { m_wavyLineType = u"startstop"; } + // If it is a start, it might be associated with a preceding trill-mark's accidentals + if (m_wavyLineType == u"start" || m_wavyLineType == u"startstop") { + m_wavyLineAccidAbove = trillAccidAbove; + m_wavyLineAccidBelow = trillAccidBelow; + m_wavyLineAccidAboveSmufl = trillAccidAboveSmufl; + m_wavyLineAccidBelowSmufl = trillAccidBelowSmufl; + } m_e.skipCurrentElement(); // skip but don't log } else if (m_e.name() == "tremolo") { m_hasTremolo = true; @@ -8694,10 +8732,22 @@ void MusicXmlParserNotations::ornaments() placement = (lastNotation.name() == u"mordent" ? u"below" : u"above"); } } - lastNotation.addAttribute(placement, m_e.readText()); + String text = m_e.readText(); + lastNotation.addAttribute(placement, text); if (!smufl.empty()) { lastNotation.addAttribute(placement + u"-smufl", smufl); } + + // Also store if it's a trill-mark, for possible wavy-line association + if (lastNotation.name() == u"trill-mark") { + if (placement == u"above") { + trillAccidAbove = text; + trillAccidAboveSmufl = smufl; + } else { + trillAccidBelow = text; + trillAccidBelowSmufl = smufl; + } + } } else { m_e.skipCurrentElement(); } @@ -8714,10 +8764,7 @@ void MusicXmlParserNotations::ornaments() if (trillMark && (m_wavyLineType == "start" || m_wavyLineType == "startstop")) { for (auto it = m_notations.begin(); it != m_notations.end(); ++it) { if (it->name() == u"trill-mark") { - // but only remove it if it doesn't have accidental marks! - if (it->attribute(u"above").empty() && it->attribute(u"below").empty()) { - m_notations.erase(it); - } + m_notations.erase(it); break; } } @@ -9263,7 +9310,9 @@ static void addTie(const Notation& notation, Note* note, const track_idx_t track static void addWavyLine(ChordRest* cr, const Fraction& tick, const int wavyLineNo, const String& wavyLineType, MusicXmlSpannerMap& spanners, TrillStack& trills, - MusicXmlLogger* logger, const XmlStreamReader* const xmlreader) + MusicXmlLogger* logger, const XmlStreamReader* const xmlreader, + const String& accidAbove = {}, const String& accidBelow = {}, + const String& accidAboveSmufl = {}, const String& accidBelowSmufl = {}) { if (!wavyLineType.empty()) { const Fraction ticks = cr->ticks(); @@ -9280,6 +9329,22 @@ static void addWavyLine(ChordRest* cr, const Fraction& tick, trill->setOrnament(Factory::createOrnament(cr)); trill->ornament()->setAnchor(ArticulationAnchor::AUTO); + Chord* chord = cr->isChord() ? toChord(cr) : nullptr; + Note* mainNote = chord ? chord->upNote() : nullptr; + + if (!accidAbove.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidAbove, accidAboveSmufl); + if (type != AccidentalType::NONE) { + setOrnamentIntervalFromAccidental(trill->ornament(), mainNote, type, true); + } + } + if (!accidBelow.empty()) { + const AccidentalType type = musicXmlString2accidentalType(accidBelow, accidBelowSmufl); + if (type != AccidentalType::NONE) { + setOrnamentIntervalFromAccidental(trill->ornament(), mainNote, type, false); + } + } + if (wavyLineType == u"start") { spanners[trill] = std::pair(tick.ticks(), -1); // LOGD("trill=%p inserted at first tick %d", trill, tick); @@ -9562,7 +9627,8 @@ void MusicXmlParserNotations::addToScore(ChordRest* const cr, Note* const note, DelayedArpMap& delayedArps) { addArpeggio(cr, m_arpeggioType, m_arpeggioNo, m_arpeggioColor, arpMap, delayedArps); - addWavyLine(cr, tick, m_wavyLineNo, m_wavyLineType, spanners, trills, m_logger, &m_e); + addWavyLine(cr, tick, m_wavyLineNo, m_wavyLineType, spanners, trills, m_logger, &m_e, + m_wavyLineAccidAbove, m_wavyLineAccidBelow, m_wavyLineAccidAboveSmufl, m_wavyLineAccidBelowSmufl); for (const Notation& notation : m_notations) { if (notation.symId() != SymId::noSym) { diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.h b/src/importexport/musicxml/internal/import/importmusicxmlpass2.h index 66d2e6df3e895..18d8aa1c549df 100644 --- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.h +++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.h @@ -394,6 +394,10 @@ class MusicXmlParserNotations engraving::Color m_tremoloColor; muse::String m_wavyLineType; int m_wavyLineNo = 0; + muse::String m_wavyLineAccidAbove; + muse::String m_wavyLineAccidBelow; + muse::String m_wavyLineAccidAboveSmufl; + muse::String m_wavyLineAccidBelowSmufl; muse::String m_arpeggioType; int m_arpeggioNo = 0; engraving::Color m_arpeggioColor;