Skip to content

Commit fe21a8c

Browse files
Merge pull request musescore#17489 from HemantAntony/15903-accidentals_not_imported_musicxml
Fix musescore#15903: Added MusicXML support for some accidentals
2 parents bc5e929 + 7d8c3d1 commit fe21a8c

File tree

5 files changed

+158
-54
lines changed

5 files changed

+158
-54
lines changed

src/importexport/musicxml/internal/musicxml/exportxml.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2182,7 +2182,12 @@ void ExportMusicXml::keysig(const KeySig* ks, ClefType ct, staff_idx_t staff, bo
21822182
//LOGD(" keysym sym %d -> line %d step %d", ksym.sym, ksym.line, step);
21832183
_xml.tag("key-step", QString(QChar(table2[step])));
21842184
_xml.tag("key-alter", accSymId2alter(ksym.sym));
2185-
_xml.tag("key-accidental", accSymId2MxmlString(ksym.sym));
2185+
XmlWriter::Attributes accidentalAttrs;
2186+
QString s = accSymId2MxmlString(ksym.sym);
2187+
if (s == "other") {
2188+
accidentalAttrs = { { "smufl", accSymId2SmuflMxmlString(ksym.sym) } };
2189+
}
2190+
_xml.tag("key-accidental", accidentalAttrs, s);
21862191
}
21872192
} else {
21882193
// traditional key signature
@@ -2556,11 +2561,15 @@ static void writeAccidental(XmlWriter& xml, const QString& tagName, const Accide
25562561
if (acc) {
25572562
QString s = accidentalType2MxmlString(acc->accidentalType());
25582563
if (s != "") {
2564+
XmlWriter::Attributes attrs;
2565+
if (s == "other") {
2566+
attrs = { { "smufl", accidentalType2SmuflMxmlString(acc->accidentalType()) } };
2567+
}
25592568
QString tag = tagName;
25602569
if (acc->bracket() != AccidentalBracket::NONE) {
2561-
tag += " parentheses=\"yes\"";
2570+
attrs.emplace_back(std::make_pair("parentheses", "yes"));
25622571
}
2563-
xml.tagRaw(tag, s);
2572+
xml.tag(AsciiStringView(tag.toStdString()), attrs, s);
25642573
}
25652574
}
25662575
}

src/importexport/musicxml/internal/musicxml/importmxmlnotepitch.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ static Accidental* accidental(QXmlStreamReader& e, Score* score)
4848
bool cautionary = e.attributes().value("cautionary") == "yes";
4949
bool editorial = e.attributes().value("editorial") == "yes";
5050
bool parentheses = e.attributes().value("parentheses") == "yes";
51+
QString smufl = e.attributes().value("smufl").toString();
5152

5253
const auto s = e.readElementText();
53-
const auto type = mxmlString2accidentalType(s);
54+
const auto type = mxmlString2accidentalType(s, smufl);
5455

5556
if (type != AccidentalType::NONE) {
5657
auto a = Factory::createAccidental(score->dummy());

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3701,18 +3701,24 @@ void MusicXMLParserPass2::doEnding(const QString& partId, Measure* measure, cons
37013701
Add a symbol defined as key-step \a step , -alter \a alter and -accidental \a accid to \a sig.
37023702
*/
37033703

3704-
static void addSymToSig(KeySigEvent& sig, const QString& step, const QString& alter, const QString& accid)
3704+
static void addSymToSig(KeySigEvent& sig, const QString& step, const QString& alter, const QString& accid,
3705+
const QString& smufl)
37053706
{
37063707
//LOGD("addSymToSig(step '%s' alt '%s' acc '%s')",
37073708
// qPrintable(step), qPrintable(alter), qPrintable(accid));
37083709

3709-
SymId id = mxmlString2accSymId(accid);
3710+
SymId id = mxmlString2accSymId(accid, smufl);
3711+
37103712
if (id == SymId::noSym) {
37113713
bool ok;
37123714
double d;
37133715
d = alter.toDouble(&ok);
37143716
AccidentalType accTpAlter = ok ? microtonalGuess(d) : AccidentalType::NONE;
3715-
id = mxmlString2accSymId(accidentalType2MxmlString(accTpAlter));
3717+
QString s = accidentalType2MxmlString(accTpAlter);
3718+
if (s == "other") {
3719+
s = accidentalType2SmuflMxmlString(accTpAlter);
3720+
}
3721+
id = mxmlString2accSymId(s);
37163722
}
37173723

37183724
if (step.size() == 1 && id != SymId::noSym) {
@@ -3762,7 +3768,7 @@ static void addKey(const KeySigEvent key, const bool printObj, Score* score, Mea
37623768
Clear key-step, -alter, -accidental.
37633769
*/
37643770

3765-
static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QString& acc)
3771+
static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QString& acc, QString& smufl)
37663772
{
37673773
//LOGD("flushAlteredTone(step '%s' alt '%s' acc '%s')",
37683774
// qPrintable(step), qPrintable(alt), qPrintable(acc));
@@ -3772,7 +3778,7 @@ static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QStr
37723778
}
37733779
// step and alt are required, but also accept step and acc
37743780
if (step != "" && (alt != "" || acc != "")) {
3775-
addSymToSig(kse, step, alt, acc);
3781+
addSymToSig(kse, step, alt, acc, smufl);
37763782
} else {
37773783
LOGD("flushAlteredTone invalid combination of step '%s' alt '%s' acc '%s')",
37783784
qPrintable(step), qPrintable(alt), qPrintable(acc)); // TODO
@@ -3818,6 +3824,7 @@ void MusicXMLParserPass2::key(const QString& partId, Measure* measure, const Fra
38183824
QString keyStep;
38193825
QString keyAlter;
38203826
QString keyAccidental;
3827+
QString smufl;
38213828

38223829
while (_e.readNextStartElement()) {
38233830
if (_e.name() == "fifths") {
@@ -3863,17 +3870,18 @@ void MusicXMLParserPass2::key(const QString& partId, Measure* measure, const Fra
38633870
} else if (_e.name() == "cancel") {
38643871
skipLogCurrElem(); // TODO ??
38653872
} else if (_e.name() == "key-step") {
3866-
flushAlteredTone(key, keyStep, keyAlter, keyAccidental);
3873+
flushAlteredTone(key, keyStep, keyAlter, keyAccidental, smufl);
38673874
keyStep = _e.readElementText();
38683875
} else if (_e.name() == "key-alter") {
38693876
keyAlter = _e.readElementText();
38703877
} else if (_e.name() == "key-accidental") {
3878+
smufl = _e.attributes().value("smufl").toString();
38713879
keyAccidental = _e.readElementText();
38723880
} else {
38733881
skipLogCurrElem();
38743882
}
38753883
}
3876-
flushAlteredTone(key, keyStep, keyAlter, keyAccidental);
3884+
flushAlteredTone(key, keyStep, keyAlter, keyAccidental, smufl);
38773885

38783886
size_t nstaves = _pass1.getPart(partId)->nstaves();
38793887
staff_idx_t staffIdx = _pass1.trackForPart(partId) / VOICES;

src/importexport/musicxml/internal/musicxml/musicxmlsupport.cpp

Lines changed: 125 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,62 @@
2828
#include "libmscore/accidental.h"
2929
#include "libmscore/articulation.h"
3030
#include "libmscore/chord.h"
31+
#include "types/symnames.h"
3132

3233
#include "musicxmlsupport.h"
3334

3435
#include "log.h"
3536

37+
using AccidentalType = mu::engraving::AccidentalType;
38+
using SymId = mu::engraving::SymId;
39+
const static QMap<QString, AccidentalType> smuflAccidentalTypes {
40+
{ "accidentalDoubleFlatOneArrowDown", AccidentalType::DOUBLE_FLAT_ONE_ARROW_DOWN },
41+
{ "accidentalFlatOneArrowDown", AccidentalType::FLAT_ONE_ARROW_DOWN },
42+
{ "accidentalNaturalOneArrowDown", AccidentalType::NATURAL_ONE_ARROW_DOWN },
43+
{ "accidentalSharpOneArrowDown", AccidentalType::SHARP_ONE_ARROW_DOWN },
44+
{ "accidentalDoubleSharpOneArrowDown", AccidentalType::DOUBLE_SHARP_ONE_ARROW_DOWN },
45+
{ "accidentalDoubleFlatOneArrowUp", AccidentalType::DOUBLE_FLAT_ONE_ARROW_UP },
46+
{ "accidentalFlatOneArrowUp", AccidentalType::FLAT_ONE_ARROW_UP },
47+
{ "accidentalNaturalOneArrowUp", AccidentalType::NATURAL_ONE_ARROW_UP },
48+
{ "accidentalSharpOneArrowUp", AccidentalType::SHARP_ONE_ARROW_UP },
49+
{ "accidentalDoubleSharpOneArrowUp", AccidentalType::DOUBLE_SHARP_ONE_ARROW_UP },
50+
{ "accidentalDoubleFlatTwoArrowsDown", AccidentalType::DOUBLE_FLAT_TWO_ARROWS_DOWN },
51+
{ "accidentalFlatTwoArrowsDown", AccidentalType::FLAT_TWO_ARROWS_DOWN },
52+
{ "accidentalNaturalTwoArrowsDown", AccidentalType::NATURAL_TWO_ARROWS_DOWN },
53+
{ "accidentalSharpTwoArrowsDown", AccidentalType::SHARP_TWO_ARROWS_DOWN },
54+
{ "accidentalDoubleSharpTwoArrowsDown", AccidentalType::DOUBLE_SHARP_TWO_ARROWS_DOWN },
55+
{ "accidentalDoubleFlatTwoArrowsUp", AccidentalType::DOUBLE_FLAT_TWO_ARROWS_UP },
56+
{ "accidentalFlatTwoArrowsUp", AccidentalType::FLAT_TWO_ARROWS_UP },
57+
{ "accidentalNaturalTwoArrowsUp", AccidentalType::NATURAL_TWO_ARROWS_UP },
58+
{ "accidentalSharpTwoArrowsUp", AccidentalType::SHARP_TWO_ARROWS_UP },
59+
{ "accidentalDoubleSharpTwoArrowsUp", AccidentalType::DOUBLE_SHARP_TWO_ARROWS_UP },
60+
{ "accidentalDoubleFlatThreeArrowsDown", AccidentalType::DOUBLE_FLAT_THREE_ARROWS_DOWN },
61+
{ "accidentalFlatThreeArrowsDown", AccidentalType::FLAT_THREE_ARROWS_DOWN },
62+
{ "accidentalNaturalThreeArrowsDown", AccidentalType::NATURAL_THREE_ARROWS_DOWN },
63+
{ "accidentalSharpThreeArrowsDown", AccidentalType::SHARP_THREE_ARROWS_DOWN },
64+
{ "accidentalDoubleSharpThreeArrowsDown", AccidentalType::DOUBLE_SHARP_THREE_ARROWS_DOWN },
65+
{ "accidentalDoubleFlatThreeArrowsUp", AccidentalType::DOUBLE_FLAT_THREE_ARROWS_UP },
66+
{ "accidentalFlatThreeArrowsUp", AccidentalType::FLAT_THREE_ARROWS_UP },
67+
{ "accidentalNaturalThreeArrowsUp", AccidentalType::NATURAL_THREE_ARROWS_UP },
68+
{ "accidentalSharpThreeArrowsUp", AccidentalType::SHARP_THREE_ARROWS_UP },
69+
{ "accidentalDoubleSharpThreeArrowsUp", AccidentalType::DOUBLE_SHARP_THREE_ARROWS_UP },
70+
{ "accidentalLowerOneSeptimalComma", AccidentalType::LOWER_ONE_SEPTIMAL_COMMA },
71+
{ "accidentalRaiseOneSeptimalComma", AccidentalType::RAISE_ONE_SEPTIMAL_COMMA },
72+
{ "accidentalLowerTwoSeptimalCommas", AccidentalType::LOWER_TWO_SEPTIMAL_COMMAS },
73+
{ "accidentalRaiseTwoSeptimalCommas", AccidentalType::RAISE_TWO_SEPTIMAL_COMMAS },
74+
{ "accidentalLowerOneUndecimalQuartertone", AccidentalType::LOWER_ONE_UNDECIMAL_QUARTERTONE },
75+
{ "accidentalRaiseOneUndecimalQuartertone", AccidentalType::RAISE_ONE_UNDECIMAL_QUARTERTONE },
76+
{ "accidentalLowerOneTridecimalQuartertone", AccidentalType::LOWER_ONE_TRIDECIMAL_QUARTERTONE },
77+
{ "accidentalRaiseOneTridecimalQuartertone", AccidentalType::RAISE_ONE_TRIDECIMAL_QUARTERTONE },
78+
{ "accidentalDoubleFlatEqualTempered", AccidentalType::DOUBLE_FLAT_EQUAL_TEMPERED },
79+
{ "accidentalFlatEqualTempered", AccidentalType::FLAT_EQUAL_TEMPERED },
80+
{ "accidentalNaturalEqualTempered", AccidentalType::NATURAL_EQUAL_TEMPERED },
81+
{ "accidentalSharpEqualTempered", AccidentalType::SHARP_EQUAL_TEMPERED },
82+
{ "accidentalDoubleSharpEqualTempered", AccidentalType::DOUBLE_SHARP_EQUAL_TEMPERED },
83+
{ "accidentalQuarterFlatEqualTempered", AccidentalType::QUARTER_FLAT_EQUAL_TEMPERED },
84+
{ "accidentalQuarterSharpEqualTempered", AccidentalType::QUARTER_SHARP_EQUAL_TEMPERED }
85+
};
86+
3687
namespace mu::engraving {
3788
NoteList::NoteList()
3889
{
@@ -492,32 +543,49 @@ QString accSymId2MxmlString(const SymId id)
492543
case SymId::accidentalBuyukMucennebFlat: s = "double-slash-flat";
493544
break;
494545

495-
//case SymId::noSym: s = "sharp1"; break;
496-
//case SymId::noSym: s = "sharp2"; break;
497-
//case SymId::noSym: s = "sharp3"; break;
498-
//case SymId::noSym: s = "sharp4"; break;
499-
//case SymId::noSym: s = "flat1"; break;
500-
//case SymId::noSym: s = "flat2"; break;
501-
//case SymId::noSym: s = "flat3"; break;
502-
//case SymId::noSym: s = "flat4"; break;
546+
case SymId::accidental1CommaSharp: s = "sharp-1";
547+
break;
548+
case SymId::accidental2CommaSharp: s = "sharp-2";
549+
break;
550+
case SymId::accidental3CommaSharp: s = "sharp-3";
551+
break;
552+
case SymId::accidental5CommaSharp: s = "sharp-5";
553+
break;
554+
case SymId::accidental1CommaFlat: s = "flat-1";
555+
break;
556+
case SymId::accidental2CommaFlat: s = "flat-2";
557+
break;
558+
case SymId::accidental3CommaFlat: s = "flat-3";
559+
break;
560+
case SymId::accidental4CommaFlat: s = "flat-4";
561+
break;
503562

504563
case SymId::accidentalSori: s = "sori";
505564
break;
506565
case SymId::accidentalKoron: s = "koron";
507566
break;
508567
default:
509-
//s = "other"; // actually pick up the SMuFL name or SymId
568+
s = "other";
510569
LOGD("accSymId2MxmlString: unknown accidental %d", static_cast<int>(id));
511570
}
512571
return s;
513572
}
514573

574+
//---------------------------------------------------------
575+
// accSymId2SmuflMxmlString
576+
//---------------------------------------------------------
577+
578+
QString accSymId2SmuflMxmlString(const SymId id)
579+
{
580+
return SymNames::nameForSymId(id).ascii();
581+
}
582+
515583
//---------------------------------------------------------
516584
// mxmlString2accSymId
517585
// see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
518586
//---------------------------------------------------------
519587

520-
SymId mxmlString2accSymId(const QString mxmlName)
588+
SymId mxmlString2accSymId(const QString mxmlName, const QString smufl)
521589
{
522590
QMap<QString, SymId> map; // map MusicXML accidental name to MuseScore enum SymId
523591
map["sharp"] = SymId::accidentalSharp;
@@ -557,22 +625,22 @@ SymId mxmlString2accSymId(const QString mxmlName)
557625
map["slash-flat"] = SymId::accidentalBakiyeFlat;
558626
map["double-slash-flat"] = SymId::accidentalBuyukMucennebFlat;
559627

560-
//map["sharp1"] = SymId::noSym;
561-
//map["sharp2"] = SymId::noSym;
562-
//map["sharp3"] = SymId::noSym;
563-
//map["sharp4"] = SymId::noSym;
564-
//map["flat1"] = SymId::noSym;
565-
//map["flat2"] = SymId::noSym;
566-
//map["flat3"] = SymId::noSym;
567-
//map["flat3"] = SymId::noSym;
628+
map["sharp-1"] = SymId::accidental1CommaSharp;
629+
map["sharp-2"] = SymId::accidental2CommaSharp;
630+
map["sharp-3"] = SymId::accidental3CommaSharp;
631+
map["sharp-5"] = SymId::accidental5CommaSharp;
632+
map["flat-1"] = SymId::accidental1CommaFlat;
633+
map["flat-2"] = SymId::accidental2CommaFlat;
634+
map["flat-3"] = SymId::accidental3CommaFlat;
635+
map["flat-4"] = SymId::accidental4CommaFlat;
568636

569637
map["sori"] = SymId::accidentalSori;
570638
map["koron"] = SymId::accidentalKoron;
571639

572-
//map["other"] = SymId::noSym; // actually pick up the SMuFL name or SymId
573-
574640
if (map.contains(mxmlName)) {
575641
return map.value(mxmlName);
642+
} else if (mxmlName == "other") {
643+
return SymNames::symIdByName(smufl);
576644
} else {
577645
LOGD("mxmlString2accSymId: unknown accidental '%s'", qPrintable(mxmlName));
578646
}
@@ -654,26 +722,42 @@ QString accidentalType2MxmlString(const AccidentalType type)
654722
case AccidentalType::FLAT_SLASH2: s = "double-slash-flat";
655723
break;
656724

657-
//case AccidentalType::NONE: s = "sharp1"; break;
658-
//case AccidentalType::NONE: s = "sharp2"; break;
659-
//case AccidentalType::NONE: s = "sharp3"; break;
660-
//case AccidentalType::NONE: s = "sharp4"; break;
661-
//case AccidentalType::NONE: s = "flat1"; break;
662-
//case AccidentalType::NONE: s = "flat2"; break;
663-
//case AccidentalType::NONE: s = "flat3"; break;
664-
//case AccidentalType::NONE: s = "flat3"; break;
725+
case AccidentalType::ONE_COMMA_SHARP: s = "sharp-1";
726+
break;
727+
case AccidentalType::TWO_COMMA_SHARP: s = "sharp-2";
728+
break;
729+
case AccidentalType::THREE_COMMA_SHARP: s = "sharp-3";
730+
break;
731+
case AccidentalType::FIVE_COMMA_SHARP: s = "sharp-5";
732+
break;
733+
case AccidentalType::ONE_COMMA_FLAT: s = "flat-1";
734+
break;
735+
case AccidentalType::TWO_COMMA_FLAT: s = "flat-2";
736+
break;
737+
case AccidentalType::THREE_COMMA_FLAT: s = "flat-3";
738+
break;
739+
case AccidentalType::FOUR_COMMA_FLAT: s = "flat-4";
740+
break;
665741

666742
case AccidentalType::SORI: s = "sori";
667743
break;
668744
case AccidentalType::KORON: s = "koron";
669745
break;
670746
default:
671-
//s = "other"; // actually pick up the SMuFL name or SymId
672-
LOGD("accidentalType2MxmlString: unknown accidental %d", static_cast<int>(type));
747+
s = "other";
673748
}
674749
return s;
675750
}
676751

752+
//---------------------------------------------------------
753+
// accidentalType2SmuflMxmlString
754+
//---------------------------------------------------------
755+
756+
QString accidentalType2SmuflMxmlString(const AccidentalType type)
757+
{
758+
return smuflAccidentalTypes.key(type);
759+
}
760+
677761
//---------------------------------------------------------
678762
// mxmlString2accidentalType
679763
//---------------------------------------------------------
@@ -683,7 +767,7 @@ QString accidentalType2MxmlString(const AccidentalType type)
683767
see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
684768
*/
685769

686-
AccidentalType mxmlString2accidentalType(const QString mxmlName)
770+
AccidentalType mxmlString2accidentalType(const QString mxmlName, const QString smufl)
687771
{
688772
QMap<QString, AccidentalType> map; // map MusicXML accidental name to MuseScore enum AccidentalType
689773
map["sharp"] = AccidentalType::SHARP;
@@ -723,22 +807,22 @@ AccidentalType mxmlString2accidentalType(const QString mxmlName)
723807
map["slash-flat"] = AccidentalType::FLAT_SLASH;
724808
map["double-slash-flat"] = AccidentalType::FLAT_SLASH2;
725809

726-
//map["sharp1"] = AccidentalType::NONE;
727-
//map["sharp2"] = AccidentalType::NONE;
728-
//map["sharp3"] = AccidentalType::NONE;
729-
//map["sharp4"] = AccidentalType::NONE;
730-
//map["flat1"] = AccidentalType::NONE;
731-
//map["flat2"] = AccidentalType::NONE;
732-
//map["flat3"] = AccidentalType::NONE;
733-
//map["flat4"] = AccidentalType::NONE;
810+
map["sharp-1"] = AccidentalType::ONE_COMMA_SHARP;
811+
map["sharp-2"] = AccidentalType::TWO_COMMA_SHARP;
812+
map["sharp-3"] = AccidentalType::THREE_COMMA_SHARP;
813+
map["sharp-5"] = AccidentalType::FIVE_COMMA_SHARP;
814+
map["flat-1"] = AccidentalType::ONE_COMMA_FLAT;
815+
map["flat-2"] = AccidentalType::TWO_COMMA_FLAT;
816+
map["flat-3"] = AccidentalType::THREE_COMMA_FLAT;
817+
map["flat-4"] = AccidentalType::FOUR_COMMA_FLAT;
734818

735819
map["sori"] = AccidentalType::SORI;
736820
map["koron"] = AccidentalType::KORON;
737821

738-
//map["other"] = AccidentalType::NONE; // actually pick up the SMuFL name or SymId
739-
740822
if (map.contains(mxmlName)) {
741823
return map.value(mxmlName);
824+
} else if (mxmlName == "other" && smuflAccidentalTypes.contains(smufl)) {
825+
return smuflAccidentalTypes.value(smufl);
742826
} else {
743827
LOGD("mxmlString2accidentalType: unknown accidental '%s'", qPrintable(mxmlName));
744828
}

src/importexport/musicxml/internal/musicxml/musicxmlsupport.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,11 @@ extern void domError(const QDomElement&);
236236
extern void domNotImplemented(const QDomElement&);
237237

238238
extern QString accSymId2MxmlString(const SymId id);
239+
extern QString accSymId2SmuflMxmlString(const SymId id);
239240
extern QString accidentalType2MxmlString(const AccidentalType type);
240-
extern AccidentalType mxmlString2accidentalType(const QString mxmlName);
241-
extern SymId mxmlString2accSymId(const QString mxmlName);
241+
extern QString accidentalType2SmuflMxmlString(const AccidentalType type);
242+
extern AccidentalType mxmlString2accidentalType(const QString mxmlName, const QString smufl);
243+
extern SymId mxmlString2accSymId(const QString mxmlName, const QString smufl = "");
242244
extern AccidentalType microtonalGuess(double val);
243245
extern bool isLaissezVibrer(const SymId id);
244246
extern const Articulation* findLaissezVibrer(const Chord* const chord);

0 commit comments

Comments
 (0)