Skip to content

Commit faed16d

Browse files
committed
Port add further header text inference cases
b6d183f
1 parent b4700f9 commit faed16d

File tree

6 files changed

+66
-44
lines changed

6 files changed

+66
-44
lines changed

src/importexport/musicxml/internal/musicxml/importmxmlpass1.cpp

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -753,8 +753,19 @@ bool isLikelySubtitleText(const String& text, const bool caseInsensitive = true)
753753
std::regex::flag_type caseOption = caseInsensitive ? std::regex::icase : std::regex::ECMAScript;
754754
return text.trimmed().contains(std::wregex(L"^[Ff]rom\\s+(?!$)", caseOption))
755755
|| text.trimmed().contains(std::wregex(L"^Theme from\\s+(?!$)", caseOption))
756-
|| text.trimmed().contains(std::wregex(L"(Op\\.?\\s?\\d+)\\s?(No\\.?\\s?\\d+)?", caseOption))
757-
|| text.trimmed().contains(std::wregex(L"^\\(.*[Ff]rom\\s.*\\)$", caseOption));
756+
|| text.trimmed().contains(std::wregex(L"(((Op\\.?\\s?\\d+)|(No\\.?\\s?\\d+))\\s?)+", caseOption))
757+
|| text.trimmed().contains(std::wregex(L"\\(.*[Ff]rom\\s.*\\)", caseOption));
758+
}
759+
760+
//---------------------------------------------------------
761+
// isLikelyCreditText
762+
//---------------------------------------------------------
763+
764+
bool isLikelyCreditText(const String& text, const bool caseInsensitive = true)
765+
{
766+
std::regex::flag_type caseOption = caseInsensitive ? std::regex::icase : std::regex::ECMAScript;
767+
return text.trimmed().contains(std::wregex(L"^((Words|Music|Lyrics|Composed),?(\\sand|\\s&|\\s&)?\\s)*[Bb]y\\s+(?!$)", caseOption))
768+
|| text.trimmed().contains(std::wregex(L"^(Traditional|Trad\\.)", caseOption));
758769
}
759770

760771
//---------------------------------------------------------
@@ -764,17 +775,31 @@ bool isLikelySubtitleText(const String& text, const bool caseInsensitive = true)
764775
// Extracts a likely subtitle from the title string
765776
// Returns the inferred subtitle
766777

767-
static String inferSubTitleFromTitle(const String& title)
778+
static void inferFromTitle(String& title, String& inferredSubtitle, String& inferredCredits)
768779
{
769-
String inferredSubTitle;
770-
static const std::regex re("\\n");
771-
for (const String& line : title.split(re)) {
780+
StringList subtitleLines;
781+
StringList creditLines;
782+
StringList titleLines = title.split(std::regex("\\n"));
783+
for (int i = titleLines.size() - 1; i > 0; --i) {
784+
String line = titleLines[i];
785+
if (isLikelyCreditText(line, true)) {
786+
for (int j = titleLines.size() - 1; j >= i; --j) {
787+
creditLines.insert(0, titleLines[j]);
788+
titleLines.removeAt(j);
789+
}
790+
continue;
791+
}
772792
if (isLikelySubtitleText(line, true)) {
773-
inferredSubTitle = line;
774-
break;
793+
for (int j = titleLines.size() - 1; j >= i; --j) {
794+
subtitleLines.insert(0, titleLines[j]);
795+
titleLines.removeAt(j);
796+
}
797+
continue;
775798
}
776799
}
777-
return inferredSubTitle;
800+
title = titleLines.join(u"\n");
801+
inferredSubtitle = subtitleLines.join(u"\n");
802+
inferredCredits = creditLines.join(u"\n");
778803
}
779804

780805
//---------------------------------------------------------
@@ -839,11 +864,12 @@ static VBox* addCreditWords(Score* score, const CreditWordsList& crWords,
839864
// createMeasuresAndVboxes
840865
//---------------------------------------------------------
841866

842-
static void createDefaultHeader(Score* score)
867+
void MusicXMLParserPass1::createDefaultHeader(Score* score)
843868
{
844869
String strTitle;
845870
String strSubTitle;
846871
String inferredStrSubTitle;
872+
String inferredStrComposer;
847873
String strComposer;
848874
String strLyricist;
849875
String strTranslator;
@@ -853,23 +879,28 @@ static void createDefaultHeader(Score* score)
853879
if (strTitle.isEmpty()) {
854880
strTitle = score->metaTag(u"workTitle");
855881
}
856-
inferredStrSubTitle = inferSubTitleFromTitle(strTitle);
882+
inferFromTitle(strTitle, inferredStrSubTitle, inferredStrComposer);
857883
}
858884
if (!(score->metaTag(u"movementNumber").isEmpty() && score->metaTag(u"workNumber").isEmpty())) {
859885
strSubTitle = score->metaTag(u"movementNumber");
860886
if (strSubTitle.isEmpty()) {
861887
strSubTitle = score->metaTag(u"workNumber");
862888
}
863-
} else if (!inferredStrSubTitle.isEmpty()) {
889+
}
890+
if (!inferredStrSubTitle.isEmpty()) {
864891
strSubTitle = inferredStrSubTitle;
865-
strTitle.replace(inferredStrSubTitle, u"");
892+
m_hasInferredHeaderText = true;
866893
}
867894
String metaComposer = score->metaTag(u"composer");
868895
String metaLyricist = score->metaTag(u"lyricist");
869896
String metaTranslator = score->metaTag(u"translator");
870897
if (!metaComposer.isEmpty()) {
871898
strComposer = metaComposer;
872899
}
900+
if (!inferredStrComposer.isEmpty()) {
901+
strComposer = inferredStrComposer;
902+
m_hasInferredHeaderText = true;
903+
}
873904
if (metaLyricist.isEmpty()) {
874905
metaLyricist = score->metaTag(u"poet");
875906
}
@@ -897,13 +928,13 @@ static void createDefaultHeader(Score* score)
897928
Create required measures with correct number, start tick and length for Score \a score.
898929
*/
899930

900-
static void createMeasuresAndVboxes(Score* score,
901-
const std::vector<Fraction>& ml,
902-
const std::vector<Fraction>& ms,
903-
const std::set<int>& systemStartMeasureNrs,
904-
const std::set<int>& pageStartMeasureNrs,
905-
const CreditWordsList& crWords,
906-
const Size& pageSize)
931+
void MusicXMLParserPass1::createMeasuresAndVboxes(Score* score,
932+
const std::vector<Fraction>& ml,
933+
const std::vector<Fraction>& ms,
934+
const std::set<int>& systemStartMeasureNrs,
935+
const std::set<int>& pageStartMeasureNrs,
936+
const CreditWordsList& crWords,
937+
const Size& pageSize)
907938
{
908939
if (crWords.empty()) {
909940
createDefaultHeader(score);

src/importexport/musicxml/internal/musicxml/importmxmlpass1.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ using MxmlTupletStates = std::map<String, MxmlTupletState>;
113113

114114
void determineTupletFractionAndFullDuration(const Fraction duration, Fraction& fraction, Fraction& fullDuration);
115115
Fraction missingTupletDuration(const Fraction duration);
116+
bool isLikelyCreditText(const String& text, const bool caseInsensitive);
116117
bool isLikelySubtitleText(const String& text, const bool caseInsensitive);
117118

118119
//---------------------------------------------------------
@@ -183,6 +184,12 @@ class MusicXMLParserPass1
183184
bool hasBeamingInfo() const { return m_hasBeamingInfo; }
184185
bool isVocalStaff(const String& id) const { return m_parts.at(id).isVocalStaff(); }
185186
static VBox* createAndAddVBoxForCreditWords(Score* score, const int miny = 0, const int maxy = 75);
187+
void createDefaultHeader(Score* const score);
188+
void createMeasuresAndVboxes(Score* const score, const std::vector<Fraction>& ml, const std::vector<Fraction>& ms,
189+
const std::set<int>& systemStartMeasureNrs, const std::set<int>& pageStartMeasureNrs,
190+
const CreditWordsList& crWords, const Size& pageSize);
191+
void setHasInferredHeaderText(bool b) { m_hasInferredHeaderText = b; }
192+
bool hasInferredHeaderText() const { return m_hasInferredHeaderText; }
186193
int maxDiff() const { return m_maxDiff; }
187194
void insertAdjustedDuration(Fraction key, Fraction value) { m_adjustedDurations.insert({ key, value }); }
188195
std::map<Fraction, Fraction>& adjustedDurations() { return m_adjustedDurations; }
@@ -209,6 +216,7 @@ class MusicXMLParserPass1
209216
MxmlLogger* m_logger = nullptr; // Error logger
210217
String m_errors; // Errors to present to the user
211218
bool m_hasBeamingInfo = false; // Whether the score supports or contains beaming info
219+
bool m_hasInferredHeaderText = false;
212220

213221
// part specific data (TODO: move to part-specific class)
214222
Fraction m_timeSigDura; // Measure duration according to last timesig read

src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,7 @@ void MusicXMLParserPass2::scorePartwise()
18361836
}
18371837
addError(checkAtEndElement(m_e, u"score-partwise"));
18381838

1839-
if (m_hasInferredHeaderText) {
1839+
if (m_pass1.hasInferredHeaderText()) {
18401840
reformatHeaderVBox(m_score->measures()->first());
18411841
}
18421842
}
@@ -2942,13 +2942,13 @@ void MusicXMLParserDirection::direction(const String& partId,
29422942
} else if (isLikelyCredit(tick)) {
29432943
Text* inferredText = addTextToHeader(TextStyleType::COMPOSER);
29442944
if (inferredText) {
2945-
m_pass2.setHasInferredHeaderText(true);
2945+
m_pass1.setHasInferredHeaderText(true);
29462946
hideRedundantHeaderText(inferredText, { u"lyricist", u"composer", u"poet" });
29472947
}
29482948
} else if (isLikelySubtitle(tick)) {
29492949
Text* inferredText = addTextToHeader(TextStyleType::SUBTITLE);
29502950
if (inferredText) {
2951-
m_pass2.setHasInferredHeaderText(true);
2951+
m_pass1.setHasInferredHeaderText(true);
29522952
if (m_score->metaTag(u"source").isEmpty()) {
29532953
m_score->setMetaTag(u"source", inferredText->plainText());
29542954
}
@@ -3149,13 +3149,11 @@ void MusicXMLParserDirection::direction(const String& partId,
31493149

31503150
bool MusicXMLParserDirection::isLikelyCredit(const Fraction& tick) const
31513151
{
3152-
static const std::wregex re(L"^\\s*((Words|Music|Lyrics),?(\\sand|\\s&amp;)?\\s)*[Bb]y\\s+(?!$)");
3153-
31543152
return (tick + m_offset < Fraction(5, 1)) // Only early in the piece
31553153
&& m_rehearsalText.empty()
31563154
&& m_metroText.empty()
31573155
&& m_tpoSound < 0.1
3158-
&& m_wordsText.contains(re);
3156+
&& isLikelyCreditText(m_wordsText, false);
31593157
}
31603158

31613159
//---------------------------------------------------------

src/importexport/musicxml/internal/musicxml/importmxmlpass2.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ class MusicXMLParserPass2
294294
void clearSpanner(const MusicXmlSpannerDesc& desc);
295295
void deleteHandledSpanner(SLine* const& spanner);
296296
int divs() { return m_divs; }
297-
void setHasInferredHeaderText(bool b) { m_hasInferredHeaderText = b; }
298297

299298
SLine* delayedOttava() { return m_delayedOttava; }
300299
void setDelayedOttava(SLine* ottava) { m_delayedOttava = ottava; }
@@ -372,7 +371,6 @@ class MusicXMLParserPass2
372371
Tie* m_tie = nullptr;
373372
Volta* m_lastVolta = nullptr;
374373
bool m_hasDrumset; // drumset defined TODO: move to pass 1
375-
bool m_hasInferredHeaderText = false;
376374

377375
MusicXmlSpannerMap m_spanners;
378376

src/importexport/musicxml/tests/data/testInferredCredits2.xml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<work>
55
<work-title>Inferred Credits 2
66
from MUSESCORE: the musical: a tone poem
7+
Words &amp; Music by also Henry Ives (and ampersands)
78
</work-title>
89
</work>
910
<identification>
@@ -84,15 +85,6 @@ from MUSESCORE: the musical: a tone poem
8485
<line>2</line>
8586
</clef>
8687
</attributes>
87-
<direction placement="above">
88-
<direction-type>
89-
<words default-y="34.66" relative-y="10.00">Words &amp; Music by Henry Ives (and ampersands)
90-
</words>
91-
<words>
92-
</words>
93-
<words></words>
94-
</direction-type>
95-
</direction>
9688
<direction placement="above">
9789
<direction-type>
9890
<words default-y="34.66" relative-y="10.00">Lyrics to be sung by candlelight

src/importexport/musicxml/tests/data/testInferredCredits2_ref.mscx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<metaTag name="workNumber"></metaTag>
5050
<metaTag name="workTitle">Inferred Credits 2
5151
from MUSESCORE: the musical: a tone poem
52+
Words &amp; Music by also Henry Ives (and ampersands)
5253
</metaTag>
5354
<Part id="1">
5455
<Staff id="1">
@@ -127,19 +128,13 @@ from MUSESCORE: the musical: a tone poem
127128
<text>from MUSESCORE: the musical: a tone poem</text>
128129
</Text>
129130
<Text>
130-
<visible>0</visible>
131131
<style>composer</style>
132-
<text>Henry Ives</text>
132+
<text>Words &amp; Music by also Henry Ives (and ampersands)</text>
133133
</Text>
134134
<Text>
135-
<visible>0</visible>
136135
<style>poet</style>
137136
<text>Henry Ives</text>
138137
</Text>
139-
<Text>
140-
<style>composer</style>
141-
<text>Words &amp; Music by Henry Ives (and ampersands)</text>
142-
</Text>
143138
<Text>
144139
<style>subtitle</style>
145140
<offset x="0" y="16.8209"/>

0 commit comments

Comments
 (0)