Skip to content

Commit

Permalink
Merge pull request musescore#17489 from HemantAntony/15903-accidental…
Browse files Browse the repository at this point in the history
…s_not_imported_musicxml

Fix musescore#15903: Added MusicXML support for some accidentals
  • Loading branch information
RomanPudashkin committed Jul 7, 2023
2 parents bc5e929 + 7d8c3d1 commit fe21a8c
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 54 deletions.
15 changes: 12 additions & 3 deletions src/importexport/musicxml/internal/musicxml/exportxml.cpp
Expand Up @@ -2182,7 +2182,12 @@ void ExportMusicXml::keysig(const KeySig* ks, ClefType ct, staff_idx_t staff, bo
//LOGD(" keysym sym %d -> line %d step %d", ksym.sym, ksym.line, step);
_xml.tag("key-step", QString(QChar(table2[step])));
_xml.tag("key-alter", accSymId2alter(ksym.sym));
_xml.tag("key-accidental", accSymId2MxmlString(ksym.sym));
XmlWriter::Attributes accidentalAttrs;
QString s = accSymId2MxmlString(ksym.sym);
if (s == "other") {
accidentalAttrs = { { "smufl", accSymId2SmuflMxmlString(ksym.sym) } };
}
_xml.tag("key-accidental", accidentalAttrs, s);
}
} else {
// traditional key signature
Expand Down Expand Up @@ -2556,11 +2561,15 @@ static void writeAccidental(XmlWriter& xml, const QString& tagName, const Accide
if (acc) {
QString s = accidentalType2MxmlString(acc->accidentalType());
if (s != "") {
XmlWriter::Attributes attrs;
if (s == "other") {
attrs = { { "smufl", accidentalType2SmuflMxmlString(acc->accidentalType()) } };
}
QString tag = tagName;
if (acc->bracket() != AccidentalBracket::NONE) {
tag += " parentheses=\"yes\"";
attrs.emplace_back(std::make_pair("parentheses", "yes"));
}
xml.tagRaw(tag, s);
xml.tag(AsciiStringView(tag.toStdString()), attrs, s);
}
}
}
Expand Down
Expand Up @@ -48,9 +48,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 = Factory::createAccidental(score->dummy());
Expand Down
22 changes: 15 additions & 7 deletions src/importexport/musicxml/internal/musicxml/importmxmlpass2.cpp
Expand Up @@ -3701,18 +3701,24 @@ 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)
{
//LOGD("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 @@ -3762,7 +3768,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)
{
//LOGD("flushAlteredTone(step '%s' alt '%s' acc '%s')",
// qPrintable(step), qPrintable(alt), qPrintable(acc));
Expand All @@ -3772,7 +3778,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 {
LOGD("flushAlteredTone invalid combination of step '%s' alt '%s' acc '%s')",
qPrintable(step), qPrintable(alt), qPrintable(acc)); // TODO
Expand Down Expand Up @@ -3818,6 +3824,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 @@ -3863,17 +3870,18 @@ 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") {
smufl = _e.attributes().value("smufl").toString();
keyAccidental = _e.readElementText();
} else {
skipLogCurrElem();
}
}
flushAlteredTone(key, keyStep, keyAlter, keyAccidental);
flushAlteredTone(key, keyStep, keyAlter, keyAccidental, smufl);

size_t nstaves = _pass1.getPart(partId)->nstaves();
staff_idx_t staffIdx = _pass1.trackForPart(partId) / VOICES;
Expand Down
166 changes: 125 additions & 41 deletions src/importexport/musicxml/internal/musicxml/musicxmlsupport.cpp
Expand Up @@ -28,11 +28,62 @@
#include "libmscore/accidental.h"
#include "libmscore/articulation.h"
#include "libmscore/chord.h"
#include "types/symnames.h"

#include "musicxmlsupport.h"

#include "log.h"

using AccidentalType = mu::engraving::AccidentalType;
using SymId = mu::engraving::SymId;
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 }
};

namespace mu::engraving {
NoteList::NoteList()
{
Expand Down Expand Up @@ -492,32 +543,49 @@ QString accSymId2MxmlString(const SymId id)
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 = "sharp-1";
break;
case SymId::accidental2CommaSharp: s = "sharp-2";
break;
case SymId::accidental3CommaSharp: s = "sharp-3";
break;
case SymId::accidental5CommaSharp: s = "sharp-5";
break;
case SymId::accidental1CommaFlat: s = "flat-1";
break;
case SymId::accidental2CommaFlat: s = "flat-2";
break;
case SymId::accidental3CommaFlat: s = "flat-3";
break;
case SymId::accidental4CommaFlat: s = "flat-4";
break;

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

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

QString accSymId2SmuflMxmlString(const SymId id)
{
return SymNames::nameForSymId(id).ascii();
}

//---------------------------------------------------------
// 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 @@ -557,22 +625,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 SymNames::symIdByName(smufl);
} else {
LOGD("mxmlString2accSymId: unknown accidental '%s'", qPrintable(mxmlName));
}
Expand Down Expand Up @@ -654,26 +722,42 @@ QString accidentalType2MxmlString(const AccidentalType type)
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
LOGD("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 @@ -683,7 +767,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 @@ -723,22 +807,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 {
LOGD("mxmlString2accidentalType: unknown accidental '%s'", qPrintable(mxmlName));
}
Expand Down
6 changes: 4 additions & 2 deletions src/importexport/musicxml/internal/musicxml/musicxmlsupport.h
Expand Up @@ -236,9 +236,11 @@ extern void domError(const QDomElement&);
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 const Articulation* findLaissezVibrer(const Chord* const chord);
Expand Down

0 comments on commit fe21a8c

Please sign in to comment.