Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/engraving/dom/tempotext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,25 +169,26 @@ TDuration TempoText::duration() const
}

static const TempoPattern tpSym[] = {
TempoPattern("<sym>metNoteQuarterUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>",
TempoPattern("<sym>metNoteQuarterUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>metAugmentationDot</sym>",
1.75 / 60.0, DurationType::V_QUARTER, 2), // double dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 60.0, DurationType::V_QUARTER,
TempoPattern("<sym>metNoteQuarterUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 60.0, DurationType::V_QUARTER,
1), // dotted 1/4
TempoPattern("<sym>metNoteQuarterUp</sym>", 1.0 / 60.0, DurationType::V_QUARTER), // 1/4
TempoPattern("<sym>metNoteHalfUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>",
TempoPattern("<sym>metNoteHalfUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>metAugmentationDot</sym>",
1.75 / 30.0, DurationType::V_HALF, 2), // double dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 30.0, DurationType::V_HALF, 1), // dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 30.0, DurationType::V_HALF, 1), // dotted 1/2
TempoPattern("<sym>metNoteHalfUp</sym>", 1.0 / 30.0, DurationType::V_HALF), // 1/2
TempoPattern("<sym>metNote8thUp</sym>\\s*<sym>metAugmentationDot</sym>\\s*<sym>metAugmentationDot</sym>", 1.75 / 120.0,
TempoPattern("<sym>metNote8thUp</sym><sym>space</sym><sym>metAugmentationDot</sym><sym>metAugmentationDot</sym>", 1.75 / 120.0,
DurationType::V_EIGHTH, 2), // double dotted 1/8
TempoPattern("<sym>metNote8thUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 120.0, DurationType::V_EIGHTH,
TempoPattern("<sym>metNote8thUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 120.0, DurationType::V_EIGHTH,
1), // dotted 1/8
TempoPattern("<sym>metNote8thUp</sym>", 1.0 / 120.0, DurationType::V_EIGHTH), // 1/8
TempoPattern("<sym>metNoteWhole</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 15.0, DurationType::V_WHOLE, 1), // dotted whole
TempoPattern("<sym>metNoteWhole</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 15.0, DurationType::V_WHOLE,
1), // dotted whole
TempoPattern("<sym>metNoteWhole</sym>", 1.0 / 15.0, DurationType::V_WHOLE), // whole
TempoPattern("<sym>metNote16thUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 240.0, DurationType::V_16TH, 1), // dotted 1/16
TempoPattern("<sym>metNote16thUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 240.0, DurationType::V_16TH, 1), // dotted 1/16
TempoPattern("<sym>metNote16thUp</sym>", 1.0 / 240.0, DurationType::V_16TH), // 1/16
TempoPattern("<sym>metNote32ndUp</sym>\\s*<sym>metAugmentationDot</sym>", 1.5 / 480.0, DurationType::V_32ND, 1), // dotted 1/32
TempoPattern("<sym>metNote32ndUp</sym><sym>space</sym><sym>metAugmentationDot</sym>", 1.5 / 480.0, DurationType::V_32ND, 1), // dotted 1/32
TempoPattern("<sym>metNote32ndUp</sym>", 1.0 / 480.0, DurationType::V_32ND), // 1/32
TempoPattern("<sym>metNoteDoubleWholeSquare</sym>", 1.0 / 7.5, DurationType::V_BREVE), // longa
TempoPattern("<sym>metNoteDoubleWhole</sym>", 1.0 / 7.5, DurationType::V_BREVE), // double whole
Expand All @@ -208,7 +209,6 @@ String TempoText::duration2tempoTextString(const TDuration dur)
for (const TempoPattern& pa : tpSym) {
if (pa.d == dur) {
String res = String::fromUtf8(pa.pattern);
res.replace(u"\\s*", u" ");
return res;
}
}
Expand Down
35 changes: 35 additions & 0 deletions src/framework/global/tests/string_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,41 @@ TEST_F(Global_Types_StringTests, String_Split)
}
}

TEST_F(Global_Types_StringTests, String_Search)
{
//! GIVEN Regex (taken from musicxml parsing for finding sibelius metronome marks eg 'q = 140'):
std::regex re(".*([yxeqhVwW])(\\.?)\\s*=[^0-9]*([0-9]+).*");

{
//! GIVEN String:
String str(u"Andante (q. = c. 90)");

String match1 = u"q";
String match2 = u".";
String match3 = u"90";

//! DO
StringList matches = str.search(re, { 1, 2, 3 });

//! CHECK

EXPECT_EQ(matches.at(0), match1);
EXPECT_EQ(matches.at(1), match2);
EXPECT_EQ(matches.at(2), match3);
}

{
//! GIVEN String:
String str(u"Andante (b = c. abc)");

//! DO
StringList matches = str.search(re, { 1, 2, 3 }, SplitBehavior::SkipEmptyParts);

//! CHECK
EXPECT_EQ(matches.size(), 0);
}
}

TEST_F(Global_Types_StringTests, String_StartEndWith)
{
{
Expand Down
22 changes: 22 additions & 0 deletions src/framework/global/types/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,28 @@ StringList String::split(const std::regex& re, SplitBehavior behavior) const
return out;
}

StringList String::search(const std::regex& re, std::initializer_list<int> matches, SplitBehavior behavior) const
{
std::string originU8;
UtfCodec::utf16to8(std::u16string_view(constStr()), originU8);
std::sregex_token_iterator iter(originU8.begin(), originU8.end(), re, matches);
std::sregex_token_iterator end;
std::vector<std::string> vec = { iter, end };

StringList out;
for (const std::string& s : vec) {
if (behavior == SplitBehavior::SkipEmptyParts && s.empty()) {
// skip
continue;
}
String sub;
UtfCodec::utf8to16(s, sub.mutStr());
out.push_back(std::move(sub));
}

return out;
}

String& String::replace(const String& before, const String& after)
{
if (before == after) {
Expand Down
1 change: 1 addition & 0 deletions src/framework/global/types/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ class String
StringList split(const Char& ch, SplitBehavior behavior = KeepEmptyParts) const;
StringList split(const String& str, SplitBehavior behavior = KeepEmptyParts) const;
StringList split(const std::regex& re, SplitBehavior behavior = KeepEmptyParts) const;
StringList search(const std::regex& re, std::initializer_list<int> matches, SplitBehavior behavior = KeepEmptyParts) const;
String& replace(const String& before, const String& after);
String& replace(char16_t before, char16_t after);
String& replace(const std::regex& re, const String& after);
Expand Down
52 changes: 52 additions & 0 deletions src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2847,6 +2847,7 @@ void MusicXMLParserDirection::direction(const String& partId,
}
}

handleTempo();
handleRepeats(measure, track, tick + m_offset);
handleNmiCmi(measure, track, tick + m_offset, delayedDirections);

Expand Down Expand Up @@ -3364,6 +3365,57 @@ void MusicXMLParserDirection::handleNmiCmi(Measure* measure, const track_idx_t t
m_wordsText.replace(u"NmiCmi", u"N.C.");
}

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
String plainWords = MScoreTextToMXML::toPlainText(m_wordsText.simplified());

static const std::regex tempo(".*([yxeqhVwW])(\\.?)\\s*=[^0-9]*([0-9]+).*");
StringList tempoMatches = plainWords.search(tempo, { 1, 2, 3 }, SplitBehavior::SkipEmptyParts);

// Not a tempo
if (tempoMatches.size() < 2) {
return;
}

const String dur = tempoMatches.at(0);
const bool dot = tempoMatches.size() == 3;
const String val = tempoMatches.at(dot ? 2 : 1);

const String dotStr = dot ? u"<sym>space</sym><sym>metAugmentationDot</sym>" : u"";
// Map Sibelius' representation of note types to their SMuFL counterparts and duration types
static const std::map<String, std::pair<String, DurationType> > syms = {
{ u"y", { u"<sym>metNote32ndUp</sym>", DurationType::V_32ND } },
{ u"x", { u"<sym>metNote16thUp</sym>", DurationType::V_16TH } },
{ u"e", { u"<sym>metNote8thUp</sym>", DurationType::V_EIGHTH } },
{ u"q", { u"<sym>metNoteQuarterUp</sym>", DurationType::V_QUARTER } },
{ u"h", { u"<sym>metNoteHalfUp</sym>", DurationType::V_HALF } },
{ u"w", { u"<sym>metNoteWhole</sym>", DurationType::V_WHOLE } },
{ u"V", { u"<sym>metNoteDoubleWholeSquare</sym>", DurationType::V_BREVE } },
{ u"W", { u"<sym>metNoteDoubleWhole</sym>", DurationType::V_BREVE } }
};

static const std::regex replace("(.*)[yxeqhVwW]\\.?(\\s*=[^0-9]*[0-9]+.*)");
const String newStr = u"$1" + syms.at(dur).first + dotStr + u"$2";
plainWords.replace(replace, newStr);
m_wordsText = plainWords;

if (!val.empty() && !dur.empty()) {
bool ok;
double d = val.toDouble(&ok);
TDuration duration = TDuration(syms.at(dur).second);
duration.setDots(dot);

if (ok && duration.isValid()) {
// convert fraction to beats per minute
m_tpoMetro = 4 * duration.fraction().numerator() * d / duration.fraction().denominator();
}
}
}

//---------------------------------------------------------
// bracket
//---------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ class MusicXMLParserDirection
void dynamics();
void handleRepeats(Measure* measure, const track_idx_t track, const Fraction tick);
void handleNmiCmi(Measure* measure, const track_idx_t track, const Fraction tick, DelayedDirectionsList& delayedDirections);
void handleTempo();
String matchRepeat() const;
void skipLogCurrElem();
bool isLikelyCredit(const Fraction& tick) const;
Expand Down
Binary file not shown.
Loading