diff --git a/src/importexport/musicxml/internal/export/exportmusicxml.cpp b/src/importexport/musicxml/internal/export/exportmusicxml.cpp
index 883509b694a94..156e6c1521575 100644
--- a/src/importexport/musicxml/internal/export/exportmusicxml.cpp
+++ b/src/importexport/musicxml/internal/export/exportmusicxml.cpp
@@ -1840,7 +1840,11 @@ void ExportMusicXml::barlineLeft(const Measure* const m, const track_idx_t track
ending(m_xml, volta, true);
}
if (rs) {
- m_xml.tag("repeat", { { "direction", "forward" } });
+ XmlWriter::Attributes attrs = { { "direction", "forward" } };
+ if (m_score->style().styleB(Sid::repeatBarTips)) {
+ attrs.push_back({ "winged", "curved" });
+ }
+ m_xml.tag("repeat", attrs);
}
m_xml.endElement();
}
@@ -2109,11 +2113,14 @@ void ExportMusicXml::barlineRight(const Measure* const m, const track_idx_t stra
}
if (bst == BarLineType::END_REPEAT || bst == BarLineType::END_START_REPEAT) {
+ XmlWriter::Attributes attrs = { { "direction", "backward" } };
if (m->repeatCount() > 2) {
- m_xml.tag("repeat", { { "direction", "backward" }, { "times", m->repeatCount() } });
- } else {
- m_xml.tag("repeat", { { "direction", "backward" } });
+ attrs.push_back({ "times", m->repeatCount() });
+ }
+ if (m_score->style().styleB(Sid::repeatBarTips)) {
+ attrs.push_back({ "winged", "curved" });
}
+ m_xml.tag("repeat", attrs);
}
m_xml.endElement();
diff --git a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp
index 406d1364f9755..0e68f6cd61da5 100644
--- a/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp
+++ b/src/importexport/musicxml/internal/import/importmusicxmlpass2.cpp
@@ -5743,18 +5743,21 @@ Regular barlines should not be added at the start or end of a measure, as that c
void MusicXmlParserPass2::barline(const String& partId, Measure* measure, const Fraction& tick)
{
- String loc = m_e.attribute("location");
+ AsciiStringView loc = m_e.asciiAttribute("location");
if (loc.empty()) {
- loc = u"right";
+ loc = "right";
}
// Place barline in correct place
Fraction locTick = tick;
- if (loc == u"left") {
+ if (loc == "left") {
locTick = measure->tick();
- } else if (loc == u"right") {
+ } else if (loc == "right") {
locTick = measure->endTick();
}
+ const String codaLabel = m_e.attribute("coda");
+ const String segnoLabel = m_e.attribute("segno");
+
String barStyle;
Color barlineColor;
String endingNumber;
@@ -5762,23 +5765,68 @@ void MusicXmlParserPass2::barline(const String& partId, Measure* measure, const
Color endingColor;
String endingText;
String repeat;
- String count;
bool printEnding = true;
while (m_e.readNextStartElement()) {
if (m_e.name() == "bar-style") {
barlineColor = Color::fromString(m_e.asciiAttribute("color").ascii());
barStyle = m_e.readText();
- } else if (m_e.name() == "ending") {
- endingNumber = m_e.attribute("number");
- endingType = m_e.attribute("type");
- endingColor = Color::fromString(m_e.asciiAttribute("color").ascii());
- printEnding = m_e.asciiAttribute("print-object") != "no";
- endingText = m_e.readText();
+ } else if (m_e.name() == "segno") {
+ const Color segnoColor = Color::fromString(m_e.asciiAttribute("color").ascii());
+ const AsciiStringView segnoSymbol = m_e.asciiAttribute("smufl");
+ Measure* markedMeasure = (loc == "right") ? measure->nextMeasure() : measure;
+ if (markedMeasure == nullptr) {
+ m_logger->logError(u"coda or segno marker cannot be placed at the end of the score", &m_e);
+ m_e.skipCurrentElement();
+ continue;
+ }
+ Marker* m = Factory::createMarker(markedMeasure);
+ m->setMarkerType(MarkerType::SEGNO);
+ if (!segnoSymbol.empty()) {
+ m->setXmlText(u"" + String::fromAscii(segnoSymbol.ascii()) + u"");
+ }
+ if (!segnoLabel.empty()) {
+ m->setLabel(segnoLabel);
+ }
+ if (segnoColor.isValid()) {
+ colorItem(m, segnoColor);
+ }
+ const track_idx_t track = m_pass1.trackForPart(partId);
+ addElemOffset(m, track, u"above", markedMeasure, markedMeasure->tick());
+ m_e.skipCurrentElement();
+ } else if (m_e.name() == "coda") {
+ const Color codaColor = Color::fromString(m_e.asciiAttribute("color").ascii());
+ const AsciiStringView codaSymbol = m_e.asciiAttribute("smufl");
+ Measure* markedMeasure = (loc == "right") ? measure->nextMeasure() : measure;
+ if (markedMeasure == nullptr) {
+ m_logger->logError(u"coda or segno marker cannot be placed at the end of the score", &m_e);
+ m_e.skipCurrentElement();
+ continue;
+ }
+ Marker* m = Factory::createMarker(markedMeasure);
+ m->setMarkerType(MarkerType::CODA);
+ if (!codaSymbol.empty()) {
+ m->setXmlText(u"" + String::fromAscii(codaSymbol.ascii()) + u"");
+ }
+ if (!codaLabel.empty()) {
+ m->setLabel(codaLabel);
+ }
+ if (codaColor.isValid()) {
+ colorItem(m, codaColor);
+ }
+ const track_idx_t track = m_pass1.trackForPart(partId);
+ addElemOffset(m, track, u"above", markedMeasure, markedMeasure->tick());
+ m_e.skipCurrentElement();
} else if (m_e.name() == "fermata") {
const Color fermataColor = Color::fromString(m_e.asciiAttribute("color").ascii());
const String fermataType = m_e.attribute("type");
- Segment* const segment = measure->getSegment(SegmentType::EndBarLine, locTick);
+ SegmentType st = SegmentType::BarLine;
+ if (locTick == measure->endTick()) {
+ st = SegmentType::EndBarLine;
+ } else if (locTick == measure->tick()) {
+ st = SegmentType::BeginBarLine;
+ }
+ Segment* const segment = measure->getSegment(st, locTick);
const track_idx_t track = m_pass1.trackForPart(partId);
Fermata* fermata = Factory::createFermata(segment);
fermata->setSymId(convertFermataToSymId(m_e.readText()));
@@ -5795,13 +5843,21 @@ void MusicXmlParserPass2::barline(const String& partId, Measure* measure, const
// Terminate tempo lines
const InferredTempoLineStack& lines = getInferredTempoLine();
terminateInferredLine(std::vector(lines.begin(), lines.end()), locTick, track);
+ } else if (m_e.name() == "ending") {
+ endingNumber = m_e.attribute("number");
+ endingType = m_e.attribute("type");
+ endingColor = Color::fromString(m_e.asciiAttribute("color").ascii());
+ printEnding = m_e.asciiAttribute("print-object") != "no";
+ endingText = m_e.readText();
} else if (m_e.name() == "repeat") {
repeat = m_e.attribute("direction");
- count = m_e.attribute("times");
- if (count.empty()) {
- count = u"2";
+ int count = m_e.attribute("times").toInt();
+ if (!count) {
+ count = 2;
}
- measure->setRepeatCount(count.toInt());
+ measure->setRepeatCount(count);
+ bool repeatBarTips = !m_e.attribute("winged").empty() && m_e.attribute("winged") != "none";
+ m_score->undoChangeStyleVal(Sid::repeatBarTips, repeatBarTips);
m_e.skipCurrentElement();
} else {
skipLogCurrElem();
diff --git a/src/importexport/musicxml/tests/data/testBarlineTips.xml b/src/importexport/musicxml/tests/data/testBarlineTips.xml
new file mode 100644
index 0000000000000..89cc1011612f3
--- /dev/null
+++ b/src/importexport/musicxml/tests/data/testBarlineTips.xml
@@ -0,0 +1,197 @@
+
+
+
+
+ Repeats on wings
+
+
+
+ MuseScore 0.7.0
+ 2007-09-10
+
+
+
+
+
+
+
+
+
+ Piano
+
+ Piano
+
+
+
+ 1
+ 1
+ 78.7402
+ 0
+
+
+
+
+
+
+ 1
+
+ 0
+
+
+ 2
+
+ G
+ 2
+
+
+ F
+ 4
+
+
+
+
+ 4
+ 1
+ 1
+
+
+ 4
+
+
+
+ C
+ 3
+
+ 2
+ 5
+ half
+ up
+ 2
+
+
+
+ A
+ 3
+
+ 2
+ 5
+ half
+ down
+ 2
+
+
+
+
+ heavy-light
+
+
+
+
+ 4
+ 1
+ 1
+
+
+ 4
+
+
+
+ G
+ 3
+
+ 2
+ 5
+ half
+ down
+ 2
+
+
+
+ G
+ 2
+
+ 2
+ 5
+ half
+ up
+ 2
+
+
+
+
+
+ 4
+ 1
+ 1
+
+
+ 4
+
+
+
+ C
+ 3
+
+ 2
+ 5
+ half
+ up
+ 2
+
+
+
+ E
+ 3
+
+ 2
+ 5
+ half
+ down
+ 2
+
+
+ light-heavy
+
+
+
+
+
+
+ 4
+ 1
+ 1
+
+
+ 4
+
+
+
+ F
+ 3
+
+ 2
+ 5
+ half
+ down
+ 2
+
+
+
+ C
+ 3
+
+ 2
+ 5
+ half
+ up
+ 2
+
+
+ light-heavy
+
+
+
+
diff --git a/src/importexport/musicxml/tests/musicxml_tests.cpp b/src/importexport/musicxml/tests/musicxml_tests.cpp
index 6514490d2457a..6d8b6d1a45d53 100644
--- a/src/importexport/musicxml/tests/musicxml_tests.cpp
+++ b/src/importexport/musicxml/tests/musicxml_tests.cpp
@@ -396,6 +396,9 @@ TEST_F(MusicXml_Tests, articulationCombination) {
TEST_F(MusicXml_Tests, backupRoundingError) {
musicXmlImportTestRef("testBackupRoundingError");
}
+TEST_F(MusicXml_Tests, barlineFermatas) {
+ musicXmlIoTest("testBarlineFermatas");
+}
TEST_F(MusicXml_Tests, barlineLoc) {
musicXmlImportTestRef("testBarlineLoc");
}
@@ -405,8 +408,8 @@ TEST_F(MusicXml_Tests, noteflightStartRepeatBarline) {
TEST_F(MusicXml_Tests, barlineSpan) {
musicXmlIoTest("testBarlineSpan");
}
-TEST_F(MusicXml_Tests, barlineFermatas) {
- musicXmlIoTest("testBarlineFermatas");
+TEST_F(MusicXml_Tests, barlineTips) {
+ musicXmlIoTest("testBarlineTips");
}
TEST_F(MusicXml_Tests, barStyles) {
musicXmlIoTest("testBarStyles");