From 371bb539290067c77df05e2a2b915181342c05ca Mon Sep 17 00:00:00 2001 From: rettinghaus Date: Thu, 19 Dec 2024 15:57:02 +0100 Subject: [PATCH] [MusicXML] full support for Harmon mutes Backport of #25888 --- importexport/musicxml/exportxml.cpp | 35 +++-- importexport/musicxml/importmxmlpass2.cpp | 38 ++++++ importexport/musicxml/importmxmlpass2.h | 1 + mtest/musicxml/io/testHarmonMutes.xml | 126 ++++++++++++++++++ .../musicxml/io/testNoteAttributes2_ref.mscx | 9 ++ mtest/musicxml/io/tst_mxml_io.cpp | 1 + 6 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 mtest/musicxml/io/testHarmonMutes.xml diff --git a/importexport/musicxml/exportxml.cpp b/importexport/musicxml/exportxml.cpp index d19bc42c1ac2b..6aba03bc05d11 100644 --- a/importexport/musicxml/exportxml.cpp +++ b/importexport/musicxml/exportxml.cpp @@ -3084,6 +3084,9 @@ static QString symIdToTechn(const SymId sid) return "half-muted"; break; case SymId::brassHarmonMuteClosed: + case SymId::brassHarmonMuteStemHalfLeft: + case SymId::brassHarmonMuteStemHalfRight: + case SymId::brassHarmonMuteStemOpen: return "harmon-mute"; break; case SymId::guitarGolpe: @@ -3292,7 +3295,6 @@ void ExportMusicXml::chordAttributes(Chord* chord, Notations& notations, Technic QString placement; QString direction; - QString attr; if (!a->isStyled(Pid::ARTICULATION_ANCHOR) && a->anchor() != ArticulationAnchor::CHORD) { placement = (a->anchor() == ArticulationAnchor::BOTTOM_STAFF || a->anchor() == ArticulationAnchor::BOTTOM_CHORD) ? "below" : "above"; } @@ -3314,18 +3316,35 @@ void ExportMusicXml::chordAttributes(Chord* chord, Notations& notations, Technic technical.tag(_xml); mxmlTechn += color2xml(a); mxmlTechn += positioningAttributes(a); + if (!placement.isEmpty()) + mxmlTechn += QString(" placement=\"%1\"").arg(placement); if (sid == SymId::stringsHarmonic) { - if (!placement.isEmpty()) - attr += QString(" placement=\"%1\"").arg(placement); - _xml.stag(mxmlTechn + attr); + _xml.stag(mxmlTechn); _xml.tagE("natural"); _xml.etag(); } - else { - if (!placement.isEmpty()) - attr += QString(" placement=\"%1\"").arg(placement); - _xml.tagE(mxmlTechn + attr); + else if (mxmlTechn.startsWith("harmon")) { + _xml.stag(mxmlTechn); + QString location = {}; + QString harmonClosedValue; + switch (sid) + { + case SymId::brassHarmonMuteClosed: + harmonClosedValue = "yes"; + break; + case SymId::brassHarmonMuteStemOpen: + harmonClosedValue = "no"; + break; + default: + harmonClosedValue = "half"; + location = QString(" location=\"%1\"").arg(sid == SymId::brassHarmonMuteStemHalfLeft ? "left" : "right"); + break; + } + _xml.tag("harmon-closed" + location, harmonClosedValue); + _xml.etag(); } + else + _xml.tagE(mxmlTechn); } } diff --git a/importexport/musicxml/importmxmlpass2.cpp b/importexport/musicxml/importmxmlpass2.cpp index cce57db4a860f..38ac1aae87c11 100644 --- a/importexport/musicxml/importmxmlpass2.cpp +++ b/importexport/musicxml/importmxmlpass2.cpp @@ -7675,6 +7675,8 @@ void MusicXMLParserNotations::technical() } else if (_e.name() == "harmonic") harmonic(); + else if (_e.name() == "harmon-mute") + harmonMute(); else if (_e.name() == "other-technical") otherTechnical(); else @@ -7724,6 +7726,42 @@ void MusicXMLParserNotations::harmonic() } } +//--------------------------------------------------------- +// harmonMute +//--------------------------------------------------------- + +/** + Parse the /score-partwise/part/measure/note/notations/technical/harmon-mute node. + */ + +void MusicXMLParserNotations::harmonMute() + { + SymId mute = SymId::brassHarmonMuteClosed; + while (_e.readNextStartElement()) { + QString name = _e.name().toString(); + if (name == "harmon-closed") { + const QString location = _e.attributes().value("location").toString(); + QString value = _e.readElementText(); + if (value == "yes") + mute = SymId::brassHarmonMuteClosed; + else if (value == "no") + mute = SymId::brassHarmonMuteStemOpen; + else if (value == "half") { + if (location == "left") + mute = SymId::brassHarmonMuteStemHalfLeft; + else if (location == "right") + mute = SymId::brassHarmonMuteStemHalfRight; + else { + _logger->logError(QString("unsupported harmon-closed location '%1'").arg(location), &_e); + mute = SymId::brassHarmonMuteStemHalfLeft; + } + } + } else + _e.skipCurrentElement(); + } + _notations.push_back(Notation::notationWithAttributes("harmon-closed", _e.attributes(), "articulations", mute)); + } + //--------------------------------------------------------- // addTechnical //--------------------------------------------------------- diff --git a/importexport/musicxml/importmxmlpass2.h b/importexport/musicxml/importmxmlpass2.h index d9d2ff1214ff4..d0c6707b8679d 100644 --- a/importexport/musicxml/importmxmlpass2.h +++ b/importexport/musicxml/importmxmlpass2.h @@ -242,6 +242,7 @@ class MusicXMLParserNotations { void addNotation(const Notation& notation, ChordRest* const cr, Note* const note); void addTechnical(const Notation& notation, Note* note); void harmonic(); + void harmonMute(); void articulations(); void dynamics(); void fermata(); diff --git a/mtest/musicxml/io/testHarmonMutes.xml b/mtest/musicxml/io/testHarmonMutes.xml new file mode 100644 index 0000000000000..67568f3319a70 --- /dev/null +++ b/mtest/musicxml/io/testHarmonMutes.xml @@ -0,0 +1,126 @@ + + + + + harmon-mute test + + + Klaus Rettinghaus + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Posaune + Pos. + + Posaune + + + + 1 + 58 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + + F + 4 + + + + + C + 3 + + 2 + 1 + half + up + + + + yes + + + + + + + C + 3 + + 2 + 1 + half + up + + + + no + + + + + + + + + C + 3 + + 2 + 1 + half + up + + + + half + + + + + + + C + 3 + + 2 + 1 + half + up + + + + half + + + + + + light-heavy + + + + diff --git a/mtest/musicxml/io/testNoteAttributes2_ref.mscx b/mtest/musicxml/io/testNoteAttributes2_ref.mscx index e832a290f9f5a..e063d0d57441a 100644 --- a/mtest/musicxml/io/testNoteAttributes2_ref.mscx +++ b/mtest/musicxml/io/testNoteAttributes2_ref.mscx @@ -369,6 +369,9 @@ quarter + + breathMarkComma + down 74 @@ -380,6 +383,9 @@ quarter + + breathMarkComma + down 76 @@ -531,6 +537,9 @@ quarter + + caesura + up 69 diff --git a/mtest/musicxml/io/tst_mxml_io.cpp b/mtest/musicxml/io/tst_mxml_io.cpp index b08b51d6715df..67142aa801c46 100644 --- a/mtest/musicxml/io/tst_mxml_io.cpp +++ b/mtest/musicxml/io/tst_mxml_io.cpp @@ -160,6 +160,7 @@ private slots: void harmony7() { mxmlMscxExportTestRef("testHarmony7"); } void harmony8() { mxmlIoTest("testHarmony8"); } void harmony9() { mxmlIoTest("testHarmony9"); } + void harmonMutes() { mxmlIoTest("testharmonMutes"); } void hello() { mxmlIoTest("testHello"); } void helloReadCompr() { mxmlReadTestCompr("testHello"); } void helloReadWriteCompr() { mxmlReadWriteTestCompr("testHello"); }