Skip to content

Commit

Permalink
[MusicXML] full support for Harmon mutes
Browse files Browse the repository at this point in the history
Backport of musescore#25888
  • Loading branch information
rettinghaus authored and Jojo-Schmitz committed Dec 20, 2024
1 parent c166903 commit 5aa7d46
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 8 deletions.
35 changes: 27 additions & 8 deletions importexport/musicxml/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3092,6 +3092,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:
Expand Down Expand Up @@ -3301,7 +3304,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";
}
Expand All @@ -3323,18 +3325,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);
}
}

Expand Down
38 changes: 38 additions & 0 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7694,6 +7694,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
Expand Down Expand Up @@ -7743,6 +7745,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(), "technical", mute));
}

//---------------------------------------------------------
// addTechnical
//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions importexport/musicxml/importmxmlpass2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
126 changes: 126 additions & 0 deletions mtest/musicxml/io/testHarmonMutes.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 4.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="4.0">
<work>
<work-title>harmon-mute test</work-title>
</work>
<identification>
<creator type="composer">Klaus Rettinghaus</creator>
<encoding>
<software>MuseScore 0.7.0</software>
<encoding-date>2007-09-10</encoding-date>
<supports element="accidental" type="yes"/>
<supports element="beam" type="yes"/>
<supports element="print" attribute="new-page" type="no"/>
<supports element="print" attribute="new-system" type="no"/>
<supports element="stem" type="yes"/>
</encoding>
</identification>
<part-list>
<score-part id="P1">
<part-name>Posaune</part-name>
<part-abbreviation>Pos.</part-abbreviation>
<score-instrument id="P1-I1">
<instrument-name>Posaune</instrument-name>
</score-instrument>
<midi-device id="P1-I1" port="1"></midi-device>
<midi-instrument id="P1-I1">
<midi-channel>1</midi-channel>
<midi-program>58</midi-program>
<volume>78.7402</volume>
<pan>0</pan>
</midi-instrument>
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>3</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>half</type>
<stem>up</stem>
<notations>
<technical>
<harmon-mute>
<harmon-closed>yes</harmon-closed>
</harmon-mute>
</technical>
</notations>
</note>
<note>
<pitch>
<step>C</step>
<octave>3</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>half</type>
<stem>up</stem>
<notations>
<technical>
<harmon-mute>
<harmon-closed>no</harmon-closed>
</harmon-mute>
</technical>
</notations>
</note>
</measure>
<measure number="2">
<note>
<pitch>
<step>C</step>
<octave>3</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>half</type>
<stem>up</stem>
<notations>
<technical>
<harmon-mute>
<harmon-closed location="left">half</harmon-closed>
</harmon-mute>
</technical>
</notations>
</note>
<note>
<pitch>
<step>C</step>
<octave>3</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>half</type>
<stem>up</stem>
<notations>
<technical>
<harmon-mute>
<harmon-closed location="right">half</harmon-closed>
</harmon-mute>
</technical>
</notations>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
</score-partwise>
1 change: 1 addition & 0 deletions mtest/musicxml/io/tst_mxml_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"); }
Expand Down

0 comments on commit 5aa7d46

Please sign in to comment.