Skip to content

Commit

Permalink
Round tempo to 2 decimal places in MusicXML export
Browse files Browse the repository at this point in the history
Since MuseScore internally stores tempo in units of 'beats per seconds'
and truncates it to a fixed precision, the exported MusicXML tempo
was sometimes incorrectly rounded. For example, 92 BPM in MuseScore
was exported as 91.9998 and 88 BPM was exported as 88.0002.

To eliminate this error, tempo is now rounded to up to 2 decimal places
when exporting. Since the MuseScore interface itself only allows up to
2 decimal places (in the Inspector), this is not expected to limit any
users.
  • Loading branch information
matangover authored and vpereverzev committed Feb 4, 2021
1 parent 996eb7d commit 73e60ea
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 2 deletions.
6 changes: 5 additions & 1 deletion importexport/musicxml/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3959,7 +3959,11 @@ void ExportMusicXml::tempoText(TempoText const* const text, int staff)

if (staff)
_xml.tag("staff", staff);
_xml.tagE(QString("sound tempo=\"%1\"").arg(QString::number(text->tempo()*60.0)));
// Format tempo with maximum 2 decimal places, because in some MuseScore files tempo is stored
// imprecisely and this could cause rounding errors (e.g. 92 BPM would be saved as 91.9998).
qreal bpm = text->tempo() * 60.0;
qreal bpmRounded = round(bpm * 100) / 100;
_xml.tagE(QString("sound tempo=\"%1\"").arg(QString::number(bpmRounded)));
_xml.etag();
}

Expand Down
2 changes: 1 addition & 1 deletion mtest/musicxml/io/testDirections2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
<words font-weight="bold" font-size="12">Andante</words>
</direction-type>
<offset>-3</offset>
<sound tempo="91.9998"/>
<sound tempo="92"/>
</direction>
</measure>
<measure number="3">
Expand Down
184 changes: 184 additions & 0 deletions mtest/musicxml/io/testTempoPrecision.mscx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="3.02">
<programVersion>3.6.0</programVersion>
<programRevision>5b046ab</programRevision>
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<pageWidth>8.27</pageWidth>
<pageHeight>11.69</pageHeight>
<enableVerticalSpread>1</enableVerticalSpread>
<Spatium>1.74978</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer">Composer</metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2021-01-17</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Title</metaTag>
<Order id="orchestral" customized="1">
<name>Orchestral</name>
<instrument id="piano">
<family id="keyboards">Keyboards</family>
</instrument>
<section id="woodwind" brackets="true" showSystemMarkings="true" barLineSpan="true" thinBrackets="true">
<family>flutes</family>
<family>oboes</family>
<family>clarinets</family>
<family>saxophones</family>
<family>bassoons</family>
<unsorted group="woodwinds"/>
</section>
<section id="brass" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>horns</family>
<family>trumpets</family>
<family>cornets</family>
<family>trombones</family>
<family>tubas</family>
</section>
<section id="timpani" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>timpani</family>
</section>
<section id="percussion" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>keyboard-percussion</family>
<family>drums</family>
<family>unpitched-metal-percussion</family>
<family>unpitched-wooden-percussion</family>
<family>other-percussion</family>
</section>
<family>keyboards</family>
<family>harps</family>
<family>organs</family>
<family>synths</family>
<section id="plucked-strings" brackets="true" showSystemMarkings="false" barLineSpan="true" thinBrackets="true">
<family>plucked-strings</family>
</section>
<soloists/>
<section id="voices" brackets="true" showSystemMarkings="false" barLineSpan="false" thinBrackets="true">
<family>voices</family>
</section>
<section id="strings" brackets="true" showSystemMarkings="true" barLineSpan="true" thinBrackets="true">
<family>orchestral-strings</family>
</section>
<unsorted/>
</Order>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Piano</trackName>
<Instrument id="piano">
<longName>Piano</longName>
<shortName>Pno.</shortName>
<trackName>Piano</trackName>
<minPitchP>21</minPitchP>
<maxPitchP>108</maxPitchP>
<minPitchA>21</minPitchA>
<maxPitchA>108</maxPitchA>
<instrumentId>keyboard.piano</instrumentId>
<clef staff="2">F</clef>
<Articulation>
<velocity>100</velocity>
<gateTime>95</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>150</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="sforzatoStaccato">
<velocity>150</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoStaccato">
<velocity>120</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoTenuto">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="0"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<Text>
<style>Title</style>
<text>Title</text>
</Text>
<Text>
<style>Composer</style>
<text>Composer</text>
</Text>
</VBox>
<Measure>
<voice>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Tempo>
<tempo>1.46666666666667</tempo>
<followText>1</followText>
<text><b></b><font face="ScoreText"/><b><font face="Edwin"/> = 88</b></text>
</Tempo>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<Tempo>
<tempo>1.53333</tempo>
<text>Andante</text>
</Tempo>
<Rest>
<durationType>measure</durationType>
<duration>4/4</duration>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
83 changes: 83 additions & 0 deletions mtest/musicxml/io/testTempoPrecision_ref.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.1">
<work>
<work-title>Title</work-title>
</work>
<identification>
<creator type="composer">Composer</creator>
<encoding>
<software>MuseScore 0.7.0</software>
<encoding-date>2007-09-10</encoding-date>
<supports element="accidental" type="yes"/>
<supports element="beam" type="yes"/>
<supports element="print" attribute="new-page" type="no"/>
<supports element="print" attribute="new-system" type="no"/>
<supports element="stem" type="yes"/>
</encoding>
</identification>
<part-list>
<score-part id="P1">
<part-name>Piano</part-name>
<part-abbreviation>Pno.</part-abbreviation>
<score-instrument id="P1-I1">
<instrument-name>Piano</instrument-name>
</score-instrument>
<midi-device id="P1-I1" port="1"></midi-device>
<midi-instrument id="P1-I1">
<midi-channel>1</midi-channel>
<midi-program>1</midi-program>
<volume>78.7402</volume>
<pan>0</pan>
</midi-instrument>
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<direction placement="above">
<direction-type>
<metronome parentheses="no">
<beat-unit>quarter</beat-unit>
<per-minute>88</per-minute>
</metronome>
</direction-type>
<sound tempo="88"/>
</direction>
<note>
<rest measure="yes"/>
<duration>4</duration>
<voice>1</voice>
</note>
</measure>
<measure number="2">
<direction placement="above">
<direction-type>
<words font-weight="bold" font-size="12">Andante</words>
</direction-type>
<sound tempo="92"/>
</direction>
<note>
<rest measure="yes"/>
<duration>4</duration>
<voice>1</voice>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
</score-partwise>
1 change: 1 addition & 0 deletions mtest/musicxml/io/tst_mxml_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ private slots:
void tempo3() { mxmlIoTestRef("testTempo3"); }
void tempo4() { mxmlIoTestRef("testTempo4"); }
void tempoOverlap() { mxmlIoTestRef("testTempoOverlap"); }
void tempoPrecision() { mxmlMscxExportTestRef("testTempoPrecision"); }
void textLines() { mxmlMscxExportTestRef("testTextLines"); }
void timesig1() { mxmlIoTest("testTimesig1"); }
void timesig3() { mxmlIoTest("testTimesig3"); }
Expand Down
1 change: 1 addition & 0 deletions mtest/musicxml/io/updateReference
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ cp $S/testTablature3.xml testTablature3.xml
cp $S/testTablature4.xml testTablature4.xml
cp $S/testTablature5.xml testTablature5_ref.xml
cp $S/testBeams3.xml testBeams3_ref.xml
cp $S/testTempoPrecision.xml testTempoPrecision_ref.xml

0 comments on commit 73e60ea

Please sign in to comment.