Skip to content

Commit 3cc1c86

Browse files
authored
Merge pull request #6866 from AntonioBL/xmltremolotuplet3x
[MU3] [Musicxml Export] - Wrong tuplet calculation in two-note tremolo
2 parents 2b39650 + 1773728 commit 3cc1c86

File tree

5 files changed

+243
-11
lines changed

5 files changed

+243
-11
lines changed

importexport/musicxml/exportxml.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2253,10 +2253,13 @@ static void tupletStop(const Tuplet* const t, const int number, Notations& notat
22532253
// tupletStartStop
22542254
//---------------------------------------------------------
22552255

2256-
static void tupletStartStop(const ChordRest* const cr, Notations& notations, XmlWriter& xml)
2256+
static void tupletStartStop(ChordRest* cr, Notations& notations, XmlWriter& xml)
22572257
{
22582258
const auto nesting = tupletNesting(cr);
2259-
const bool doActualAndNormal = (nesting > 1);
2259+
bool doActualAndNormal = (nesting > 1);
2260+
if (cr->isChord() && isTwoNoteTremolo(toChord(cr))) {
2261+
doActualAndNormal = true;
2262+
}
22602263
for (int level = nesting - 1; level >= 0; --level) {
22612264
const auto startTuplet = startTupletAtLevel(cr, level + 1);
22622265
if (startTuplet)

importexport/musicxml/importmxmlpass2.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -864,9 +864,9 @@ static Fraction calculateTupletDuration(const Tuplet* const t)
864864
foreach (DurationElement* de, t->elements()) {
865865
if (de->type() == ElementType::CHORD || de->type() == ElementType::REST) {
866866
const auto cr = static_cast<ChordRest*>(de);
867-
const auto durationType = cr->actualDurationType();
868-
if (durationType.isValid() && !durationType.isMeasure()) {
869-
res += durationType.fraction();
867+
const auto fraction = cr->ticks(); // TODO : take care of nested tuplets
868+
if (fraction.isValid()) {
869+
res += fraction;
870870
}
871871
}
872872
}
@@ -914,7 +914,7 @@ static void handleTupletStart(const ChordRest* const cr, Tuplet*& tuplet,
914914
tuplet = new Tuplet(cr->score());
915915
tuplet->setTrack(cr->track());
916916
tuplet->setRatio(Fraction(actualNotes, normalNotes));
917-
// tuplet->setTick(cr->tick());
917+
tuplet->setTick(cr->tick());
918918
tuplet->setBracketType(tupletDesc.bracket);
919919
tuplet->setNumberType(tupletDesc.shownumber);
920920
// TODO type, placement, bracket
@@ -4065,7 +4065,8 @@ static void addFiguredBassElemens(FiguredBassList& fbl, const Fraction noteStart
40654065
static void addTremolo(ChordRest* cr,
40664066
const int tremoloNr, const QString& tremoloType,
40674067
Chord*& tremStart,
4068-
MxmlLogger* logger, const QXmlStreamReader* const xmlreader)
4068+
MxmlLogger* logger, const QXmlStreamReader* const xmlreader,
4069+
Fraction& timeMod)
40694070
{
40704071
if (!cr->isChord())
40714072
return;
@@ -4085,6 +4086,10 @@ static void addTremolo(ChordRest* cr,
40854086
else if (tremoloType == "start") {
40864087
if (tremStart) logger->logError("MusicXML::import: double tremolo start", xmlreader);
40874088
tremStart = static_cast<Chord*>(cr);
4089+
// timeMod takes into account also the factor 2 of a two-note tremolo
4090+
if (timeMod.isValid() && ((timeMod.denominator() % 2) == 0)) {
4091+
timeMod.setDenominator(timeMod.denominator() / 2);
4092+
}
40884093
}
40894094
else if (tremoloType == "stop") {
40904095
if (tremStart) {
@@ -4104,6 +4109,10 @@ static void addTremolo(ChordRest* cr,
41044109
tremolo->chord2()->setTicks(tremDur);
41054110
// add tremolo to first chord (only)
41064111
tremStart->add(tremolo);
4112+
// timeMod takes into account also the factor 2 of a two-note tremolo
4113+
if (timeMod.isValid() && ((timeMod.denominator() % 2) == 0)) {
4114+
timeMod.setDenominator(timeMod.denominator() / 2);
4115+
}
41074116
}
41084117
else logger->logError("MusicXML::import: double tremolo stop w/o start", xmlreader);
41094118
tremStart = nullptr;
@@ -4350,7 +4359,7 @@ Note* MusicXMLParserPass2::note(const QString& partId,
43504359
// - sTime for non-chord / first chord note
43514360
// - prevTime for others
43524361
auto noteStartTime = chord ? prevSTime : sTime;
4353-
const auto timeMod = mnd.timeMod();
4362+
auto timeMod = mnd.timeMod();
43544363

43554364
// determine tuplet state, used twice (before and after note allocation)
43564365
MxmlTupletFlags tupletAction;
@@ -4524,6 +4533,11 @@ Note* MusicXMLParserPass2::note(const QString& partId,
45244533
gac = gcl.size();
45254534
}
45264535

4536+
// handle tremolo before handling tuplet (two note tremolos modify timeMod)
4537+
if (cr) {
4538+
addTremolo(cr, notations.tremoloNr(), notations.tremoloType(), _tremStart, _logger, &_e, timeMod);
4539+
}
4540+
45274541
// handle tuplet state for the current chord or rest
45284542
if (cr) {
45294543
if (!chord && !grace) {
@@ -4574,9 +4588,6 @@ Note* MusicXMLParserPass2::note(const QString& partId,
45744588

45754589
// add figured bass element
45764590
addFiguredBassElemens(fbl, noteStartTime, msTrack, dura, measure);
4577-
if (cr) {
4578-
addTremolo(cr, notations.tremoloNr(), notations.tremoloType(), _tremStart, _logger, &_e);
4579-
}
45804591

45814592
// don't count chord or grace note duration
45824593
// note that this does not check the MusicXML requirement that notes in a chord
16.9 KB
Binary file not shown.
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
3+
<score-partwise version="3.1">
4+
<work>
5+
<work-number>MuseScore testfile</work-number>
6+
<work-title>Test</work-title>
7+
</work>
8+
<identification>
9+
<encoding>
10+
<software>MuseScore 0.7.0</software>
11+
<encoding-date>2007-09-10</encoding-date>
12+
<supports element="accidental" type="yes"/>
13+
<supports element="beam" type="yes"/>
14+
<supports element="print" attribute="new-page" type="no"/>
15+
<supports element="print" attribute="new-system" type="no"/>
16+
<supports element="stem" type="yes"/>
17+
</encoding>
18+
</identification>
19+
<part-list>
20+
<score-part id="P1">
21+
<part-name>Piano</part-name>
22+
<part-abbreviation>Pno.</part-abbreviation>
23+
<score-instrument id="P1-I1">
24+
<instrument-name>Piano</instrument-name>
25+
</score-instrument>
26+
<midi-device id="P1-I1" port="1"></midi-device>
27+
<midi-instrument id="P1-I1">
28+
<midi-channel>1</midi-channel>
29+
<midi-program>1</midi-program>
30+
<volume>78.7402</volume>
31+
<pan>0</pan>
32+
</midi-instrument>
33+
</score-part>
34+
</part-list>
35+
<part id="P1">
36+
<measure number="1">
37+
<attributes>
38+
<divisions>12</divisions>
39+
<key>
40+
<fifths>0</fifths>
41+
</key>
42+
<time>
43+
<beats>4</beats>
44+
<beat-type>4</beat-type>
45+
</time>
46+
<clef>
47+
<sign>G</sign>
48+
<line>2</line>
49+
</clef>
50+
</attributes>
51+
<note>
52+
<pitch>
53+
<step>A</step>
54+
<octave>4</octave>
55+
</pitch>
56+
<duration>12</duration>
57+
<voice>1</voice>
58+
<type>half</type>
59+
<time-modification>
60+
<actual-notes>2</actual-notes>
61+
<normal-notes>1</normal-notes>
62+
</time-modification>
63+
<stem>up</stem>
64+
<notations>
65+
<ornaments>
66+
<tremolo type="start">1</tremolo>
67+
</ornaments>
68+
</notations>
69+
</note>
70+
<note>
71+
<pitch>
72+
<step>C</step>
73+
<octave>5</octave>
74+
</pitch>
75+
<duration>12</duration>
76+
<voice>1</voice>
77+
<type>half</type>
78+
<time-modification>
79+
<actual-notes>2</actual-notes>
80+
<normal-notes>1</normal-notes>
81+
</time-modification>
82+
<stem>down</stem>
83+
<notations>
84+
<ornaments>
85+
<tremolo type="stop">1</tremolo>
86+
</ornaments>
87+
</notations>
88+
</note>
89+
<note>
90+
<pitch>
91+
<step>E</step>
92+
<octave>5</octave>
93+
</pitch>
94+
<duration>6</duration>
95+
<voice>1</voice>
96+
<type>quarter</type>
97+
<time-modification>
98+
<actual-notes>2</actual-notes>
99+
<normal-notes>1</normal-notes>
100+
</time-modification>
101+
<stem>down</stem>
102+
<notations>
103+
<ornaments>
104+
<tremolo type="start">1</tremolo>
105+
</ornaments>
106+
</notations>
107+
</note>
108+
<note>
109+
<pitch>
110+
<step>G</step>
111+
<octave>5</octave>
112+
</pitch>
113+
<duration>6</duration>
114+
<voice>1</voice>
115+
<type>quarter</type>
116+
<time-modification>
117+
<actual-notes>2</actual-notes>
118+
<normal-notes>1</normal-notes>
119+
</time-modification>
120+
<stem>down</stem>
121+
<notations>
122+
<ornaments>
123+
<tremolo type="stop">1</tremolo>
124+
</ornaments>
125+
</notations>
126+
</note>
127+
<note>
128+
<rest/>
129+
<duration>12</duration>
130+
<voice>1</voice>
131+
<type>quarter</type>
132+
</note>
133+
</measure>
134+
<measure number="2">
135+
<note>
136+
<pitch>
137+
<step>C</step>
138+
<octave>5</octave>
139+
</pitch>
140+
<duration>8</duration>
141+
<voice>1</voice>
142+
<type>half</type>
143+
<time-modification>
144+
<actual-notes>6</actual-notes>
145+
<normal-notes>2</normal-notes>
146+
</time-modification>
147+
<stem>down</stem>
148+
<notations>
149+
<tuplet type="start" bracket="yes">
150+
<tuplet-actual>
151+
<tuplet-number>3</tuplet-number>
152+
<tuplet-type>quarter</tuplet-type>
153+
</tuplet-actual>
154+
<tuplet-normal>
155+
<tuplet-number>2</tuplet-number>
156+
<tuplet-type>quarter</tuplet-type>
157+
</tuplet-normal>
158+
</tuplet>
159+
<ornaments>
160+
<tremolo type="start">1</tremolo>
161+
</ornaments>
162+
</notations>
163+
</note>
164+
<note>
165+
<pitch>
166+
<step>E</step>
167+
<octave>5</octave>
168+
</pitch>
169+
<duration>8</duration>
170+
<voice>1</voice>
171+
<type>half</type>
172+
<time-modification>
173+
<actual-notes>6</actual-notes>
174+
<normal-notes>2</normal-notes>
175+
</time-modification>
176+
<stem>down</stem>
177+
<notations>
178+
<ornaments>
179+
<tremolo type="stop">1</tremolo>
180+
</ornaments>
181+
</notations>
182+
</note>
183+
<note>
184+
<pitch>
185+
<step>G</step>
186+
<octave>5</octave>
187+
</pitch>
188+
<duration>8</duration>
189+
<voice>1</voice>
190+
<type>quarter</type>
191+
<time-modification>
192+
<actual-notes>3</actual-notes>
193+
<normal-notes>2</normal-notes>
194+
</time-modification>
195+
<stem>down</stem>
196+
<notations>
197+
<tuplet type="stop"/>
198+
</notations>
199+
</note>
200+
<note>
201+
<rest/>
202+
<duration>12</duration>
203+
<voice>1</voice>
204+
<type>quarter</type>
205+
</note>
206+
<note>
207+
<rest/>
208+
<duration>12</duration>
209+
<voice>1</voice>
210+
<type>quarter</type>
211+
</note>
212+
<barline location="right">
213+
<bar-style>light-heavy</bar-style>
214+
</barline>
215+
</measure>
216+
</part>
217+
</score-partwise>

mtest/musicxml/io/tst_mxml_io.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ private slots:
196196
void tuplets6() { mxmlIoTestRef("testTuplets6"); }
197197
void tuplets7() { mxmlIoTest("testTuplets7"); }
198198
void tuplets8() { mxmlMscxExportTestRef("testTuplets8"); }
199+
void twoNoteTremoloTuplet() { mxmlIoTest("testTwoNoteTremoloTuplet"); }
199200
void uninitializedDivisions() { mxmlIoTestRef("testUninitializedDivisions"); }
200201
void unusualDurations() { mxmlIoTestRef("testUnusualDurations"); }
201202
void virtualInstruments() { mxmlIoTestRef("testVirtualInstruments"); }

0 commit comments

Comments
 (0)