diff --git a/src/importexport/musicxml/internal/musicxml/exportxml.cpp b/src/importexport/musicxml/internal/musicxml/exportxml.cpp index 480cb00500f1b..aeb4eea02532f 100644 --- a/src/importexport/musicxml/internal/musicxml/exportxml.cpp +++ b/src/importexport/musicxml/internal/musicxml/exportxml.cpp @@ -374,6 +374,7 @@ class ExportMusicXml : public muse::Injectable void write(muse::io::IODevice* dev); void credits(XmlWriter& xml); void moveToTick(const Fraction& t); + void moveToTickIfNeed(const Fraction& t); void words(TextBase const* const text, staff_idx_t staff); void tboxTextAsWords(TextBase const* const text, const staff_idx_t staff, PointF position); void rehearsal(RehearsalMark const* const rmk, staff_idx_t staff); @@ -2167,6 +2168,14 @@ void ExportMusicXml::moveToTick(const Fraction& t) m_tick = t; } +void ExportMusicXml::moveToTickIfNeed(const Fraction& t) +{ + if (m_tick != t) { + m_attr.doAttr(m_xml, false); + moveToTick(t); + } +} + //--------------------------------------------------------- // timesig //--------------------------------------------------------- @@ -5314,6 +5323,9 @@ void ExportMusicXml::hairpin(Hairpin const* const hp, staff_idx_t staff, const F if ((isStart && hp->beginText().isEmpty()) || (!isStart && hp->endText().isEmpty())) { return; } + // generate backup or forward to the start time of the element + const Fraction tickToWrite = isStart ? hp->tick() : hp->tick2(); + moveToTickIfNeed(tickToWrite); directionTag(m_xml, m_attr, hp); writeHairpinText(m_xml, hp, isStart); directionETag(m_xml, staff); @@ -5346,6 +5358,10 @@ void ExportMusicXml::hairpin(Hairpin const* const hp, staff_idx_t staff, const F } } + // generate backup or forward to the start time of the element + const Fraction tickToWrite = isStart ? hp->tick() : hp->tick2(); + moveToTickIfNeed(tickToWrite); + directionTag(m_xml, m_attr, hp); if (isStart) { writeHairpinText(m_xml, hp, isStart); @@ -5420,6 +5436,7 @@ int ExportMusicXml::findOttava(const Ottava* ot) const void ExportMusicXml::ottava(Ottava const* const ot, staff_idx_t staff, const Fraction& tick) { int n = findOttava(ot); + bool isStart = ot->tick() == tick; if (n >= 0) { m_ottavas[n] = 0; } else { @@ -5471,6 +5488,10 @@ void ExportMusicXml::ottava(Ottava const* const ot, staff_idx_t staff, const Fra } if (!octaveShiftXml.empty()) { + // generate backup or forward to the start time of the element + const Fraction tickToWrite = isStart ? ot->tick() : ot->tick2(); + moveToTickIfNeed(tickToWrite); + directionTag(m_xml, m_attr, ot); m_xml.startElement("direction-type"); octaveShiftXml += color2xml(ot); @@ -5491,6 +5512,11 @@ void ExportMusicXml::pedal(Pedal const* const pd, staff_idx_t staff, const Fract if (pd->tick() != tick && pd->endHookType() == HookType::HOOK_45) { return; } + bool isStart = pd->tick() == tick; + + // generate backup or forward to the start time of the element + const Fraction tickToWrite = isStart ? pd->tick() : pd->tick2(); + moveToTickIfNeed(tickToWrite); directionTag(m_xml, m_attr, pd); m_xml.startElement("direction-type"); @@ -5660,6 +5686,10 @@ void ExportMusicXml::textLine(TextLineBase const* const tl, staff_idx_t staff, c rest += color2xml(tl); rest += positioningAttributes(tl, tl->tick() == tick); + // generate backup or forward to the start time of the element + const Fraction tickToWrite = isStart ? tl->tick() : tl->tick2(); + moveToTickIfNeed(tickToWrite); + directionTag(m_xml, m_attr, tl); if (!tl->beginText().isEmpty() && tl->tick() == tick) { @@ -6123,7 +6153,7 @@ static void directionMarker(XmlWriter& xml, const Marker* const m, const std::ve static track_idx_t findTrackForAnnotations(track_idx_t track, Segment* seg) { - if (seg->segmentType() != SegmentType::ChordRest) { + if (!(seg->isChordRestType() || seg->isTimeTickType())) { return muse::nidx; } @@ -6688,7 +6718,7 @@ static void figuredBass(XmlWriter& xml, track_idx_t strack, track_idx_t etrack, static void spannerStart(ExportMusicXml* exp, track_idx_t strack, track_idx_t etrack, track_idx_t track, staff_idx_t sstaff, Segment* seg) { - if (seg->segmentType() == SegmentType::ChordRest) { + if (seg->isChordRestType() || seg->isTimeTickType()) { Fraction stick = seg->tick(); for (auto it = exp->score()->spanner().lower_bound(stick.ticks()); it != exp->score()->spanner().upper_bound(stick.ticks()); ++it) { Spanner* e = it->second; @@ -7985,6 +8015,18 @@ void ExportMusicXml::writeMeasureTracks(const Measure* const m, for (track_idx_t track = strack; track < etrack; ++track) { for (Segment* seg = m->first(); seg; seg = seg->next()) { if (seg->isTimeTickType()) { + // Prefer to start/stop spanners on a chordrest segment where one is available + const Segment* crSeg = m_score->tick2leftSegment(seg->tick()); + if (crSeg && crSeg->tick() == seg->tick()) { + continue; + } + spannerStart(this, strack, etrack, track, partRelStaffNo, seg); + + const staff_idx_t spannerStaff = track2staff(track); + const track_idx_t starttrack = staff2track(spannerStaff); + const track_idx_t endtrack = staff2track(spannerStaff + 1); + spannerStop(this, starttrack, endtrack, seg->tick(), partRelStaffNo, spannersStopped); + continue; } EngravingItem* const el = seg->element(track); @@ -7997,10 +8039,7 @@ void ExportMusicXml::writeMeasureTracks(const Measure* const m, } // generate backup or forward to the start time of the element - if (m_tick != seg->tick()) { - m_attr.doAttr(m_xml, false); - moveToTick(seg->tick()); - } + moveToTickIfNeed(seg->tick()); // handle annotations and spanners (directions attached to this note or rest) if (el->isChordRest()) { diff --git a/src/importexport/musicxml/internal/musicxml/importmxmlpass1.cpp b/src/importexport/musicxml/internal/musicxml/importmxmlpass1.cpp index 87b0b89bf4b78..41febe37340ec 100644 --- a/src/importexport/musicxml/internal/musicxml/importmxmlpass1.cpp +++ b/src/importexport/musicxml/internal/musicxml/importmxmlpass1.cpp @@ -239,6 +239,23 @@ void MusicXMLParserPass1::addError(const String& error) } } +void MusicXMLParserPass1::setExporterSoftware(String& exporter) +{ + if (exporter.contains(u"sibelius")) { + if (exporter.contains(u"dolet 6")) { + m_exporterSoftware = MusicXMLExporterSoftware::DOLET6; + } else if (exporter.contains(u"dolet 8")) { + m_exporterSoftware = MusicXMLExporterSoftware::DOLET8; + } else { + m_exporterSoftware = MusicXMLExporterSoftware::SIBELIUS; + } + } else if (exporter.contains(u"finale")) { + m_exporterSoftware = MusicXMLExporterSoftware::FINALE; + } else if (exporter.contains(u"noteflight")) { + m_exporterSoftware = MusicXMLExporterSoftware::NOTEFLIGHT; + } +} + //--------------------------------------------------------- // initPartState //--------------------------------------------------------- @@ -951,7 +968,7 @@ void MusicXMLParserPass1::createMeasuresAndVboxes(Score* score, ++pageNr; if (pageNr == 1) { - vbox = addCreditWords(score, crWords, pageSize, true, m_exporterString.contains(u"sibelius")); + vbox = addCreditWords(score, crWords, pageSize, true, sibOrDolet()); if (i == 0 && vbox) { vbox->setExcludeFromOtherParts(false); } @@ -978,11 +995,21 @@ void MusicXMLParserPass1::createMeasuresAndVboxes(Score* score, // add a footer vbox if the next measure is on a new page or end of score has been reached if ((pageStartMeasureNrs.count(int(i + 1)) || i == (ml.size() - 1)) && pageNr == 1) { - addCreditWords(score, crWords, pageSize, false, m_exporterString.contains(u"sibelius")); + addCreditWords(score, crWords, pageSize, false, sibOrDolet()); } } } +bool MusicXMLParserPass1::sibOrDolet() const +{ + return m_exporterSoftware == MusicXMLExporterSoftware::SIBELIUS || dolet(); +} + +bool MusicXMLParserPass1::dolet() const +{ + return m_exporterSoftware == MusicXMLExporterSoftware::DOLET6 || m_exporterSoftware == MusicXMLExporterSoftware::DOLET8; +} + //--------------------------------------------------------- // determineMeasureStart //--------------------------------------------------------- @@ -1272,7 +1299,8 @@ void MusicXMLParserPass1::identification() // TODO while (m_e.readNextStartElement()) { if (m_e.name() == "software") { - m_exporterString += m_e.readText().toLower(); + String exporterString = m_e.readText().toLower(); + setExporterSoftware(exporterString); } else if (m_e.name() == "supports" && m_e.asciiAttribute("element") == "beam" && m_e.asciiAttribute("type") == "yes") { m_hasBeamingInfo = true; m_e.skipCurrentElement(); @@ -2248,7 +2276,7 @@ void MusicXMLParserPass1::scoreInstrument(const String& partId, const String& cu */ // Finale exports all instrument names as 'Grand Piano' - use part name - if (m_exporterString.contains(u"finale")) { + if (exporterSoftware() == MusicXMLExporterSoftware::FINALE) { instrName = m_parts[partId].getName(); if (instrName.size() <= 1) { instrName = curPartGroupName; diff --git a/src/importexport/musicxml/internal/musicxml/importmxmlpass1.h b/src/importexport/musicxml/internal/musicxml/importmxmlpass1.h index d039879cdee1a..a3f6465a7d4cf 100644 --- a/src/importexport/musicxml/internal/musicxml/importmxmlpass1.h +++ b/src/importexport/musicxml/internal/musicxml/importmxmlpass1.h @@ -90,6 +90,15 @@ enum class MxmlTupletFlag : char { STOP_CURRENT = 8 }; +enum class MusicXMLExporterSoftware : char { + SIBELIUS, + DOLET6, + DOLET8, + FINALE, + NOTEFLIGHT, + OTHER +}; + typedef muse::Flags MxmlTupletFlags; struct MxmlTupletState { @@ -195,21 +204,24 @@ class MusicXMLParserPass1 void insertAdjustedDuration(Fraction key, Fraction value) { m_adjustedDurations.insert({ key, value }); } std::map& adjustedDurations() { return m_adjustedDurations; } void insertSeenDenominator(int val) { m_seenDenominators.emplace(val); } - String exporterString() const { return m_exporterString; } + MusicXMLExporterSoftware exporterSoftware() const { return m_exporterSoftware; } + bool sibOrDolet() const; + bool dolet() const; private: // functions void addError(const String& error); // Add an error to be shown in the GUI + void setExporterSoftware(String& exporter); // generic pass 1 data muse::XmlStreamReader m_e; - String m_exporterString; // Name of the software which exported the file + MusicXMLExporterSoftware m_exporterSoftware = MusicXMLExporterSoftware::OTHER; // Software which exported the file int m_divs = 0; // Current MusicXML divisions value - std::map m_parts; // Parts data, mapped on part id + std::map m_parts; // Parts data, mapped on part id std::set m_systemStartMeasureNrs; // Measure numbers of measures starting a page std::set m_pageStartMeasureNrs; // Measure numbers of measures starting a page - std::vector m_measureLength; // Length of each measure - std::vector m_measureStart; // Start time of each measure + std::vector m_measureLength; // Length of each measure + std::vector m_measureStart; // Start time of each measure CreditWordsList m_credits; // All credits collected PartMap m_partMap; // TODO merge into MusicXmlPart ?? std::map m_instruments; // instruments for each part, mapped on part id diff --git a/src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp b/src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp index 4b566615b36fc..a15e72d65d618 100644 --- a/src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp +++ b/src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp @@ -2257,7 +2257,7 @@ void MusicXMLParserPass2::part() } if (!unendedTie->endNote()) { - cleanupUnterminatedTie(unendedTie, m_score, m_pass1.exporterString().contains(u"dolet 6")); + cleanupUnterminatedTie(unendedTie, m_score, m_pass1.exporterSoftware() == MusicXMLExporterSoftware::DOLET6); } } @@ -3276,7 +3276,7 @@ void MusicXMLParserDirection::direction(const String& partId, bool isVocalStaff = m_pass1.isVocalStaff(partId); bool isPercussionStaff = m_pass1.isPercussionStaff(partId); bool isExpressionText = false; - bool delayOttava = m_pass1.exporterString().contains(u"sibelius"); + bool delayOttava = m_pass1.exporterSoftware() == MusicXMLExporterSoftware::SIBELIUS; m_systemDirection = m_e.attribute("system") == "only-top"; //LOGD("direction track %d", track); std::vector starts; @@ -3583,19 +3583,23 @@ void MusicXMLParserDirection::direction(const String& partId, delete desc.sp; } else { if (spdesc.isStarted) { + // Adjustments to ottavas by the offset value are unwanted + const Fraction spTick = spdesc.sp && spdesc.sp->isOttava() ? tick : tick + m_offset; if (spdesc.sp && spdesc.sp->isOttava() && delayOttava) { // Sibelius writes ottava ends 1 note too early m_pass2.setDelayedOttava(spdesc.sp); m_pass2.delayedOttava()->setTrack2(m_track); - m_pass2.delayedOttava()->setTick2(tick + m_offset); + m_pass2.delayedOttava()->setTick2(spTick); + // need to set tick again later m_pass2.clearSpanner(desc); } else { - handleSpannerStop(spdesc.sp, m_track, tick + m_offset, spanners); + handleSpannerStop(spdesc.sp, m_track, spTick, spanners); m_pass2.clearSpanner(desc); } } else { spdesc.sp = desc.sp; - spdesc.tick2 = tick + m_offset; + const Fraction spTick = spdesc.sp && spdesc.sp->isOttava() ? tick : tick + m_offset; + spdesc.tick2 = spTick; spdesc.track2 = m_track; spdesc.isStopped = true; } @@ -3939,7 +3943,7 @@ void MusicXMLParserDirection::otherDirection() // TODO: Multiple sets of maps for exporters other than Dolet 6/Sibelius // TODO: Add more symbols from Sibelius std::map otherDirectionStrings; - if (m_pass1.exporterString().contains(u"dolet")) { + if (m_pass1.dolet()) { otherDirectionStrings = { { String(u"To Coda"), String(u"To Coda") }, { String(u"Segno"), String(u"segno") }, @@ -4177,7 +4181,7 @@ void MusicXMLParserDirection::textToDynamic(String& text) } String simplifiedText = MScoreTextToMXML::toPlainText(text).simplified(); // Correct finale's incorrect dynamic export - if (m_pass1.exporterString().contains(u"finale")) { + if (m_pass1.exporterSoftware() == MusicXMLExporterSoftware::FINALE) { static const std::map finaleDynamicSubs = { { u"π", u"pp" }, { u"P", u"mp" }, { u"F", u"mf" }, { u"ƒ", u"ff" }, { u"Ï", u"fff" }, { u"S", u"sf" }, { u"ß", u"sfz" }, @@ -4578,7 +4582,7 @@ void MusicXMLParserDirection::handleTempo(String& wordsString) }; MetronomeTextMap textMap; - if (m_pass1.exporterString().contains(u"sibelius")) { + if (m_pass1.sibOrDolet()) { textMap = sibeliusSyms; } else if (m_fontFamily == u"MetTimes Plain") { textMap = metTimesSyms; @@ -4885,19 +4889,20 @@ void MusicXMLParserDirection::octaveShift(const String& type, const int number, } else { Ottava* o = spdesc.isStopped ? toOttava(spdesc.sp) : Factory::createOttava(m_score->dummy()); - // if (placement.empty()) placement = "above"; // TODO ? set default - - if (type == u"down" && ottavasize == 8) { - o->setOttavaType(OttavaType::OTTAVA_8VA); - } - if (type == u"down" && ottavasize == 15) { - o->setOttavaType(OttavaType::OTTAVA_15MA); - } - if (type == u"up" && ottavasize == 8) { - o->setOttavaType(OttavaType::OTTAVA_8VB); - } - if (type == u"up" && ottavasize == 15) { - o->setOttavaType(OttavaType::OTTAVA_15MB); + if (type == u"down") { + m_placement = m_placement.empty() ? u"above" : m_placement; + if (ottavasize == 8) { + o->setOttavaType(OttavaType::OTTAVA_8VA); + } else if (ottavasize == 15) { + o->setOttavaType(OttavaType::OTTAVA_15MA); + } + } else if (type == u"up") { + m_placement = m_placement.empty() ? u"below" : m_placement; + if (ottavasize == 8) { + o->setOttavaType(OttavaType::OTTAVA_8VB); + } else if (ottavasize == 15) { + o->setOttavaType(OttavaType::OTTAVA_15MB); + } } const Color color = Color::fromString(m_e.asciiAttribute("color").ascii()); @@ -6613,7 +6618,7 @@ Note* MusicXMLParserPass2::note(const String& partId, String noteheadValue = m_e.readText(); if (noteheadValue == "none") { hasHead = false; - } else if (noteheadValue == "named" && m_pass1.exporterString().contains(u"noteflight")) { + } else if (noteheadValue == "named" && m_pass1.exporterSoftware() == MusicXMLExporterSoftware::NOTEFLIGHT) { headScheme = NoteHeadScheme::HEAD_PITCHNAME; } else { headGroup = convertNotehead(noteheadValue); @@ -7515,7 +7520,7 @@ void MusicXMLParserPass2::harmony(const String& partId, Measure* measure, const const HarmonyDesc newHarmonyDesc(track, ha, fd); bool insert = true; - if (m_pass1.exporterString().contains(u"dolet")) { + if (m_pass1.sibOrDolet()) { const int ticks = (sTime + offset).ticks(); for (auto itr = harmonyMap.begin(); itr != harmonyMap.end(); itr++) { if (itr->first != ticks) { diff --git a/src/importexport/musicxml/tests/data/testDoletOttavas.xml b/src/importexport/musicxml/tests/data/testDoletOttavas.xml new file mode 100644 index 0000000000000..9cb4976ee2d21 Binary files /dev/null and b/src/importexport/musicxml/tests/data/testDoletOttavas.xml differ diff --git a/src/importexport/musicxml/tests/data/testDoletOttavas_ref.mscx b/src/importexport/musicxml/tests/data/testDoletOttavas_ref.mscx new file mode 100644 index 0000000000000..92af5f061eb6c --- /dev/null +++ b/src/importexport/musicxml/tests/data/testDoletOttavas_ref.mscx @@ -0,0 +1,285 @@ + + + + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + stdNormal + + 3 + + [Unnamed (treble staff)] + + + 21 + 108 + 21 + 108 + keyboard.piano.grand + F + 0 + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 150 + 100 + + + 150 + 50 + + + 120 + 50 + + + 120 + 100 + + + + + + + + + + 10 + + + 5 + + + + + G + G + 1 + + + 4 + 4 + + + + 8va + + + + 1/2 + + + + + eighth + up + + 65 + 13 + + + + 1 + quarter + up + + 65 + 13 + + + + + + -1/2 + + + + + + 8vb + + + + 1 + + + + + half + up + + + + + + + 1 + -1/2 + + + + 65 + 13 + + + + + + + + quarter + up + + + + + -1 + 1/2 + + + + 65 + 13 + + + + quarter + up + + 65 + 13 + + + + + + -1 + + + + + half + + + end + + + + + + diff --git a/src/importexport/musicxml/tests/data/testSibOttavas.xml b/src/importexport/musicxml/tests/data/testSibOttavas.xml index 9cb4976ee2d21..2feec15ed9192 100644 Binary files a/src/importexport/musicxml/tests/data/testSibOttavas.xml and b/src/importexport/musicxml/tests/data/testSibOttavas.xml differ diff --git a/src/importexport/musicxml/tests/data/testSibOttavas_ref.mscx b/src/importexport/musicxml/tests/data/testSibOttavas_ref.mscx index 92af5f061eb6c..19a25ec046b74 100644 --- a/src/importexport/musicxml/tests/data/testSibOttavas_ref.mscx +++ b/src/importexport/musicxml/tests/data/testSibOttavas_ref.mscx @@ -3,82 +3,138 @@ 480 1 1 @@ -101,19 +157,13 @@ 3 - [Unnamed (treble staff)] + - 21 - 108 - 21 - 108 keyboard.piano.grand - F - 0 100 - 95 + 100 100 @@ -160,6 +210,9 @@ 10 + + page + 5 @@ -186,6 +239,7 @@ + no eighth up @@ -198,7 +252,7 @@ quarter up - 65 + 77 13 @@ -225,6 +279,7 @@ + down @@ -261,7 +316,7 @@ quarter up - 65 + 53 13 diff --git a/src/importexport/musicxml/tests/data/testTimeTickExport.mscx b/src/importexport/musicxml/tests/data/testTimeTickExport.mscx new file mode 100755 index 0000000000000..a491179edc22d --- /dev/null +++ b/src/importexport/musicxml/tests/data/testTimeTickExport.mscx @@ -0,0 +1,307 @@ + + + 4.5.0 + + + 480 + 1 + 1 + 1 + 0 + 1 + + + Composer / arranger + + 2024-10-02 + + + + Apple Macintosh + + + Subtitle + + + Untitled score + + Orchestra + + Keyboards + +
+ flutes + oboes + clarinets + saxophones + bassoons + +
+
+ horns + trumpets + cornets + flugelhorns + trombones + tubas + +
+
+ timpani +
+
+ keyboard-percussion + + drums + unpitched-metal-percussion + unpitched-wooden-percussion + other-percussion + +
+ keyboards + harps + organs + synths + + +
+ voices + voice-groups +
+
+ orchestral-strings +
+
+ + + + stdNormal + + + 1 + + + + stdNormal + + F + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + F + + + Fluid + + + + + + + + 0 + + + 4 + 4 + + + whole + + 67 + 15 + + + + -1/2 + 1 + + + + 0 + + + + 1 + + + + + + + + + + 8va + + + + 2 + + + + + whole + + 69 + 17 + + + + -1/2 + 1 + + + + + -1 + + + + + + + + + whole + + 71 + 19 + + + + -1/2 + 1 + + + + 1 + + + + 1 + + + + + + + + + + + -2 + + + + + whole + + 72 + 14 + + + + -1/2 + 1 + + + + + -1 + + + + + + + + + + + 0 + + + 4 + 4 + + + whole + + 43 + 15 + + + + + + + + whole + + 45 + 17 + + + + -3/4 + 1 + + + + 1 + + + + 1 + 1/4 + + + + + + + + + whole + + 47 + 19 + + + + -1/2 + 1 + + + + + -1 + -1/4 + + + + + + + + + whole + + 48 + 14 + + + + + +
+
diff --git a/src/importexport/musicxml/tests/data/testTimeTickExport_ref.xml b/src/importexport/musicxml/tests/data/testTimeTickExport_ref.xml new file mode 100644 index 0000000000000..2d497a9b41dec --- /dev/null +++ b/src/importexport/musicxml/tests/data/testTimeTickExport_ref.xml @@ -0,0 +1,243 @@ + + + + + Untitled score + + + Composer / arranger + + MuseScore 0.7.0 + 2007-09-10 + + + + + + + + + + Piano + Pno. + + Piano + + + + 1 + 1 + 78.7402 + 0 + + + + + + + 1 + + 0 + + + 2 + + G + 2 + + + F + 4 + + + + + G + 4 + + 4 + 1 + whole + 1 + + + 2 + + + + + + 1 + + + 2 + + + 4 + + + + G + 2 + + 4 + 5 + whole + 2 + + + + + + + + 1 + + + + A + 5 + + 4 + 1 + whole + 1 + + + 2 + + + + + + 1 + + + 2 + + + 4 + + + + A + 2 + + 4 + 5 + whole + 2 + + + 3 + + + + + + 2 + + + 3 + + + + + + B + 5 + + 4 + 1 + whole + 1 + + + + + + 1 + + + 2 + + + + + + 1 + + + 2 + + + 4 + + + + B + 2 + + 4 + 5 + whole + 2 + + + 2 + + + + + + 2 + + + 2 + + + + + + C + 5 + + 4 + 1 + whole + 1 + + + 2 + + + + + + 1 + + + 2 + + + 4 + + + + C + 3 + + 4 + 5 + whole + 2 + + + light-heavy + + + + diff --git a/src/importexport/musicxml/tests/data/testWedge5_ref.xml b/src/importexport/musicxml/tests/data/testWedge5_ref.xml index 5fd1bce464c5b..ea896b0bbd05d 100644 --- a/src/importexport/musicxml/tests/data/testWedge5_ref.xml +++ b/src/importexport/musicxml/tests/data/testWedge5_ref.xml @@ -78,6 +78,17 @@ + + 2 + + + + + + + + 2 + light-heavy diff --git a/src/importexport/musicxml/tests/musicxml_tests.cpp b/src/importexport/musicxml/tests/musicxml_tests.cpp index 3fabca71ea387..ce747f917e30f 100644 --- a/src/importexport/musicxml/tests/musicxml_tests.cpp +++ b/src/importexport/musicxml/tests/musicxml_tests.cpp @@ -550,6 +550,9 @@ TEST_F(Musicxml_Tests, divisionsDefinedTooLate2) { TEST_F(Musicxml_Tests, divisionsDuration) { mxmlIoTest("testDivisionsDuration"); } +TEST_F(Musicxml_Tests, doletOttavas) { + mxmlImportTestRef("testDoletOttavas"); +} TEST_F(Musicxml_Tests, doubleClefError) { mxmlIoTestRef("testDoubleClefError"); } @@ -1181,6 +1184,12 @@ TEST_F(Musicxml_Tests, timesig3) { TEST_F(Musicxml_Tests, timeTick) { mxmlImportTestRef("testTimeTick"); } +TEST_F(Musicxml_Tests, timeTickExport) { + bool use302 = MScore::useRead302InTestMode; + MScore::useRead302InTestMode = false; + mxmlMscxExportTestRef("testTimeTickExport"); + MScore::useRead302InTestMode = use302; +} TEST_F(Musicxml_Tests, titleSwapMu) { mxmlImportTestRef("testTitleSwapMu"); }