Score unreadable, reports negative measure length

• Aug 7, 2021 - 23:29
Reported version
3.6
Type
Functional
Frequency
Many
Severity
S2 - Critical
Reproducibility
Once
Status
needs info
Regression
Yes
Workaround
Yes
Project

Bonjour,
Lors de la saisie, le programme a planté et la partition est devenue illisible.
Merci pour toute aide me permettant de la récupérer

Attachment Size
Donald Covay - Chain Of Fools.mscz 28.59 KB

Comments

Title Plantage Muscore et partition devenue illisible Muscore crash and partition become unreadable
Severity S1 - Blocker S2 - Critical

Translation:
When typing, the program crashed and the score became unreadable.
Thank you for any help allowing me to recover it

First fix, extracting the mscx from the msxz (it is a ZIP archive in disguise), opening it with a plain text editor, searching and deleting all negative measure durations (just the - sign), moving it back into the mscz.
Opening that now does reports corruptions:

Measure 48, Staff 1 incomplete. Expected: 4/4; Found: 6/4
Measure 48, Staff 2 incomplete. Expected: 4/4; Found: 6/4
Measure 48, Staff 3 incomplete. Expected: 4/4; Found: 6/4
Measure 50, Staff 1 incomplete. Expected: 8/16; Found: 0/1
Measure 50, Staff 3 incomplete. Expected: 8/16; Found: 0/1

but allows to open it anyway, by using the "Ignore" button.
Now see How to fix a score that contains corruptions

Attachment Size
Donald Covay - Chain Of Fools.mscz 30.31 KB
Status active needs info

This is not the first report with these symptoms, I can't find the others though currently, but there were at least 3 more, possible in the forum rather than the issue tracker?

Any idea how you managed to get the score into that condition?

Title Muscore crash and partition become unreadable Muscore crash and partition become unreadable due to negative measure durations
Title Muscore crash and partition become unreadable due to negative measure durations Score unreadable, reports negative measure durations
Title Score unreadable, reports negative measure durations Muscore crash and partition become unreadable
Status needs info active

Unpacking the saved score to retrieve the mscx file, reveals an measure length of -8/16. Possibly an underlying bug; saving a negative measure length?

Title Muscore crash and partition become unreadable Score unreadable, reports negative measure durations
Status active needs info

Possibly, even surely a bug, but we'd need steps to reproduce

It is supposed to be a true (and positive) "fraction", the actual measure duration, like len="8/16", and only gets written for measures that have a different duration than what the time signature asks for (measure.cpp):

void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool forceTimeSig) const
      {
      if (MScore::debugMode) {
            const int mno = no() + 1;
            xml.comment(QString("Measure %1").arg(mno));
            }
      if (_len != _timesig) {
            // this is an irregular measure
            xml.stag(this, QString("len=\"%1/%2\"").arg(_len.numerator()).arg(_len.denominator()));
            }
      else
            xml.stag(this);

Maybe we'd better just report that error as a corruption and on "Ignore" remove the -, rather than denying to read the score entirely.

Maybe we should make sure on writing a score that the numerator never gets (written as) negative. Actually as per the code this shouldn't happen for fractions (fraction.h):

      constexpr Fraction(int z, int n) : _numerator { n < 0 ? -z : z }, _denominator { n < 0 ? -n : n } { }

but might for the numerator (also fraction.h):

      void setNumerator(int v)   { _numerator = v;              }
      void setDenominator(int v) {
            if (v < 0) { _numerator = -_numerator; _denominator = -v; }
            else _denominator = v;
            }
      void set(int z, int n)     {
            if (n < 0)  { _numerator = -z; _denominator = -n; }
            else { _numerator = z; _denominator = n; }
            }

No idea why setNumerator() doesn't use the same mechanism as setDenominator()?!? Or is that the place where it goes horribly wrong?

The error on read is reported here (measure.cpp):

      bool irregular;
      if (e.hasAttribute("len")) {
            QStringList sl = e.attribute("len").split('/');
            if (sl.size() == 2)
                  _len = Fraction(sl[0].toInt(), sl[1].toInt());
            else
                  qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
            irregular = true;
            if (_len.numerator() <= 0 || _len.denominator() <= 0) {
                  e.raiseError(QObject::tr("MSCX error at line %1: invalid measure length: %2").arg(e.lineNumber()).arg(_len.toString()));
                  return;
                  }
            score()->sigmap()->add(tick().ticks(), SigEvent(_len, _timesig));
            score()->sigmap()->add((tick() + ticks()).ticks(), SigEvent(_timesig));
            }

So in addition to not allow for negative values, 0 is not allowed either.
So it should never get written in the first place!

Much better though would be to prevent this from happening at all. But as mentioned: for that we'd need steps to reproduce.