Skip to content

Commit

Permalink
XML ottava fixes
Browse files Browse the repository at this point in the history
Backport of musescore#24776
  • Loading branch information
miiizen authored and Jojo-Schmitz committed Sep 19, 2024
1 parent 99775a6 commit 686a743
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 48 deletions.
38 changes: 33 additions & 5 deletions importexport/musicxml/importmxmlpass1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,22 @@ void MusicXMLParserPass1::addError(const QString& error)
}
}

void MusicXMLParserPass1::setExporterSoftware(QString& exporter)
{
if (exporter.contains("sibelius")) {
if (exporter.contains("dolet 6"))
_exporterSoftware = MusicXMLExporterSoftware::DOLET6;
else if (exporter.contains("dolet 8"))
_exporterSoftware = MusicXMLExporterSoftware::DOLET8;
else
_exporterSoftware = MusicXMLExporterSoftware::SIBELIUS;
}
else if (exporter.contains("finale"))
_exporterSoftware = MusicXMLExporterSoftware::FINALE;
else if (exporter.contains("noteflight"))
_exporterSoftware = MusicXMLExporterSoftware::NOTEFLIGHT;
}

//---------------------------------------------------------
// initPartState
//---------------------------------------------------------
Expand Down Expand Up @@ -885,7 +901,7 @@ void MusicXMLParserPass1::createMeasuresAndVboxes(Score* const score,
if (pageStartMeasureNrs.count(i) || i == 0) {
++pageNr;
if (pageNr == 1) {
vbox = addCreditWords(score, crWords, pageSize, true, _exporterString.contains("sibelius"));
vbox = addCreditWords(score, crWords, pageSize, true, sibOrDolet());
//if (i == 0 && vbox)
// vbox->setExcludeFromOtherParts(false);
}
Expand All @@ -908,10 +924,20 @@ void MusicXMLParserPass1::createMeasuresAndVboxes(Score* const score,

// add a footer vbox if the next measure is on a new page or end of score has been reached
if ((pageStartMeasureNrs.count(i + 1) || i == (ml.size() - 1)) && pageNr == 1)
addCreditWords(score, crWords, pageSize, false, _exporterString.contains("sibelius"));
addCreditWords(score, crWords, pageSize, false, sibOrDolet());
}
}

bool MusicXMLParserPass1::sibOrDolet() const
{
return _exporterSoftware == MusicXMLExporterSoftware::SIBELIUS || dolet();
}

bool MusicXMLParserPass1::dolet() const
{
return _exporterSoftware == MusicXMLExporterSoftware::DOLET6 || _exporterSoftware == MusicXMLExporterSoftware::DOLET8;
}

//---------------------------------------------------------
// determineMeasureStart
//---------------------------------------------------------
Expand Down Expand Up @@ -1242,8 +1268,10 @@ void MusicXMLParserPass1::identification()
else if (_e.name() == "encoding") {
// TODO
while (_e.readNextStartElement()) {
if (_e.name() == "software")
_exporterString += _e.readElementText().toLower();
if (_e.name() == "software") {
QString exporterString = _e.readElementText().toLower();
setExporterSoftware(exporterString);
}
else if (_e.name() == "supports" && _e.attributes().value("element") == "beam" && _e.attributes().value("type") == "yes") {
_hasBeamingInfo = true;
_e.skipCurrentElement();
Expand Down Expand Up @@ -2242,7 +2270,7 @@ void MusicXMLParserPass1::scoreInstrument(const QString& partId, const QString&
*/

// Finale exports all instrument names as 'Grand Piano' - use part name
if (_exporterString.contains("finale")) {
if (exporterSoftware() == MusicXMLExporterSoftware::FINALE) {
instrName = _parts[partId].getName();
if (instrName.size() <= 1)
instrName = curPartGroupName;
Expand Down
16 changes: 14 additions & 2 deletions importexport/musicxml/importmxmlpass1.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ enum class MxmlTupletFlag : char {
STOP_CURRENT = 8
};

enum class MusicXMLExporterSoftware : char {
SIBELIUS,
DOLET6,
DOLET8,
FINALE,
NOTEFLIGHT,
OTHER
};

typedef QFlags<MxmlTupletFlag> MxmlTupletFlags;

struct MxmlTupletState {
Expand Down Expand Up @@ -191,15 +200,18 @@ class MusicXMLParserPass1 {
void addInferredTranspose(const QString& partId);
void setHasInferredHeaderText(bool b) { _hasInferredHeaderText = b; }
bool hasInferredHeaderText() const { return _hasInferredHeaderText; }
QString exporterString() const { return _exporterString; }
MusicXMLExporterSoftware exporterSoftware() const { return _exporterSoftware; }
bool sibOrDolet() const;
bool dolet() const;

private:
// functions
void addError(const QString& error); ///< Add an error to be shown in the GUI
void setExporterSoftware(QString& exporter);

// generic pass 1 data
QXmlStreamReader _e;
QString _exporterString; ///< Name of the software which exported the file
MusicXMLExporterSoftware _exporterSoftware = MusicXMLExporterSoftware::OTHER; // Software which exported the file
int _divs; ///< Current MusicXML divisions value
QMap<QString, MusicXmlPart> _parts; ///< Parts data, mapped on part id
std::set<int> _systemStartMeasureNrs; ///< Measure numbers of measures starting a page
Expand Down
46 changes: 30 additions & 16 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2298,7 +2298,7 @@ void MusicXMLParserPass2::part()
// Clean up unterminated ties
for (auto tie : _ties) {
if (tie.second) {
cleanupUnterminatedTie(tie.second, _score, _pass1.exporterString().contains("dolet 6"));
cleanupUnterminatedTie(tie.second, _score, _pass1.exporterSoftware() == MusicXMLExporterSoftware::DOLET6);
_ties[tie.first] = nullptr;
}
}
Expand Down Expand Up @@ -3188,7 +3188,7 @@ void MusicXMLParserDirection::direction(const QString& partId,
int track = _pass1.trackForPart(partId);
bool isVocalStaff = _pass1.isVocalStaff(partId);
bool isExpressionText = false;
bool delayOttava = _pass1.exporterString().contains("sibelius");
bool delayOttava = _pass1.exporterSoftware() == MusicXMLExporterSoftware::SIBELIUS;
_systemDirection = _e.attributes().value("system").toString() == "only-top";
//qDebug("direction track %d", track);
QList<MusicXmlSpannerDesc> starts;
Expand Down Expand Up @@ -3463,21 +3463,25 @@ void MusicXMLParserDirection::direction(const QString& partId,
}
else {
if (spdesc._isStarted) {
// Adjustments to ottavas by the offset value are unwanted
const Fraction spTick = spdesc._sp && spdesc._sp->isOttava() ? tick : tick + _offset;
if (spdesc._sp && spdesc._sp->isOttava() && delayOttava) {
// Sibelius writes ottava ends 1 note too early
_pass2.setDelayedOttava(spdesc._sp);
_pass2.delayedOttava()->setTrack2(track);
_pass2.delayedOttava()->setTick2(tick + _offset);
_pass2.delayedOttava()->setTick2(spTick);
// need to set tick again later
_pass2.clearSpanner(desc);
}
else {
handleSpannerStop(spdesc._sp, track, tick + _offset, spanners);
handleSpannerStop(spdesc._sp, track, spTick, spanners);
_pass2.clearSpanner(desc);
}
}
else {
spdesc._sp = desc._sp;
spdesc._tick2 = tick + _offset;
const Fraction spTick = spdesc._sp && spdesc._sp->isOttava() ? tick : tick + _offset;
spdesc._tick2 = spTick;
spdesc._track2 = track;
spdesc._isStopped = true;
}
Expand Down Expand Up @@ -3667,7 +3671,7 @@ void MusicXMLParserDirection::otherDirection()
// TODO: Multiple sets of maps for exporters other than Dolet 6/Sibelius
// TODO: Add more symbols from Sibelius
QMap<QString, QString> otherDirectionStrings;
if (_pass1.exporterString().contains("dolet")) {
if (_pass1.dolet()) {
otherDirectionStrings = {
{ QString("To Coda"), QString("To Coda") },
{ QString("Segno"), QString("<sym>segno</sym>") },
Expand Down Expand Up @@ -4479,12 +4483,20 @@ void MusicXMLParserDirection::octaveShift(const QString& type, const int number,
else {
Ottava* o = spdesc._isStopped ? toOttava(spdesc._sp) : new Ottava(_score);

// if (placement.isEmpty()) placement = "above"; // TODO ? set default

if (type == "down" && ottavasize == 8) o->setOttavaType(OttavaType::OTTAVA_8VA);
if (type == "down" && ottavasize == 15) o->setOttavaType(OttavaType::OTTAVA_15MA);
if (type == "up" && ottavasize == 8) o->setOttavaType(OttavaType::OTTAVA_8VB);
if (type == "up" && ottavasize == 15) o->setOttavaType(OttavaType::OTTAVA_15MB);
if (type == "down") {
_placement = _placement.isEmpty() ? "above" : _placement;
if (ottavasize == 8)
o->setOttavaType(OttavaType::OTTAVA_8VA);
else if (ottavasize == 15)
o->setOttavaType(OttavaType::OTTAVA_15MA);
}
else /*if (type == "up")*/ {
_placement = _placement.isEmpty() ? "below" : _placement;
if (ottavasize == 8)
o->setOttavaType(OttavaType::OTTAVA_8VB);
else if (ottavasize == 15)
o->setOttavaType(OttavaType::OTTAVA_15MB);
}

const QColor color { _e.attributes().value("color").toString() };
if (color.isValid())
Expand Down Expand Up @@ -6095,7 +6107,7 @@ Note* MusicXMLParserPass2::note(const QString& partId,
QString noteheadValue = _e.readElementText();
if (noteheadValue == "none")
hasHead = false;
else if (noteheadValue == "named" && _pass1.exporterString().contains("noteflight"))
else if (noteheadValue == "named" && _pass1.exporterSoftware() == MusicXMLExporterSoftware::NOTEFLIGHT)
headScheme = NoteHead::Scheme::HEAD_PITCHNAME;
else
headGroup = convertNotehead(noteheadValue);
Expand Down Expand Up @@ -6390,7 +6402,8 @@ Note* MusicXMLParserPass2::note(const QString& partId,
Notation notation { "tied" };
const QString ctype { "type" };
notation.addAttribute(&ctype, &tieType);
addTie(notation, _score, note, cr->track(), _ties, _logger, &_e, _pass1.exporterString().contains("dolet 6"));
addTie(notation, _score, note, cr->track(), _ties, _logger, &_e,
_pass1.exporterSoftware() == MusicXMLExporterSoftware::DOLET6);
}
}

Expand Down Expand Up @@ -7001,7 +7014,7 @@ void MusicXMLParserPass2::harmony(const QString& partId, Measure* measure, const

const HarmonyDesc newHarmonyDesc(track, ha, fd);
bool insert = true;
if (_pass1.exporterString().contains("dolet")) {
if (_pass1.sibOrDolet()) {
const int ticks = (sTime + offset).ticks();
for (auto itr = harmonyMap.begin(); itr != harmonyMap.end(); itr++) {
if (itr->first != ticks)
Expand Down Expand Up @@ -8171,7 +8184,8 @@ void MusicXMLParserNotations::addToScore(ChordRest* const cr, Note* const note,
addGlissandoSlide(notation, note, glissandi, spanners, _logger, &_e);
}
else if (note && notation.name() == "tied") {
addTie(notation, _score, note, cr->track(), ties, _logger, &_e, _pass1.exporterString().contains("dolet 6"));
addTie(notation, _score, note, cr->track(), ties, _logger, &_e,
_pass1.exporterSoftware() == MusicXMLExporterSoftware::DOLET6);
}
else if (note && notation.parent() == "technical") {
addTechnical(notation, note);
Expand Down
Binary file added mtest/musicxml/io/testDoletOttavas.xml
Binary file not shown.
Loading

0 comments on commit 686a743

Please sign in to comment.