Skip to content

Commit

Permalink
Fix badly exported metronome marks from Sibelius on XML import
Browse files Browse the repository at this point in the history
Backport of musescore#21587
  • Loading branch information
miiizen authored and Jojo-Schmitz committed Aug 20, 2024
1 parent 972dbe2 commit 355b917
Show file tree
Hide file tree
Showing 6 changed files with 382 additions and 11 deletions.
55 changes: 54 additions & 1 deletion importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 <words>
// 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 ? "<sym>space</sym><sym>metAugmentationDot</sym>" : "";
// Map Sibelius' representation of note types to their SMuFL counterparts and duration types
static const QMap<QString, QPair<QString, TDuration::DurationType> > syms = {
{ "y", { "<sym>metNote32ndUp</sym>", TDuration::DurationType::V_32ND } },
{ "x", { "<sym>metNote16thUp</sym>", TDuration::DurationType::V_16TH } },
{ "e", { "<sym>metNote8thUp</sym>", TDuration::DurationType::V_EIGHTH } },
{ "q", { "<sym>metNoteQuarterUp</sym>", TDuration::DurationType::V_QUARTER } },
{ "h", { "<sym>metNoteHalfUp</sym>", TDuration::DurationType::V_HALF } },
{ "w", { "<sym>metNoteWhole</sym>", TDuration::DurationType::V_WHOLE } },
{ "V", { "<sym>metNoteDoubleWholeSquare</sym>", TDuration::DurationType::V_BREVE } },
{ "W", { "<sym>metNoteDoubleWhole</sym>", 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
//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions importexport/musicxml/importmxmlpass2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 9 additions & 10 deletions libmscore/tempotext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,20 @@ int TempoText::findTempoDuration(const QString& s, int& len, TDuration& dur)
}

static const TempoPattern tpSym[] = {
TempoPattern("<sym>metNoteQuarterUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>", 1.75/60.0, TDuration::DurationType::V_QUARTER, 2), // double dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/60.0, TDuration::DurationType::V_QUARTER, 1), // dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.75/60.0, TDuration::DurationType::V_QUARTER, 2), // double dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/60.0, TDuration::DurationType::V_QUARTER, 1), // dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym>", 1.0/60.0, TDuration::DurationType::V_QUARTER), // 1/4
TempoPattern("<sym>metNoteHalfUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>", 1.75/30.0, TDuration::DurationType::V_HALF, 2), // double dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/30.0, TDuration::DurationType::V_HALF, 1), // dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.75/30.0, TDuration::DurationType::V_HALF, 2), // double dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/30.0, TDuration::DurationType::V_HALF, 1), // dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym>", 1.0/30.0, TDuration::DurationType::V_HALF), // 1/2
TempoPattern("<sym>metNote8thUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>", 1.75/120.0, TDuration::DurationType::V_EIGHTH, 2), // double dotted 1/8
TempoPattern("<sym>metNote8thUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/120.0, TDuration::DurationType::V_EIGHTH, 1), // dotted 1/8
TempoPattern("<sym>metNote8thUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.75/120.0, TDuration::DurationType::V_EIGHTH, 2), // double dotted 1/8
TempoPattern("<sym>metNote8thUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/120.0, TDuration::DurationType::V_EIGHTH, 1), // dotted 1/8
TempoPattern("<sym>metNote8thUp</sym>", 1.0/120.0, TDuration::DurationType::V_EIGHTH), // 1/8
TempoPattern("<sym>metNoteWhole</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/15.0, TDuration::DurationType::V_WHOLE, 1), // dotted whole
TempoPattern("<sym>metNoteWhole</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/15.0, TDuration::DurationType::V_WHOLE, 1), // dotted whole
TempoPattern("<sym>metNoteWhole</sym>", 1.0/15.0, TDuration::DurationType::V_WHOLE), // whole
TempoPattern("<sym>metNote16thUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/240.0, TDuration::DurationType::V_16TH, 1), // dotted 1/16
TempoPattern("<sym>metNote16thUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/240.0, TDuration::DurationType::V_16TH, 1), // dotted 1/16
TempoPattern("<sym>metNote16thUp</sym>", 1.0/240.0, TDuration::DurationType::V_16TH), // 1/16
TempoPattern("<sym>metNote32ndUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5/480.0, TDuration::DurationType::V_32ND, 1), // dotted 1/32
TempoPattern("<sym>metNote32ndUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5/480.0, TDuration::DurationType::V_32ND, 1), // dotted 1/32
TempoPattern("<sym>metNote32ndUp</sym>", 1.0/480.0, TDuration::DurationType::V_32ND), // 1/32
TempoPattern("<sym>metNoteDoubleWholeSquare</sym>", 1.0/7.5, TDuration::DurationType::V_BREVE), // longa
TempoPattern("<sym>metNoteDoubleWhole</sym>", 1.0/7.5, TDuration::DurationType::V_BREVE), // double whole
Expand Down Expand Up @@ -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;
}
}
Expand Down
Binary file added mtest/musicxml/io/testSibMetronomeMarks.xml
Binary file not shown.
Loading

0 comments on commit 355b917

Please sign in to comment.