Skip to content

Commit

Permalink
Merge pull request #19972 from mike-spa/musicXMLimprovements
Browse files Browse the repository at this point in the history
Porting a bunch of old musicXML fixes
  • Loading branch information
RomanPudashkin committed Nov 16, 2023
2 parents 16fc08d + bd7c5b3 commit e2fe70b
Show file tree
Hide file tree
Showing 84 changed files with 35,278 additions and 475 deletions.
40 changes: 40 additions & 0 deletions src/engraving/dom/part.cpp
Expand Up @@ -515,6 +515,28 @@ void Part::setShortName(const String& s)
instrument()->setShortName(s);
}

//---------------------------------------------------------
// setLongNameAll
//---------------------------------------------------------

void Part::setLongNameAll(const String& s)
{
for (auto instrument : _instruments) {
instrument.second->setLongName(s);
}
}

//---------------------------------------------------------
// setShortNameAll
//---------------------------------------------------------

void Part::setShortNameAll(const String& s)
{
for (auto instrument : _instruments) {
instrument.second->setShortName(s);
}
}

//---------------------------------------------------------
// setPlainLongName
//---------------------------------------------------------
Expand All @@ -533,6 +555,24 @@ void Part::setPlainShortName(const String& s)
setShortName(XmlWriter::xmlString(s));
}

//---------------------------------------------------------
// setPlainLongNameAll
//---------------------------------------------------------

void Part::setPlainLongNameAll(const String& s)
{
setLongNameAll(XmlWriter::xmlString(s));
}

//---------------------------------------------------------
// setPlainShortNameAll
//---------------------------------------------------------

void Part::setPlainShortNameAll(const String& s)
{
setShortNameAll(XmlWriter::xmlString(s));
}

//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions src/engraving/dom/part.h
Expand Up @@ -114,9 +114,13 @@ class Part final : public EngravingObject

void setLongName(const String& s);
void setShortName(const String& s);
void setLongNameAll(const String& s); // For all instruments in _instruments
void setShortNameAll(const String& s); // For all instruments in _instruments

void setPlainLongName(const String& s);
void setPlainShortName(const String& s);
void setPlainLongNameAll(const String& s);
void setPlainShortNameAll(const String& s);

void setStaves(int);

Expand Down
12 changes: 6 additions & 6 deletions src/engraving/rendering/dev/lyricslayout.cpp
Expand Up @@ -381,17 +381,17 @@ void LyricsLayout::layout(LyricsLineSegment* item, LayoutContext& ctx)

// VERTICAL POSITION: at the base line of the syllable text
if (!item->isEndType()) {
ldata->setPosY(lyr->ldata()->pos().y());
item->ryoffset() = lyr->offset().y();
ldata->setPosY(lyr->ldata()->pos().y() + lyr->chordRest()->pos().y());
item->ryoffset() = lyr->offset().y() + lyr->chordRest()->offset().y();
} else {
// use Y position of *next* syllable if there is one on same system
Lyrics* nextLyr1 = searchNextLyrics(lyr->segment(), lyr->staffIdx(), lyr->no(), lyr->placement());
if (nextLyr1 && nextLyr1->segment()->system() == item->system()) {
ldata->setPosY(nextLyr1->ldata()->pos().y());
item->ryoffset() = nextLyr1->offset().y();
ldata->setPosY(nextLyr1->ldata()->pos().y() + nextLyr1->chordRest()->pos().y());
item->ryoffset() = nextLyr1->offset().y() + nextLyr1->chordRest()->offset().y();
} else {
ldata->setPosY(lyr->ldata()->pos().y());
item->ryoffset() = lyr->offset().y();
ldata->setPosY(lyr->ldata()->pos().y() + lyr->chordRest()->pos().y());
item->ryoffset() = lyr->offset().y() + lyr->chordRest()->offset().y();
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/engraving/rendering/dev/systemlayout.cpp
Expand Up @@ -1086,8 +1086,11 @@ void SystemLayout::layoutSystemElements(System* system, LayoutContext& ctx)

LyricsLayout::layoutLyrics(ctx, system);

// here are lyrics dashes and melisma
for (Spanner* sp : ctx.dom().unmanagedSpanners()) {
// Layout lyrics dashes and melisma
// NOTE: loop on a *copy* of unmanagedSpanners because in some cases
// the underlying operation may invalidate some of the iterators.
std::set<Spanner*> unmanagedSpanners = ctx.dom().unmanagedSpanners();
for (Spanner* sp : unmanagedSpanners) {
if (sp->tick() >= etick || sp->tick2() <= stick) {
continue;
}
Expand Down
59 changes: 51 additions & 8 deletions src/importexport/musicxml/internal/musicxml/exportxml.cpp
Expand Up @@ -376,7 +376,7 @@ class ExportMusicXml
int findOttava(const Ottava* tl) const;
int findTrill(const Trill* tl) const;
void chord(Chord* chord, staff_idx_t staff, const std::vector<Lyrics*>& ll, bool useDrumset);
void rest(Rest* chord, staff_idx_t staff);
void rest(Rest* chord, staff_idx_t staff, const std::vector<Lyrics*>& ll);
void clef(staff_idx_t staff, const ClefType ct, const QString& extraAttributes = "");
void timesig(TimeSig* tsig);
void keysig(const KeySig* ks, ClefType ct, staff_idx_t staff = 0, bool visible = true);
Expand Down Expand Up @@ -3515,6 +3515,8 @@ static void writeBeam(XmlWriter& xml, ChordRest* const cr, Beam* const b)
int blp = -1; // beam level previous chord
int blc = -1; // beam level current chord
int bln = -1; // beam level next chord
BeamMode bmc = BeamMode::AUTO; // beam mode current chord
BeamMode bmn = BeamMode::AUTO; // beam mode next chord
// find beam level previous chord
for (size_t i = idx - 1; blp == -1 && i != mu::nidx; --i) {
const auto crst = elements[i];
Expand All @@ -3525,26 +3527,34 @@ static void writeBeam(XmlWriter& xml, ChordRest* const cr, Beam* const b)
// find beam level current chord
if (cr->isChord()) {
blc = toChord(cr)->beams();
bmc = toChord(cr)->beamMode();
}
// find beam level next chord
for (size_t i = idx + 1; bln == -1 && i < elements.size(); ++i) {
const auto crst = elements[i];
if (crst->isChord()) {
bln = toChord(crst)->beams();
bmn = toChord(crst)->beamMode();
}
}
// find beam type and write
for (int i = 1; i <= blc; ++i) {
QString text;
if (blp < i && bln >= i) {
// TODO: correctly handle Beam::Mode::AUTO
// when equivalent to BEGIN32 or BEGIN64
if ((blp < i && bln >= i)
|| bmc == BeamMode::BEGIN16 && i > 1
|| bmc == BeamMode::BEGIN32 && i > 2) {
text = "begin";
} else if (blp < i && bln < i) {
if (bln > 0) {
text = "forward hook";
} else if (blp > 0) {
text = "backward hook";
}
} else if (blp >= i && bln < i) {
} else if ((blp >= i && bln < i)
|| bmn == BeamMode::BEGIN16 && i > 1
|| bmn == BeamMode::BEGIN32 && i > 2) {
text = "end";
} else if (blp >= i && bln >= i) {
text = "continue";
Expand Down Expand Up @@ -3788,7 +3798,7 @@ static bool isSmallNote(const Note* const note)

static bool isCueNote(const Note* const note)
{
return (!note->chord()->isGrace()) && isSmallNote(note) && !note->play();
return isSmallNote(note) && !note->play();
}

//---------------------------------------------------------
Expand Down Expand Up @@ -3831,6 +3841,8 @@ static void writeTypeAndDots(XmlWriter& xml, const Note* const note)
// small notes are indicated by size=cue, but for grace and cue notes this is implicit
if (isSmallNote(note) && !isCueNote(note) && !note->chord()->isGrace()) {
xml.tag("type", { { "size", "cue" } }, s);
} else if (isSmallNote(note) && !isCueNote(note) && note->chord()->isGrace()) {
xml.tag("type", { { "size", "grace-cue" } }, s);
} else {
xml.tag("type", s);
}
Expand Down Expand Up @@ -4152,7 +4164,7 @@ void ExportMusicXml::chord(Chord* chord, staff_idx_t staff, const std::vector<Ly
For a single-staff part, \a staff equals zero, suppressing the <staff> element.
*/

void ExportMusicXml::rest(Rest* rest, staff_idx_t staff)
void ExportMusicXml::rest(Rest* rest, staff_idx_t staff, const std::vector<Lyrics*>& ll)
{
static char table2[] = "CDEFGAB";
#ifdef DEBUG_TICK
Expand Down Expand Up @@ -4267,6 +4279,8 @@ void ExportMusicXml::rest(Rest* rest, staff_idx_t staff)
tupletStartStop(rest, notations, _xml);
notations.etag(_xml);

lyrics(ll, rest->track());

_xml.endElement();
}

Expand Down Expand Up @@ -5072,14 +5086,42 @@ void ExportMusicXml::ottava(Ottava const* const ot, staff_idx_t staff, const Fra

void ExportMusicXml::pedal(Pedal const* const pd, staff_idx_t staff, const Fraction& tick)
{
// "change" type is handled only on the beginning of pedal lines
if (pd->tick() != tick && pd->endHookType() == HookType::HOOK_45) {
return;
}

directionTag(_xml, _attr, pd);
_xml.startElement("direction-type");
QString pedalType;
QString pedalXml;
QString signText;
QString lineText = pd->lineVisible() ? " line=\"yes\"" : " line=\"no\"";
if (pd->tick() == tick) {
pedalXml = "pedal type=\"start\" line=\"yes\"";
switch (pd->beginHookType()) {
case HookType::HOOK_45:
pedalType = "change";
break;
case HookType::NONE:
pedalType = "resume";
break;
default:
pedalType = "start";
}
signText = pd->beginText() == "" ? " sign=\"no\"" : " sign=\"yes\"";
} else {
pedalXml = "pedal type=\"stop\" line=\"yes\"";
if (!pd->endText().isEmpty() || pd->endHookType() == HookType::HOOK_90) {
pedalType = "stop";
} else {
pedalType = "discontinue";
}
// "change" type is handled only on the beginning of pedal lines

signText = pd->endText() == "" ? " sign=\"no\"" : " sign=\"yes\"";
}
pedalXml = QString("pedal type=\"%1\"").arg(pedalType);
pedalXml += lineText;
pedalXml += signText;
pedalXml += positioningAttributes(pd, pd->tick() == tick);
_xml.tagRaw(pedalXml);
_xml.endElement();
Expand Down Expand Up @@ -7067,7 +7109,8 @@ void ExportMusicXml::writeElement(EngravingItem* el, const Measure* m, staff_idx
} else if (el->isRest()) {
const auto r = toRest(el);
if (!(r->isGap())) {
rest(r, sstaff);
const auto ll = r->lyrics();
rest(r, sstaff, ll);
}
} else if (el->isBarLine()) {
const auto barln = toBarLine(el);
Expand Down
Expand Up @@ -143,13 +143,9 @@ QString mxmlNoteDuration::checkTiming(const QString& type, const bool rest, cons
errorStr = "";
_dura = _specDura;
} else {
// note:
// rounding error detection may conflict with changed duration detection (Overture).
// exporters that intentionally change note duration typically produce a large difference,
// most likely in practice this will not be an issue
const int maxDiff = 2; // maximum difference considered a rounding error
if (qAbs(_calcDura.ticks() - _specDura.ticks()) <= maxDiff) {
if (qAbs(_calcDura.ticks() - _specDura.ticks()) <= _pass1->maxDiff()) {
errorStr += " -> assuming rounding error";
_pass1->insertAdjustedDuration(_dura, _calcDura);
_dura = _calcDura;
_specDura = _calcDura; // prevent changing off time
} else {
Expand Down Expand Up @@ -186,6 +182,7 @@ QString mxmlNoteDuration::checkTiming(const QString& type, const bool rest, cons
_dura = Fraction(4, 4);
}

_pass1->insertSeenDenominator(_dura.reduced().denominator());
return errorStr;
}

Expand All @@ -203,17 +200,7 @@ void mxmlNoteDuration::duration(QXmlStreamReader& e)

_specDura.set(0, 0); // invalid unless set correctly
int intDura = e.readElementText().toInt();
if (intDura > 0) {
if (_divs > 0) {
_specDura.set(intDura, 4 * _divs);
_specDura.reduce(); // prevent overflow in later Fraction operations
} else {
_logger->logError("illegal or uninitialized divisions", &e);
}
} else {
_logger->logError("illegal duration", &e);
}
//LOGD("specified duration %s valid %d", qPrintable(_specDura.print()), _specDura.isValid());
_specDura = _pass1->calcTicks(intDura, &e); // Duration reading (and rounding) code consolidated to pass1
}

//---------------------------------------------------------
Expand Down
Expand Up @@ -25,6 +25,7 @@

#include "engraving/dom/durationtype.h"
#include "engraving/types/fraction.h"
#include "importmxmlpass1.h"

namespace mu::engraving {
class MxmlLogger;
Expand All @@ -40,8 +41,8 @@ class MxmlLogger;
class mxmlNoteDuration
{
public:
mxmlNoteDuration(int divs, MxmlLogger* logger)
: _divs(divs), _logger(logger) { /* nothing so far */ }
mxmlNoteDuration(int divs, MxmlLogger* logger, MusicXMLParserPass1* pass1)
: _divs(divs), _logger(logger), _pass1(pass1) { /* nothing so far */ }
QString checkTiming(const QString& type, const bool rest, const bool grace);
Fraction duration() const { return _dura; } // duration to use
Fraction calculatedDuration() const { return _calcDura; } // value calculated from note type etcetera
Expand All @@ -61,6 +62,7 @@ class mxmlNoteDuration
Fraction _dura;
TDuration _normalType;
Fraction _timeMod { 1, 1 }; // default to no time modification
MusicXMLParserPass1* _pass1;
MxmlLogger* _logger; ///< Error logger
};
} // namespace Ms
Expand Down

0 comments on commit e2fe70b

Please sign in to comment.