Skip to content

Commit

Permalink
Fix #321753 - [MusicXML import] enable import of MusicXML note durati…
Browse files Browse the repository at this point in the history
…on to set duration as shown in the piano roll editor

See discussion in https://musescore.org/en/node/313339. This change enables correct import of Overture files containing
changed note durations (while leaving the note type unchanged) by using the duration to change the note's off time.
Strictly speaking Overture does not adhere to the MusicMXL spec, but this change does not seem to introduce any regression.
If necessary it can be made optional in future (either as a user setting or by making it Overture specific).

Duplicate of musescore#8282, resp. backport of musescore#8429, part 2
  • Loading branch information
lvinken authored and Jojo-Schmitz committed Sep 1, 2021
1 parent 9449218 commit f4886d9
Show file tree
Hide file tree
Showing 7 changed files with 836 additions and 4 deletions.
1 change: 1 addition & 0 deletions importexport/musicxml/importmxmlnoteduration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ QString mxmlNoteDuration::checkTiming(const QString& type, const bool rest, cons
if (qAbs(_calcDura.ticks() - _specDura.ticks()) <= maxDiff) {
errorStr += " -> assuming rounding error";
_dura = _calcDura;
_specDura = _calcDura; // prevent changing off time
}
else
errorStr += " -> using calculated duration";
Expand Down
19 changes: 19 additions & 0 deletions importexport/musicxml/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5601,6 +5601,25 @@ Note* MusicXMLParserPass2::note(const QString& partId,
addGraceChordsBefore(c, gcl);
}

if (mnd.calculatedDuration().isValid()
&& mnd.specifiedDuration().isValid()
&& mnd.calculatedDuration().isNotZero()
&& mnd.calculatedDuration() != mnd.specifiedDuration()) {

// convert duration into note length
Fraction durationMult { (mnd.specifiedDuration() / mnd.calculatedDuration()).reduced() };
durationMult = (1000 * durationMult).reduced();
const int noteLen = durationMult.numerator() / durationMult.denominator();

NoteEventList nel;
NoteEvent ne;
ne.setLen(noteLen);
nel.append(ne);
note->setPlayEvents(nel);
if (c)
c->setPlayEventType(PlayEventType::User);
}

if (velocity > 0) {
note->setVeloType(Note::ValueType::USER_VAL);
note->setVeloOffset(velocity);
Expand Down
163 changes: 161 additions & 2 deletions mtest/musicxml/io/testDurationLargeError.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@
<miscellaneous>
<miscellaneous-field name="description">
Test handling of large errors in durations (larger than rounding errors).
Expect MuseScore to use the calculated duration, resulting in a normal
MusicXML file (with divsions 1 and duration 2 for the half notes).
Expected result in MuseScore:
Measure 1 G4: off time 0.9
Measure 2 B4: off time 1.1
Measure 3 C4: off time 1.008
Measure 3 D4: off time 1.006
Measure 4 C5: off time 0.993
All other notes: no changed off time
MuseScore will use the calculated duration, resulting (on export) in a
normal MusicXML file (with divsions 1 and duration 2 for the half notes).
</miscellaneous-field>
</miscellaneous>
</identification>
Expand Down Expand Up @@ -98,6 +105,158 @@
<type>half</type>
<stem>down</stem>
</note>
</measure>
<measure number="3">
<attributes>
<divisions>480</divisions>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>4</octave>
</pitch>
<duration>484</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>D</step>
<octave>4</octave>
</pitch>
<duration>483</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>482</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>F</step>
<octave>4</octave>
</pitch>
<duration>481</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
</measure>
<measure number="4">
<note>
<pitch>
<step>G</step>
<octave>4</octave>
</pitch>
<duration>480</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>A</step>
<octave>4</octave>
</pitch>
<duration>479</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>B</step>
<octave>4</octave>
</pitch>
<duration>478</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>C</step>
<octave>5</octave>
</pitch>
<duration>477</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
</measure>
<measure number="5">
<attributes>
<divisions>100</divisions>
</attributes>
<note>
<rest/>
<duration>80</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<rest/>
<duration>100</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<rest/>
<duration>120</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<rest/>
<duration>140</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
</measure>
<measure number="6">
<attributes>
<divisions>1</divisions>
</attributes>
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>G</step>
<octave>4</octave>
</pitch>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
<stem>up</stem>
</note>
<note>
<pitch>
<step>A</step>
<octave>4</octave>
</pitch>
<duration>2</duration>
<voice>1</voice>
<type>half</type>
<stem>up</stem>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
Expand Down
Loading

0 comments on commit f4886d9

Please sign in to comment.