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");