Skip to content

Commit

Permalink
fix #14148: export of nonsense chords
Browse files Browse the repository at this point in the history
improved handling of "N.C." and other unparseable chords
  • Loading branch information
MarcSabatella committed Jul 11, 2013
1 parent 34a4d6d commit 55ed042
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 69 deletions.
57 changes: 34 additions & 23 deletions libmscore/harmony.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ QString Harmony::harmonyName()
if (_leftParen)
s = "(";

r = tpc2name(_rootTpc, _rootSpelling, _rootLowerCase);
if (_rootTpc != INVALID_TPC)
r = tpc2name(_rootTpc, _rootSpelling, _rootLowerCase);

if (_textName != "")
e = _textName.remove('=');
Expand Down Expand Up @@ -220,8 +221,11 @@ void Harmony::write(Xml& xml) const
}
Element::writeProperties(xml);
}
else
Text::writeProperties(xml);
else {
xml.tag("name", _textName);
Element::writeProperties(xml);
// Text::writeProperties(xml);
}
if (_rightParen)
xml.tagE("rightParen");
xml.etag();
Expand Down Expand Up @@ -303,14 +307,18 @@ void Harmony::read(XmlReader& e)
// These will typically only exist for chords imported from MusicXML prior to MuseScore 2.0
// or constructed in the Harmony Properties dialog.

if (_id > 0)
// lookup id in chord list and generate new description if necessary
getDescription();
else if (_textName != "")
// no id - look up name, in case it is in chord list with no id
getDescription(_textName);
if (_rootTpc != INVALID_TPC) {
if (_id > 0)
// lookup id in chord list and generate new description if necessary
getDescription();
else if (_textName != "")
// no id - look up name, in case it is in chord list with no id
getDescription(_textName);
}
else if (_textName == "")
_textName = text();

// render chord from description
// render chord from description (or _textName)
render();
}

Expand All @@ -327,7 +335,7 @@ void Harmony::determineRootBaseSpelling(NoteSpellingType& rootSpelling, bool& ro
else if (score()->styleB(ST_useSolfeggioNoteNames))
rootSpelling = SOLFEGGIO;
baseSpelling = rootSpelling;
const ChordDescription* cd = getDescription();
const ChordDescription* cd = descr();
if (cd) {
QString quality;
quality = cd->quality();
Expand All @@ -337,7 +345,7 @@ void Harmony::determineRootBaseSpelling(NoteSpellingType& rootSpelling, bool& ro
rootLowerCase = false;
}
else
rootLowerCase = false;
rootLowerCase = score()->styleB(ST_lowerCaseMinorChords);
if (baseSpelling == GERMAN)
baseLowerCase = true;
else
Expand Down Expand Up @@ -496,6 +504,8 @@ const ChordDescription* Harmony::parseHarmony(const QString& ss, int* root, int*
int r = convertRoot(s, _rootSpelling, idx);
if (r == INVALID_TPC) {
qDebug("1:parseHarmony failed <%s>", qPrintable(ss));
_userName = s;
_textName = s;
return 0;
}
*root = r;
Expand Down Expand Up @@ -595,13 +605,14 @@ void Harmony::setHarmony(const QString& s)
render();
}
else {
// syntax error, leave text as is
// unparseable chord, render as plain text
foreach(const TextSegment* s, textList)
delete s;
textList.clear();
setRootTpc(INVALID_TPC);
setBaseTpc(INVALID_TPC);
_id = -1;
render();
}
}

Expand Down Expand Up @@ -1040,9 +1051,6 @@ void Harmony::render(const QList<RenderAction>& renderList, qreal& x, qreal& y,

void Harmony::render(const TextStyle* st)
{
if (_rootTpc == INVALID_TPC)
return;

if (st == 0)
st = &textStyle();
ChordList* chordList = score()->style()->chordList();
Expand Down Expand Up @@ -1070,13 +1078,16 @@ void Harmony::render(const TextStyle* st)
if (_leftParen)
render("( ", x, y);

// render root
render(chordList->renderListRoot, x, y, _rootTpc, _rootSpelling, _rootLowerCase);

// render extension
const ChordDescription* cd = getDescription();
if (cd)
render(cd->renderList, x, y, 0);
if (_rootTpc != INVALID_TPC) {
// render root
render(chordList->renderListRoot, x, y, _rootTpc, _rootSpelling, _rootLowerCase);
// render extension
const ChordDescription* cd = getDescription();
if (cd)
render(cd->renderList, x, y, 0);
}
else
render(_textName, x, y);

// render bass
if (_baseTpc != INVALID_TPC)
Expand Down
21 changes: 16 additions & 5 deletions mscore/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4499,13 +4499,13 @@ double ExportMusicXml::getTenthsFromDots(double dots)

void ExportMusicXml::harmony(Harmony const* const h, FretDiagram const* const fd)
{
double rx = h->userOff().x()*10;
QString relative;
if (rx > 0) {
relative = QString(" relative-x=\"%1\"").arg(QString::number(rx,'f',2));
}
int rootTpc = h->rootTpc();
if (rootTpc != INVALID_TPC) {
double rx = h->userOff().x()*10;
QString relative;
if (rx > 0) {
relative = QString(" relative-x=\"%1\"").arg(QString::number(rx,'f',2));
}
if (h->hasFrame())
xml.stag(QString("harmony print-frame=\"yes\"").append(relative));
else
Expand Down Expand Up @@ -4580,13 +4580,24 @@ void ExportMusicXml::harmony(Harmony const* const h, FretDiagram const* const fd
// export an unrecognized Chord
// which may contain arbitrary text
//
xml.stag(QString("harmony").append(relative));
xml.stag("root");
xml.tag("root-step text=\"\"", "C");
xml.etag(); // root
QString k = "kind text=\"" + h->hTextName() + "\"";
xml.tag(k, "none");
xml.etag(); // harmony
#if 0
// prior to 2.0, MuseScore exported unrecognized chords as plain text
xml.stag("direction");
xml.stag("direction-type");
xml.tag("words", h->text());
xml.etag();
xml.etag();
#endif
}
#if 0
// this is very old code that may never have actually been used
xml.tag(QString("kind text=\"%1\"").arg(h->extensionName()), extension);
for (int i = 0; i < h->numberOfDegrees(); i++) {
HDegree hd = h->degree(i);
Expand Down
59 changes: 18 additions & 41 deletions mscore/importxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5041,11 +5041,18 @@ void MusicXml::xmlHarmony(QDomElement e, int tick, Measure* measure, int staff)
if (tag == "root") {
QString step;
int alter = 0;
bool invalidRoot = false;
for (QDomElement ee = e.firstChildElement(); !ee.isNull(); ee = ee.nextSiblingElement()) {
QString tag(ee.tagName());
if (tag == "root-step") {
// attributes: print-style
step = ee.text();
if (ee.hasAttribute("text")) {
QString rtext = ee.attribute("text");
if (rtext == "") {
invalidRoot = true;
}
}
}
else if (tag == "root-alter") {
// attributes: print-object, print-style
Expand All @@ -5055,7 +5062,10 @@ void MusicXml::xmlHarmony(QDomElement e, int tick, Measure* measure, int staff)
else
domError(ee);
}
ha->setRootTpc(step2tpc(step, AccidentalVal(alter)));
if (invalidRoot)
ha->setRootTpc(INVALID_TPC);
else
ha->setRootTpc(step2tpc(step, AccidentalVal(alter)));
}
else if (tag == "function") {
// attributes: print-style
Expand Down Expand Up @@ -5145,52 +5155,19 @@ void MusicXml::xmlHarmony(QDomElement e, int tick, Measure* measure, int staff)

//TODO-WS ha->setTick(tick);

const ChordDescription* d = ha->fromXml(kind, kindText, symbols, parens, degreeList);
const ChordDescription* d = 0;
if (ha->rootTpc() != INVALID_TPC)
d = ha->fromXml(kind, kindText, symbols, parens, degreeList);
if (d) {
ha->setId(d->id);
ha->setTextName(d->names.front());
ha->render();
}
#if 0
else {
// This code won't be hit if MusicXML was at all straightforward,
// as fromXml() is normally able to construct a chord description by itself.
// The following is retained from previous revisions as a fallback,
// in case fromXml fails but there is a match to be found in the tags from the chord list.
d = ha->fromXml(kind, degreeList);
if (d == 0) {
QString degrees;
foreach(const HDegree &d, degreeList) {
if (!degrees.isEmpty())
degrees += " ";
degrees += d.text();
}
qDebug("unknown chord txt: <%s> kind: <%s> degrees: %s",
qPrintable(kindText), qPrintable(kind), qPrintable(degrees));
// Strategy II: lookup "kind", merge in degree list and try to find
// harmony in list

d = ha->fromXml(kind);
if (d) {
ha->setId(d->id);
foreach(const HDegree &d, degreeList)
ha->addDegree(d);
ha->resolveDegreeList();
ha->render();
}
else {
qDebug("'kind: <%s> not found in harmony data base", qPrintable(kind));
QString s = tpc2name(ha->rootTpc(), score->style(ST_useGermanNoteNames).toBool()) + kindText;
ha->setText(s);
}
}
else {
ha->setId(d->id);
// ha->resolveDegreeList();
ha->render();
}
ha->setId(-1);
ha->setTextName(kindText);
}
#endif
ha->render();

ha->setVisible(printObject == "yes");

// TODO-LV: do this only if ha points to a valid harmony
Expand Down

0 comments on commit 55ed042

Please sign in to comment.