Skip to content

Commit

Permalink
Fix GH#15903: Added MusicXML support for some accidentals
Browse files Browse the repository at this point in the history
Backport of musescore#17489
  • Loading branch information
HemantAntony authored and Jojo-Schmitz committed Jul 5, 2023
1 parent b7f6faa commit 59f5aa5
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 53 deletions.
3 changes: 2 additions & 1 deletion importexport/musicxml/importmxmlnotepitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ static Accidental* accidental(QXmlStreamReader& e, Score* score)
bool cautionary = e.attributes().value("cautionary") == "yes";
bool editorial = e.attributes().value("editorial") == "yes";
bool parentheses = e.attributes().value("parentheses") == "yes";
QString smufl = e.attributes().value("smufl").toString();

const auto s = e.readElementText();
const auto type = mxmlString2accidentalType(s);
const auto type = mxmlString2accidentalType(s, smufl);

if (type != AccidentalType::NONE) {
auto a = new Accidental(score);
Expand Down
23 changes: 15 additions & 8 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4569,18 +4569,22 @@ void MusicXMLParserPass2::doEnding(const QString& partId, Measure* measure, cons
Add a symbol defined as key-step \a step , -alter \a alter and -accidental \a accid to \a sig.
*/

static void addSymToSig(KeySigEvent& sig, const QString& step, const QString& alter, const QString& accid)
static void addSymToSig(KeySigEvent& sig, const QString& step, const QString& alter, const QString& accid,
const QString& smufl)
{
//qDebug("addSymToSig(step '%s' alt '%s' acc '%s')",
// qPrintable(step), qPrintable(alter), qPrintable(accid));

SymId id = mxmlString2accSymId(accid);
SymId id = mxmlString2accSymId(accid, smufl);
if (id == SymId::noSym) {
bool ok;
double d;
d = alter.toDouble(&ok);
AccidentalType accTpAlter = ok ? microtonalGuess(d) : AccidentalType::NONE;
id = mxmlString2accSymId(accidentalType2MxmlString(accTpAlter));
QString s = accidentalType2MxmlString(accTpAlter);
if (s == "other")
s = accidentalType2SmuflMxmlString(accTpAlter);
id = mxmlString2accSymId(s);
}

if (step.size() == 1 && id != SymId::noSym) {
Expand Down Expand Up @@ -4634,7 +4638,7 @@ static void addKey(const KeySigEvent key, const bool printObj, Score* score, Mea
Clear key-step, -alter, -accidental.
*/

static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QString& acc)
static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QString& acc, QString& smufl)
{
//qDebug("flushAlteredTone(step '%s' alt '%s' acc '%s')",
// qPrintable(step), qPrintable(alt), qPrintable(acc));
Expand All @@ -4644,7 +4648,7 @@ static void flushAlteredTone(KeySigEvent& kse, QString& step, QString& alt, QStr

// step and alt are required, but also accept step and acc
if (step != "" && (alt != "" || acc != "")) {
addSymToSig(kse, step, alt, acc);
addSymToSig(kse, step, alt, acc, smufl);
}
else {
qDebug("flushAlteredTone invalid combination of step '%s' alt '%s' acc '%s')",
Expand Down Expand Up @@ -4689,6 +4693,7 @@ void MusicXMLParserPass2::key(const QString& partId, Measure* measure, const Fra
QString keyStep;
QString keyAlter;
QString keyAccidental;
QString smufl;

while (_e.readNextStartElement()) {
if (_e.name() == "fifths")
Expand Down Expand Up @@ -4723,17 +4728,19 @@ void MusicXMLParserPass2::key(const QString& partId, Measure* measure, const Fra
else if (_e.name() == "cancel")
skipLogCurrElem(); // TODO ??
else if (_e.name() == "key-step") {
flushAlteredTone(key, keyStep, keyAlter, keyAccidental);
flushAlteredTone(key, keyStep, keyAlter, keyAccidental, smufl);
keyStep = _e.readElementText();
}
else if (_e.name() == "key-alter")
keyAlter = _e.readElementText();
else if (_e.name() == "key-accidental")
else if (_e.name() == "key-accidental") {
smufl = _e.attributes().value("smufl").toString();
keyAccidental = _e.readElementText();
}
else
skipLogCurrElem();
}
flushAlteredTone(key, keyStep, keyAlter, keyAccidental);
flushAlteredTone(key, keyStep, keyAlter, keyAccidental, smufl);

int nstaves = _pass1.getPart(partId)->nstaves();
int staffIdx = _pass1.trackForPart(partId) / VOICES;
Expand Down
148 changes: 106 additions & 42 deletions importexport/musicxml/musicxmlsupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,54 @@

namespace Ms {

const static QMap<QString, AccidentalType> smuflAccidentalTypes {
{ "accidentalDoubleFlatOneArrowDown", AccidentalType::DOUBLE_FLAT_ONE_ARROW_DOWN },
{ "accidentalFlatOneArrowDown", AccidentalType::FLAT_ONE_ARROW_DOWN },
{ "accidentalNaturalOneArrowDown", AccidentalType::NATURAL_ONE_ARROW_DOWN },
{ "accidentalSharpOneArrowDown", AccidentalType::SHARP_ONE_ARROW_DOWN },
{ "accidentalDoubleSharpOneArrowDown", AccidentalType::DOUBLE_SHARP_ONE_ARROW_DOWN },
{ "accidentalDoubleFlatOneArrowUp", AccidentalType::DOUBLE_FLAT_ONE_ARROW_UP },
{ "accidentalFlatOneArrowUp", AccidentalType::FLAT_ONE_ARROW_UP },
{ "accidentalNaturalOneArrowUp", AccidentalType::NATURAL_ONE_ARROW_UP },
{ "accidentalSharpOneArrowUp", AccidentalType::SHARP_ONE_ARROW_UP },
{ "accidentalDoubleSharpOneArrowUp", AccidentalType::DOUBLE_SHARP_ONE_ARROW_UP },
{ "accidentalDoubleFlatTwoArrowsDown", AccidentalType::DOUBLE_FLAT_TWO_ARROWS_DOWN },
{ "accidentalFlatTwoArrowsDown", AccidentalType::FLAT_TWO_ARROWS_DOWN },
{ "accidentalNaturalTwoArrowsDown", AccidentalType::NATURAL_TWO_ARROWS_DOWN },
{ "accidentalSharpTwoArrowsDown", AccidentalType::SHARP_TWO_ARROWS_DOWN },
{ "accidentalDoubleSharpTwoArrowsDown", AccidentalType::DOUBLE_SHARP_TWO_ARROWS_DOWN },
{ "accidentalDoubleFlatTwoArrowsUp", AccidentalType::DOUBLE_FLAT_TWO_ARROWS_UP },
{ "accidentalFlatTwoArrowsUp", AccidentalType::FLAT_TWO_ARROWS_UP },
{ "accidentalNaturalTwoArrowsUp", AccidentalType::NATURAL_TWO_ARROWS_UP },
{ "accidentalSharpTwoArrowsUp", AccidentalType::SHARP_TWO_ARROWS_UP },
{ "accidentalDoubleSharpTwoArrowsUp", AccidentalType::DOUBLE_SHARP_TWO_ARROWS_UP },
{ "accidentalDoubleFlatThreeArrowsDown", AccidentalType::DOUBLE_FLAT_THREE_ARROWS_DOWN },
{ "accidentalFlatThreeArrowsDown", AccidentalType::FLAT_THREE_ARROWS_DOWN },
{ "accidentalNaturalThreeArrowsDown", AccidentalType::NATURAL_THREE_ARROWS_DOWN },
{ "accidentalSharpThreeArrowsDown", AccidentalType::SHARP_THREE_ARROWS_DOWN },
{ "accidentalDoubleSharpThreeArrowsDown", AccidentalType::DOUBLE_SHARP_THREE_ARROWS_DOWN },
{ "accidentalDoubleFlatThreeArrowsUp", AccidentalType::DOUBLE_FLAT_THREE_ARROWS_UP },
{ "accidentalFlatThreeArrowsUp", AccidentalType::FLAT_THREE_ARROWS_UP },
{ "accidentalNaturalThreeArrowsUp", AccidentalType::NATURAL_THREE_ARROWS_UP },
{ "accidentalSharpThreeArrowsUp", AccidentalType::SHARP_THREE_ARROWS_UP },
{ "accidentalDoubleSharpThreeArrowsUp", AccidentalType::DOUBLE_SHARP_THREE_ARROWS_UP },
{ "accidentalLowerOneSeptimalComma", AccidentalType::LOWER_ONE_SEPTIMAL_COMMA },
{ "accidentalRaiseOneSeptimalComma", AccidentalType::RAISE_ONE_SEPTIMAL_COMMA },
{ "accidentalLowerTwoSeptimalCommas", AccidentalType::LOWER_TWO_SEPTIMAL_COMMAS },
{ "accidentalRaiseTwoSeptimalCommas", AccidentalType::RAISE_TWO_SEPTIMAL_COMMAS },
{ "accidentalLowerOneUndecimalQuartertone", AccidentalType::LOWER_ONE_UNDECIMAL_QUARTERTONE },
{ "accidentalRaiseOneUndecimalQuartertone", AccidentalType::RAISE_ONE_UNDECIMAL_QUARTERTONE },
{ "accidentalLowerOneTridecimalQuartertone", AccidentalType::LOWER_ONE_TRIDECIMAL_QUARTERTONE },
{ "accidentalRaiseOneTridecimalQuartertone", AccidentalType::RAISE_ONE_TRIDECIMAL_QUARTERTONE },
{ "accidentalDoubleFlatEqualTempered", AccidentalType::DOUBLE_FLAT_EQUAL_TEMPERED },
{ "accidentalFlatEqualTempered", AccidentalType::FLAT_EQUAL_TEMPERED },
{ "accidentalNaturalEqualTempered", AccidentalType::NATURAL_EQUAL_TEMPERED },
{ "accidentalSharpEqualTempered", AccidentalType::SHARP_EQUAL_TEMPERED },
{ "accidentalDoubleSharpEqualTempered", AccidentalType::DOUBLE_SHARP_EQUAL_TEMPERED },
{ "accidentalQuarterFlatEqualTempered", AccidentalType::QUARTER_FLAT_EQUAL_TEMPERED },
{ "accidentalQuarterSharpEqualTempered", AccidentalType::QUARTER_SHARP_EQUAL_TEMPERED }
};

NoteList::NoteList()
{
for (int i = 0; i < MAX_VOICE_DESC_STAVES; ++i)
Expand Down Expand Up @@ -439,30 +487,38 @@ QString accSymId2MxmlString(const SymId id)
case SymId::accidentalBakiyeFlat: s = "slash-flat"; break;
case SymId::accidentalBuyukMucennebFlat: s = "double-slash-flat"; break;

//case SymId::noSym: s = "sharp1"; break;
//case SymId::noSym: s = "sharp2"; break;
//case SymId::noSym: s = "sharp3"; break;
//case SymId::noSym: s = "sharp4"; break;
//case SymId::noSym: s = "flat1"; break;
//case SymId::noSym: s = "flat2"; break;
//case SymId::noSym: s = "flat3"; break;
//case SymId::noSym: s = "flat4"; break;
case SymId::accidental1CommaSharp: s = "sharp1"; break;
case SymId::accidental2CommaSharp: s = "sharp2"; break;
case SymId::accidental3CommaSharp: s = "sharp3"; break;
case SymId::accidental5CommaSharp: s = "sharp5"; break;
case SymId::accidental1CommaFlat: s = "flat1"; break;
case SymId::accidental2CommaFlat: s = "flat2"; break;
case SymId::accidental3CommaFlat: s = "flat3"; break;
case SymId::accidental4CommaFlat: s = "flat4"; break;

case SymId::accidentalSori: s = "sori"; break;
case SymId::accidentalKoron: s = "koron"; break;
default:
//s = "other"; // actually pick up the SMuFL name or SymId
qDebug("accSymId2MxmlString: unknown accidental %d", static_cast<int>(id));
s = "other";
}
return s;
}

//---------------------------------------------------------
// accSymId2SmuflMxmlString
//---------------------------------------------------------

QString accSymId2SmuflMxmlString(const SymId id)
{
return Sym::id2name(id);
}

//---------------------------------------------------------
// mxmlString2accSymId
// see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
//---------------------------------------------------------

SymId mxmlString2accSymId(const QString mxmlName)
SymId mxmlString2accSymId(const QString mxmlName, const QString smufl)
{
QMap<QString, SymId> map; // map MusicXML accidental name to MuseScore enum SymId
map["sharp"] = SymId::accidentalSharp;
Expand Down Expand Up @@ -502,22 +558,22 @@ SymId mxmlString2accSymId(const QString mxmlName)
map["slash-flat"] = SymId::accidentalBakiyeFlat;
map["double-slash-flat"] = SymId::accidentalBuyukMucennebFlat;

//map["sharp1"] = SymId::noSym;
//map["sharp2"] = SymId::noSym;
//map["sharp3"] = SymId::noSym;
//map["sharp4"] = SymId::noSym;
//map["flat1"] = SymId::noSym;
//map["flat2"] = SymId::noSym;
//map["flat3"] = SymId::noSym;
//map["flat3"] = SymId::noSym;
map["sharp-1"] = SymId::accidental1CommaSharp;
map["sharp-2"] = SymId::accidental2CommaSharp;
map["sharp-3"] = SymId::accidental3CommaSharp;
map["sharp-5"] = SymId::accidental5CommaSharp;
map["flat-1"] = SymId::accidental1CommaFlat;
map["flat-2"] = SymId::accidental2CommaFlat;
map["flat-3"] = SymId::accidental3CommaFlat;
map["flat-4"] = SymId::accidental4CommaFlat;

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

//map["other"] = SymId::noSym; // actually pick up the SMuFL name or SymId

if (map.contains(mxmlName))
return map.value(mxmlName);
else if (mxmlName == "other")
return Sym::name2id(smufl);
else
qDebug("mxmlString2accSymId: unknown accidental '%s'", qPrintable(mxmlName));

Expand Down Expand Up @@ -570,24 +626,32 @@ QString accidentalType2MxmlString(const AccidentalType type)
case AccidentalType::FLAT_SLASH: s = "slash-flat"; break;
case AccidentalType::FLAT_SLASH2: s = "double-slash-flat"; break;

//case AccidentalType::NONE: s = "sharp1"; break;
//case AccidentalType::NONE: s = "sharp2"; break;
//case AccidentalType::NONE: s = "sharp3"; break;
//case AccidentalType::NONE: s = "sharp4"; break;
//case AccidentalType::NONE: s = "flat1"; break;
//case AccidentalType::NONE: s = "flat2"; break;
//case AccidentalType::NONE: s = "flat3"; break;
//case AccidentalType::NONE: s = "flat3"; break;
case AccidentalType::ONE_COMMA_SHARP: s = "sharp-1"; break;
case AccidentalType::TWO_COMMA_SHARP: s = "sharp-2"; break;
case AccidentalType::THREE_COMMA_SHARP: s = "sharp-3"; break;
case AccidentalType::FIVE_COMMA_SHARP: s = "sharp-5"; break;
case AccidentalType::ONE_COMMA_FLAT: s = "flat-1"; break;
case AccidentalType::TWO_COMMA_FLAT: s = "flat-2"; break;
case AccidentalType::THREE_COMMA_FLAT: s = "flat-3"; break;
case AccidentalType::FOUR_COMMA_FLAT: s = "flat-4"; break;

case AccidentalType::SORI: s = "sori"; break;
case AccidentalType::KORON: s = "koron"; break;
default:
//s = "other"; // actually pick up the SMuFL name or SymId
qDebug("accidentalType2MxmlString: unknown accidental %d", static_cast<int>(type));
s = "other";
}
return s;
}

//---------------------------------------------------------
// accidentalType2SmuflMxmlString
//---------------------------------------------------------

QString accidentalType2SmuflMxmlString(const AccidentalType type)
{
return smuflAccidentalTypes.key(type);
}

//---------------------------------------------------------
// mxmlString2accidentalType
//---------------------------------------------------------
Expand All @@ -597,7 +661,7 @@ QString accidentalType2MxmlString(const AccidentalType type)
see https://github.com/w3c/musicxml/blob/6e3a667b85855b04d7e4548ea508b537bc29fc52/schema/musicxml.xsd#L1392-L1439
*/

AccidentalType mxmlString2accidentalType(const QString mxmlName)
AccidentalType mxmlString2accidentalType(const QString mxmlName, const QString smufl)
{
QMap<QString, AccidentalType> map; // map MusicXML accidental name to MuseScore enum AccidentalType
map["sharp"] = AccidentalType::SHARP;
Expand Down Expand Up @@ -637,22 +701,22 @@ AccidentalType mxmlString2accidentalType(const QString mxmlName)
map["slash-flat"] = AccidentalType::FLAT_SLASH;
map["double-slash-flat"] = AccidentalType::FLAT_SLASH2;

//map["sharp1"] = AccidentalType::NONE;
//map["sharp2"] = AccidentalType::NONE;
//map["sharp3"] = AccidentalType::NONE;
//map["sharp4"] = AccidentalType::NONE;
//map["flat1"] = AccidentalType::NONE;
//map["flat2"] = AccidentalType::NONE;
//map["flat3"] = AccidentalType::NONE;
//map["flat4"] = AccidentalType::NONE;
map["sharp-1"] = AccidentalType::ONE_COMMA_SHARP;
map["sharp-2"] = AccidentalType::TWO_COMMA_SHARP;
map["sharp-3"] = AccidentalType::THREE_COMMA_SHARP;
map["sharp-5"] = AccidentalType::FIVE_COMMA_SHARP;
map["flat-1"] = AccidentalType::ONE_COMMA_FLAT;
map["flat-2"] = AccidentalType::TWO_COMMA_FLAT;
map["flat-3"] = AccidentalType::THREE_COMMA_FLAT;
map["flat-4"] = AccidentalType::FOUR_COMMA_FLAT;

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

//map["other"] = AccidentalType::NONE; // actually pick up the SMuFL name or SymId

if (map.contains(mxmlName))
return map.value(mxmlName);
else if (mxmlName == "other" && smuflAccidentalTypes.contains(smufl))
return smuflAccidentalTypes.value(smufl);
else
qDebug("mxmlString2accidentalType: unknown accidental '%s'", qPrintable(mxmlName));
return AccidentalType::NONE;
Expand Down
6 changes: 4 additions & 2 deletions importexport/musicxml/musicxmlsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,11 @@ extern void domNotImplemented(const QDomElement&);


extern QString accSymId2MxmlString(const SymId id);
extern QString accSymId2SmuflMxmlString(const SymId id);
extern QString accidentalType2MxmlString(const AccidentalType type);
extern AccidentalType mxmlString2accidentalType(const QString mxmlName);
extern SymId mxmlString2accSymId(const QString mxmlName);
extern QString accidentalType2SmuflMxmlString(const AccidentalType type);
extern AccidentalType mxmlString2accidentalType(const QString mxmlName, const QString smufl);
extern SymId mxmlString2accSymId(const QString mxmlName, const QString smufl = "");
extern AccidentalType microtonalGuess(double val);
extern bool isLaissezVibrer(const SymId id);
extern bool hasLaissezVibrer(const Chord* const chord);
Expand Down

0 comments on commit 59f5aa5

Please sign in to comment.