Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Porting a bunch of old musicXML fixes #19972

Merged
merged 39 commits into from Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2dcda2f
Port Fix beams in multi-voice MusicXML import
mike-spa Oct 30, 2023
31bdb5d
Port Change non-end melismas to hyphens
mike-spa Oct 31, 2023
e6586f6
Port Fix barlines on multi-staff parts
mike-spa Oct 31, 2023
2375788
Port Fix small chords on MusicXML import
mike-spa Oct 31, 2023
ef990b7
Port Add partial default-y support
mike-spa Oct 31, 2023
4dc5ba0
Port Pedal change elements ignored
mike-spa Oct 31, 2023
c9133e0
Port Handle unterminated pedal markings
mike-spa Oct 31, 2023
2198149
Port Crash caused by importing negative offset
mike-spa Oct 31, 2023
56e5ffa
Port Add space between tempo text and metro
mike-spa Oct 31, 2023
cd6e0bb
Port Improve placement defaults
mike-spa Nov 3, 2023
2d741e3
Port Correctly omit instrument names
mike-spa Nov 3, 2023
8aa8433
Port Add inferencing for incorrect part names
mike-spa Nov 3, 2023
405a8f2
Port Infer subtitles
mike-spa Nov 6, 2023
8487102
Port Change inferred credits to composer
mike-spa Nov 6, 2023
44f5bc3
Port Correct import of coda symbols
mike-spa Nov 6, 2023
9dda825
Port Fix second-line melisma issue
mike-spa Nov 6, 2023
29d2b17
Port Fix melisma y position
mike-spa Nov 6, 2023
09f8760
Port Another small melisma fix
mike-spa Nov 6, 2023
1c47d1f
Port Add support for "wavy" type brackets
mike-spa Nov 7, 2023
5b073ee
Port Fix missing secondary beam breaks
mike-spa Nov 7, 2023
06c65ba
Port Properly handle cue grace notes
mike-spa Nov 7, 2023
be2c111
Port Repeat text on incorrect side of barline
mike-spa Nov 7, 2023
8106efb
Port Remove lyric bracket StaffText
mike-spa Nov 7, 2023
a58e2d9
Port Infer NmiCmi to N.C.
mike-spa Nov 7, 2023
e6915b1
Port Infer $ and Ø to segno and coda on read
mike-spa Nov 7, 2023
d9aa007
Port Fix parts with excessive hidden staves
mike-spa Nov 8, 2023
e1bad71
Port Fix barline and brace spanning > 2 staves
mike-spa Nov 8, 2023
a62b25c
Port Fix import of default pedal
mike-spa Nov 8, 2023
2fdd873
Port Fix part names unhiding when multiple instruments
mike-spa Nov 8, 2023
2ec31f1
Port Change VoiceList key from QString to int
mike-spa Nov 8, 2023
8473727
Port Improve tuplet rounding error correction
mike-spa Nov 8, 2023
e6eedea
Port Fix wedges with <offset> values
mike-spa Nov 8, 2023
e55d5a8
Codestyle fix
mike-spa Nov 8, 2023
5d17166
Remove QString
mike-spa Nov 8, 2023
a63c534
Fix unit tests on "poet" tag
mike-spa Nov 14, 2023
9006041
N.C. correction
mike-spa Nov 15, 2023
5e50247
Override text style for composer credit
mike-spa Nov 15, 2023
8b37598
Fix crash on lyrics line layout
mike-spa Nov 16, 2023
bd7c5b3
Rebase fixes
mike-spa Nov 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better swap this with the next to avoid a warning reg. wrong order of initialisation

MxmlLogger* _logger; ///< Error logger
};
} // namespace Ms
Expand Down