diff --git a/importexport/musicxml/importmxmlpass2.cpp b/importexport/musicxml/importmxmlpass2.cpp index d9742f9d26ac8..f36bff921aa1c 100644 --- a/importexport/musicxml/importmxmlpass2.cpp +++ b/importexport/musicxml/importmxmlpass2.cpp @@ -31,6 +31,7 @@ #include "libmscore/chordlist.h" #include "libmscore/chordrest.h" #include "libmscore/drumset.h" +#include "libmscore/durationtype.h" #include "libmscore/dynamic.h" #include "libmscore/fermata.h" #include "libmscore/figuredbass.h" @@ -3275,7 +3276,7 @@ void MusicXMLParserDirection::direction(const QString& partId, else skipLogCurrElem(); } - + handleTempo(); handleRepeats(measure, track, tick + _offset); handleNmiCmi(measure, track, tick + _offset, delayedDirections); handleChordSym(track, tick + _offset, harmonyMap); @@ -4388,6 +4389,58 @@ void MusicXMLParserDirection::handleChordSym(const int track, const Fraction tic _wordsText.clear(); } +void MusicXMLParserDirection::handleTempo() + { + // Pick up any tempo markings which may have been exported from Sibelius as + // eg. andante (q = c. 90) + // Sibelius uses a symbol font with the characters 'yxeqhVwW' each drawn as a different duration + // which we need to map to SMuFL syms + QString plainWords = MScoreTextToMXML::toPlainText(_wordsText.simplified()); + + static const QRegExp tempo(".*([yxeqhVwW])(\\.?)\\s*=[^0-9]*([0-9]+).*"); +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + QStringList tempoMatches = plainWords.split(tempo, Qt::SkipEmptyParts); +#else + QStringList tempoMatches = plainWords.split(tempo, QString::SkipEmptyParts); +#endif + + // Not a tempo + if (tempoMatches.size() < 2) + return; + + const QString dur = tempoMatches.at(0); + const bool dot = tempoMatches.size() == 3; + const QString val = tempoMatches.at(dot ? 2 : 1); + + const QString dotStr = dot ? "spacemetAugmentationDot" : ""; + // Map Sibelius' representation of note types to their SMuFL counterparts and duration types + static const QMap > syms = { + { "y", { "metNote32ndUp", TDuration::DurationType::V_32ND } }, + { "x", { "metNote16thUp", TDuration::DurationType::V_16TH } }, + { "e", { "metNote8thUp", TDuration::DurationType::V_EIGHTH } }, + { "q", { "metNoteQuarterUp", TDuration::DurationType::V_QUARTER } }, + { "h", { "metNoteHalfUp", TDuration::DurationType::V_HALF } }, + { "w", { "metNoteWhole", TDuration::DurationType::V_WHOLE } }, + { "V", { "metNoteDoubleWholeSquare", TDuration::DurationType::V_BREVE } }, + { "W", { "metNoteDoubleWhole", TDuration::DurationType::V_BREVE } } + }; + + static const QRegExp replace("(.*)[yxeqhVwW]\\.?(\\s*=[^0-9]*[0-9]+.*)"); + const QString newStr = "$1" + syms[dur].first + dotStr + "$2"; + plainWords.replace(replace, newStr); + _wordsText = plainWords; + + if (!val.isEmpty() && !dur.isEmpty()) { + bool ok; + double d = val.toDouble(&ok); + TDuration duration = TDuration(syms[dur].second); + duration.setDots(dot); + + if (ok && duration.isValid()) // convert fraction to beats per minute + _tpoMetro = 4 * duration.fraction().numerator() * d / duration.fraction().denominator(); + } + } + //--------------------------------------------------------- // bracket //--------------------------------------------------------- diff --git a/importexport/musicxml/importmxmlpass2.h b/importexport/musicxml/importmxmlpass2.h index d3550a91175bf..b5031d28ae3ea 100644 --- a/importexport/musicxml/importmxmlpass2.h +++ b/importexport/musicxml/importmxmlpass2.h @@ -444,6 +444,7 @@ class MusicXMLParserDirection { void handleRepeats(Measure* measure, const int track, const Fraction tick); QString matchRepeat() const; void handleNmiCmi(Measure* measure, const int track, const Fraction tick, DelayedDirectionsList& delayedDirections); + void handleTempo(); void handleChordSym(const int track, const Fraction tick, HarmonyMap& harmonyMap); bool isLikelyFingering(const QString& fingeringStr) const; bool isLikelyCredit(const Fraction& tick) const; diff --git a/libmscore/tempotext.cpp b/libmscore/tempotext.cpp index efe0e23c36037..74bf20951fa8a 100644 --- a/libmscore/tempotext.cpp +++ b/libmscore/tempotext.cpp @@ -155,20 +155,20 @@ int TempoText::findTempoDuration(const QString& s, int& len, TDuration& dur) } static const TempoPattern tpSym[] = { - TempoPattern("metNoteQuarterUp\\s*metAugmentationDot\\s*metAugmentationDot", 1.75/60.0, TDuration::DurationType::V_QUARTER, 2), // double dotted 1/4 - TempoPattern("metNoteQuarterUp\\s*metAugmentationDot", 1.5/60.0, TDuration::DurationType::V_QUARTER, 1), // dotted 1/4 + TempoPattern("metNoteQuarterUpspacemetAugmentationDotspacemetAugmentationDot", 1.75/60.0, TDuration::DurationType::V_QUARTER, 2), // double dotted 1/4 + TempoPattern("metNoteQuarterUpspacemetAugmentationDot", 1.5/60.0, TDuration::DurationType::V_QUARTER, 1), // dotted 1/4 TempoPattern("metNoteQuarterUp", 1.0/60.0, TDuration::DurationType::V_QUARTER), // 1/4 - TempoPattern("metNoteHalfUp\\s*metAugmentationDot\\s*metAugmentationDot", 1.75/30.0, TDuration::DurationType::V_HALF, 2), // double dotted 1/2 - TempoPattern("metNoteHalfUp\\s*metAugmentationDot", 1.5/30.0, TDuration::DurationType::V_HALF, 1), // dotted 1/2 + TempoPattern("metNoteHalfUpspacemetAugmentationDotspacemetAugmentationDot", 1.75/30.0, TDuration::DurationType::V_HALF, 2), // double dotted 1/2 + TempoPattern("metNoteHalfUpspacemetAugmentationDot", 1.5/30.0, TDuration::DurationType::V_HALF, 1), // dotted 1/2 TempoPattern("metNoteHalfUp", 1.0/30.0, TDuration::DurationType::V_HALF), // 1/2 - TempoPattern("metNote8thUp\\s*metAugmentationDot\\s*metAugmentationDot", 1.75/120.0, TDuration::DurationType::V_EIGHTH, 2), // double dotted 1/8 - TempoPattern("metNote8thUp\\s*metAugmentationDot", 1.5/120.0, TDuration::DurationType::V_EIGHTH, 1), // dotted 1/8 + TempoPattern("metNote8thUpspacemetAugmentationDotspacemetAugmentationDot", 1.75/120.0, TDuration::DurationType::V_EIGHTH, 2), // double dotted 1/8 + TempoPattern("metNote8thUpspacemetAugmentationDot", 1.5/120.0, TDuration::DurationType::V_EIGHTH, 1), // dotted 1/8 TempoPattern("metNote8thUp", 1.0/120.0, TDuration::DurationType::V_EIGHTH), // 1/8 - TempoPattern("metNoteWhole\\s*metAugmentationDot", 1.5/15.0, TDuration::DurationType::V_WHOLE, 1), // dotted whole + TempoPattern("metNoteWholespacemetAugmentationDot", 1.5/15.0, TDuration::DurationType::V_WHOLE, 1), // dotted whole TempoPattern("metNoteWhole", 1.0/15.0, TDuration::DurationType::V_WHOLE), // whole - TempoPattern("metNote16thUp\\s*metAugmentationDot", 1.5/240.0, TDuration::DurationType::V_16TH, 1), // dotted 1/16 + TempoPattern("metNote16thUpspacemetAugmentationDot", 1.5/240.0, TDuration::DurationType::V_16TH, 1), // dotted 1/16 TempoPattern("metNote16thUp", 1.0/240.0, TDuration::DurationType::V_16TH), // 1/16 - TempoPattern("metNote32ndUp\\s*metAugmentationDot", 1.5/480.0, TDuration::DurationType::V_32ND, 1), // dotted 1/32 + TempoPattern("metNote32ndUpspacemetAugmentationDot", 1.5/480.0, TDuration::DurationType::V_32ND, 1), // dotted 1/32 TempoPattern("metNote32ndUp", 1.0/480.0, TDuration::DurationType::V_32ND), // 1/32 TempoPattern("metNoteDoubleWholeSquare", 1.0/7.5, TDuration::DurationType::V_BREVE), // longa TempoPattern("metNoteDoubleWhole", 1.0/7.5, TDuration::DurationType::V_BREVE), // double whole @@ -206,7 +206,6 @@ QString TempoText::duration2tempoTextString(const TDuration dur) for (const TempoPattern& pa : tpSym) { if (pa.d == dur) { QString res = pa.pattern; - res.replace("\\s*", " "); return res; } } diff --git a/mtest/musicxml/io/testSibMetronomeMarks.xml b/mtest/musicxml/io/testSibMetronomeMarks.xml new file mode 100644 index 0000000000000..101cfc7fbfc2b Binary files /dev/null and b/mtest/musicxml/io/testSibMetronomeMarks.xml differ diff --git a/mtest/musicxml/io/testSibMetronomeMarks_ref.mscx b/mtest/musicxml/io/testSibMetronomeMarks_ref.mscx new file mode 100644 index 0000000000000..4b988bfb653b7 --- /dev/null +++ b/mtest/musicxml/io/testSibMetronomeMarks_ref.mscx @@ -0,0 +1,317 @@ + + + + + 0 + 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 + + + + + G + G + + + 4 + 4 + + + 0.666667 + 1 + Lingering metNoteQuarterUp = c. 40 + + + measure + 1/1 + + + + + + line + + + + 1.95 + 1 + metNoteQuarterUpspacemetAugmentationDot = c. 78 + + + measure + 1/1 + + + + + + + 1.5 + 1 + Andante (metNoteQuarterUp = c. 90) + + + measure + 1/1 + + + + + + line + + + + 1.333333 + 1 + Leggero (metNoteQuarterUp = c. 80) + + + measure + 1/1 + + + + + + + 0.24375 + 1 + metNote32ndUpspacemetAugmentationDot = c. 78 + + + measure + 1/1 + + + + + + + 0.325 + 1 + metNote16thUp = c. 78 + + + measure + 1/1 + + + + + + + 0.975 + 1 + metNote8thUpspacemetAugmentationDot = c. 78 + + + measure + 1/1 + + + + + + + 2.6 + 1 + metNoteHalfUp = c. 78 + + + measure + 1/1 + + + + + + + 15.6 + 1 + metNoteDoubleWholeSquarespacemetAugmentationDot = c. 78 + + + measure + 1/1 + + + + + + + 5.2 + 1 + metNoteWhole = c. 78 + + + measure + 1/1 + + + + + + + 15.6 + 1 + metNoteDoubleWholespacemetAugmentationDot = c. 78 + + + measure + 1/1 + + + end + + + + + + diff --git a/mtest/musicxml/io/tst_mxml_io.cpp b/mtest/musicxml/io/tst_mxml_io.cpp index 4e38bbfc4f545..495d75acfab8e 100644 --- a/mtest/musicxml/io/tst_mxml_io.cpp +++ b/mtest/musicxml/io/tst_mxml_io.cpp @@ -263,6 +263,7 @@ private slots: void restsNoType() { mxmlIoTestRef("testRestsNoType"); } void restsTypeWhole() { mxmlIoTestRef("testRestsTypeWhole"); } void secondVoiceMelismata() { mxmlImportTestRef("testSecondVoiceMelismata"); } + void sibMetronomeMarks() { mxmlImportTestRef("testSibMetronomeMarks"); } void sibOttavas() { mxmlImportTestRef("testSibOttavas"); } void slurs() { mxmlIoTest("testSlurs"); } void slurs2() { mxmlIoTest("testSlurs2"); }