Skip to content

Commit

Permalink
[MusicXML] Add full support for holes element
Browse files Browse the repository at this point in the history
Backport of musescore#25932
  • Loading branch information
rettinghaus authored and Jojo-Schmitz committed Dec 28, 2024
1 parent a904e30 commit d938cdc
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 4 deletions.
25 changes: 25 additions & 0 deletions importexport/musicxml/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3097,6 +3097,12 @@ static QString symIdToTechn(const SymId sid)
case SymId::brassHarmonMuteStemOpen:
return "harmon-mute";
break;
case SymId::windClosedHole:
case SymId::windHalfClosedHole1:
case SymId::windHalfClosedHole2:
case SymId::windHalfClosedHole3:
case SymId::windOpenHole:
return "hole";
case SymId::guitarGolpe:
return "golpe";
break;
Expand Down Expand Up @@ -3352,6 +3358,25 @@ void ExportMusicXml::chordAttributes(Chord* chord, Notations& notations, Technic
_xml.tag("harmon-closed" + location, harmonClosedValue);
_xml.etag();
}
else if (mxmlTechn.startsWith(u"hole")) {
_xml.stag(mxmlTechn);
QString location = {};
QString holeClosedValue;
switch (sid) {
case SymId::windClosedHole:
holeClosedValue = "yes";
break;
case SymId::windOpenHole:
holeClosedValue = "no";
break;
default:
holeClosedValue = "half";
location = QString(" location=\"%1\"").arg(sid == SymId::windHalfClosedHole1 ? "right" : "bottom");
break;
}
_xml.tag("hole-closed" + location, holeClosedValue);
_xml.etag();
}
else
_xml.tagE(mxmlTechn);
}
Expand Down
68 changes: 64 additions & 4 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,7 @@ static bool convertArticulationToSymId(const QString& mxmlName, SymId& id)
map["stopped"] = SymId::brassMuteClosed;
map["snap-pizzicato"] = SymId::pluckedSnapPizzicatoAbove;
map["heal"] = SymId::keyboardPedalHeel1 ;
map["toe"] = SymId::keyboardPedalToe1 ;
map["toe"] = SymId::keyboardPedalToe2 ;
map["fingernails"] = SymId::pluckedWithFingernails ;
map["brass-bend"] = SymId::brassBend ;
map["flip"] = SymId::brassFlip;
Expand Down Expand Up @@ -7600,6 +7600,17 @@ void MusicXMLParserNotations::articulations()
_notations.push_back(artic);
_e.skipCurrentElement(); // skip but don't log
}
else if (_e.name() == "other-articulation") {
const QString smufl = _e.attributes().value("smufl").toString();

if (!smufl.isEmpty()) {
SymId id = SymId::noSym;
Notation artic = Notation::notationWithAttributes(_e.name().toString(),
_e.attributes(), "articulations", id);
_notations.push_back(artic);
}
_e.skipCurrentElement(); // skip but don't log
}
else {
skipLogCurrElem();
}
Expand All @@ -7619,7 +7630,7 @@ void MusicXMLParserNotations::ornaments()
bool trillMark = false;
// <trill-mark placement="above"/>
while (_e.readNextStartElement()) {
SymId id { SymId::noSym };
SymId id = SymId::noSym;
if (convertArticulationToSymId(_e.name().toString(), id)) {
Notation notation = Notation::notationWithAttributes(_e.name().toString(),
_e.attributes(), "articulations", id);
Expand Down Expand Up @@ -7687,7 +7698,7 @@ void MusicXMLParserNotations::ornaments()
void MusicXMLParserNotations::technical()
{
while (_e.readNextStartElement()) {
SymId id { SymId::noSym };
SymId id = SymId::noSym;
if (convertArticulationToSymId(_e.name().toString(), id)) {
Notation notation = Notation::notationWithAttributes(_e.name().toString(),
_e.attributes(), "technical", id);
Expand All @@ -7704,6 +7715,8 @@ void MusicXMLParserNotations::technical()
harmonic();
else if (_e.name() == "harmon-mute")
harmonMute();
else if (_e.name() == "hole")
hole();
else if (_e.name() == "other-technical")
otherTechnical();
else
Expand All @@ -7714,7 +7727,18 @@ void MusicXMLParserNotations::technical()

void MusicXMLParserNotations::otherTechnical()
{
QString text = _e.readElementText();
const QString smufl = _e.attributes().value("smufl").toString();

if (!smufl.isEmpty()) {
SymId id = SymId::noSym;
Notation notation = Notation::notationWithAttributes(_e.name().toString(),
_e.attributes(), "technical", id);
_notations.push_back(notation);
_e.skipCurrentElement();
return;
}

const QString text = _e.readElementText();

if (text == "z") {
// Buzz roll
Expand Down Expand Up @@ -7789,6 +7813,42 @@ void MusicXMLParserNotations::harmonMute()
_notations.push_back(Notation::notationWithAttributes("harmon-closed", _e.attributes(), "technical", mute));
}

//---------------------------------------------------------
// hole
//---------------------------------------------------------

/**
Parse the /score-partwise/part/measure/note/notations/technical/hole node.
*/

void MusicXMLParserNotations::hole()
{
SymId hole = SymId::noSym;
while (_e.readNextStartElement()) {
if (_e.name() == "hole-closed") {
const QString location = _e.attributes().value("location").toString();
const QString value = _e.readElementText();
if (value == "yes")
hole = SymId::windClosedHole;
else if (value == "no")
hole = SymId::windOpenHole;
else if (value == "half") {
if (location == "bottom")
hole = SymId::windHalfClosedHole2;
else if (location == "right")
hole = SymId::windHalfClosedHole1;
else {
_logger->logError(QString("unsupported hole-closed location '%1'").arg(location), &_e);
hole = SymId::windHalfClosedHole3;
}
}
}
else
_e.skipCurrentElement();
}
_notations.push_back(Notation::notationWithAttributes("hole-closed", _e.attributes(), "technical", hole));
}

//---------------------------------------------------------
// 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 @@ -243,6 +243,7 @@ class MusicXMLParserNotations {
void addTechnical(const Notation& notation, Note* note);
void harmonic();
void harmonMute();
void hole();
void articulations();
void dynamics();
void fermata();
Expand Down
120 changes: 120 additions & 0 deletions mtest/musicxml/io/testHoles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?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>Holes 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>Flute</part-name>
<part-abbreviation>Fl.</part-abbreviation>
<score-instrument id="P1-I1">
<instrument-name>Flute</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>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>down</stem>
<notations>
<technical>
<hole>
<hole-closed>no</hole-closed>
</hole>
</technical>
</notations>
</note>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>down</stem>
<notations>
<technical>
<hole>
<hole-closed>yes</hole-closed>
</hole>
</technical>
</notations>
</note>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>down</stem>
<notations>
<technical>
<hole>
<hole-closed location="bottom">half</hole-closed>
</hole>
</technical>
</notations>
</note>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>down</stem>
<notations>
<technical>
<hole>
<hole-closed location="right">half</hole-closed>
</hole>
</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 @@ -164,6 +164,7 @@ private slots:
void hello() { mxmlIoTest("testHello"); }
void helloReadCompr() { mxmlReadTestCompr("testHello"); }
void helloReadWriteCompr() { mxmlReadWriteTestCompr("testHello"); }
void holes() { mxmlIoTest("testHoles"); }
void implicitMeasure1() { mxmlIoTest("testImplicitMeasure1"); }
void incompleteTuplet() { mxmlIoTestRef("testIncompleteTuplet"); }
void incorrectStaffNumber1() { mxmlIoTestRef("testIncorrectStaffNumber1"); }
Expand Down

0 comments on commit d938cdc

Please sign in to comment.