Skip to content

Commit

Permalink
fix #299492: [Musicxml Export] - Fermata at barline not exported
Browse files Browse the repository at this point in the history
  • Loading branch information
lvinken authored and vpereverzev committed Oct 5, 2020
1 parent ba9e762 commit 075e6b5
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 24 deletions.
121 changes: 97 additions & 24 deletions importexport/musicxml/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ class ExportMusicXml {
void keysig(const KeySig* ks, ClefType ct, int staff = 0, bool visible = true);
void barlineLeft(const Measure* const m);
void barlineMiddle(const BarLine* bl);
void barlineRight(const Measure* const m);
void barlineRight(const Measure* const m, const int strack, const int etrack);
void lyrics(const std::vector<Lyrics*>* ll, const int trk);
void work(const MeasureBase* measure);
void calcDivMoveToTick(const Fraction& t);
Expand Down Expand Up @@ -1685,11 +1685,96 @@ void ExportMusicXml::barlineMiddle(const BarLine* bl)
}
}

//---------------------------------------------------------
// fermataPosition - return fermata y position as MusicXML string
//---------------------------------------------------------

static QString fermataPosition(const Fermata* const fermata)
{
QString res;

if (preferences.getBool(PREF_EXPORT_MUSICXML_EXPORTLAYOUT)) {
constexpr qreal SPATIUM2TENTHS = 10;
constexpr qreal EPSILON = 0.01;
const auto spatium = fermata->spatium();
const auto defY = -1* SPATIUM2TENTHS* fermata->ipos().y() / spatium;
const auto relY = -1* SPATIUM2TENTHS* fermata->offset().y() / spatium;

if (qAbs(defY) >= EPSILON)
res += QString(" default-y=\"%1\"").arg(QString::number(defY,'f',2));
if (qAbs(relY) >= EPSILON)
res += QString(" relative-y=\"%1\"").arg(QString::number(relY,'f',2));
}

return res;
}

//---------------------------------------------------------
// fermata - write a fermata
//---------------------------------------------------------

static void fermata(const Fermata* const a, XmlWriter& xml)
{
QString tagName = "fermata";
tagName += QString(" type=\"%1\"").arg(a->placement() == Placement::ABOVE ? "upright" : "inverted");
tagName += fermataPosition(a);
tagName += color2xml(a);
SymId id = a->symId();
if (id == SymId::fermataAbove || id == SymId::fermataBelow)
xml.tagE(tagName);
// MusicXML does not support the very short fermata nor short fermata (Henze),
// export as short fermata (better than not exporting at all)
else if (id == SymId::fermataShortAbove || id == SymId::fermataShortBelow
|| id == SymId::fermataShortHenzeAbove || id == SymId::fermataShortHenzeBelow
|| id == SymId::fermataVeryShortAbove || id == SymId::fermataVeryShortBelow)
xml.tag(tagName, "angled");
// MusicXML does not support the very long fermata nor long fermata (Henze),
// export as long fermata (better than not exporting at all)
else if (id == SymId::fermataLongAbove || id == SymId::fermataLongBelow
|| id == SymId::fermataLongHenzeAbove || id == SymId::fermataLongHenzeBelow
|| id == SymId::fermataVeryLongAbove || id == SymId::fermataVeryLongBelow)
xml.tag(tagName, "square");
else
qDebug("unknown fermata sim id %d", id);
}

//---------------------------------------------------------
// barlineHasFermata -- search for fermata on barline
//---------------------------------------------------------

static bool barlineHasFermata(const BarLine* const barline, const int strack, const int etrack) // TODO: track
{
const Segment* seg = barline ? barline->segment() : 0;
if (seg) {
for (const auto anno : seg->annotations()) {
if (anno->isFermata() && strack <= anno->track() && anno->track() < etrack)
return true;
}
}

return false;
}

//---------------------------------------------------------
// writeBarlineFermata -- write fermata on barline
//---------------------------------------------------------

static void writeBarlineFermata(const BarLine* const barline, XmlWriter& xml, const int strack, const int etrack)
{
const Segment* seg = barline ? barline->segment() : 0;
if (seg) {
for (const auto anno : seg->annotations()) {
if (anno->isFermata() && strack <= anno->track() && anno->track() < etrack)
fermata(toFermata(anno), xml);
}
}
}

//---------------------------------------------------------
// barlineRight -- search for and handle barline right
//---------------------------------------------------------

void ExportMusicXml::barlineRight(const Measure* const m)
void ExportMusicXml::barlineRight(const Measure* const m, const int strack, const int etrack)
{
const Measure* mmR1 = m->mmRest1(); // the multi measure rest this measure is covered by
const Measure* mmRLst = mmR1->isMMRest() ? mmR1->mmRestLast() : 0; // last measure of replaced sequence of empty measures
Expand All @@ -1714,7 +1799,12 @@ void ExportMusicXml::barlineRight(const Measure* const m)
special = "short";
}
}
if (!needBarStyle && !volta && special.isEmpty())

// check fermata
// no need to take mmrest into account, MS does not create mmrests for measure with fermatas
const auto hasFermata = barlineHasFermata(m->endBarLine(), strack, etrack);

if (!needBarStyle && !volta && special.isEmpty() && !hasFermata)
return;

_xml.stag(QString("barline location=\"right\""));
Expand Down Expand Up @@ -1750,6 +1840,8 @@ void ExportMusicXml::barlineRight(const Measure* const m)
_xml.tag("bar-style", special);
}

writeBarlineFermata(m->endBarLine(), _xml, strack, etrack);

if (volta) {
ending(_xml, volta, false);
}
Expand Down Expand Up @@ -2344,7 +2436,6 @@ static void tremoloSingleStartStop(Chord* chord, Notations& notations, Ornaments
}
}


//---------------------------------------------------------
// fermatas
//---------------------------------------------------------
Expand All @@ -2354,26 +2445,8 @@ static void fermatas(const QVector<Element*>& cra, XmlWriter& xml, Notations& no
for (const Element* e : cra) {
if (!e->isFermata())
continue;
const Fermata* a = toFermata(e);
notations.tag(xml);
QString tagName = "fermata";
tagName += QString(" type=\"%1\"").arg(a->placement() == Placement::ABOVE ? "upright" : "inverted");
tagName += color2xml(a);
SymId id = a->symId();
if (id == SymId::fermataAbove || id == SymId::fermataBelow)
xml.tagE(tagName);
// MusicXML does not support the very short fermata nor short fermata (Henze),
// export as short fermata (better than not exporting at all)
else if (id == SymId::fermataShortAbove || id == SymId::fermataShortBelow
|| id == SymId::fermataShortHenzeAbove || id == SymId::fermataShortHenzeBelow
|| id == SymId::fermataVeryShortAbove || id == SymId::fermataVeryShortBelow)
xml.tag(tagName, "angled");
// MusicXML does not support the very long fermata nor long fermata (Henze),
// export as long fermata (better than not exporting at all)
else if (id == SymId::fermataLongAbove || id == SymId::fermataLongBelow
|| id == SymId::fermataLongHenzeAbove || id == SymId::fermataLongHenzeBelow
|| id == SymId::fermataVeryLongAbove || id == SymId::fermataVeryLongBelow)
xml.tag(tagName, "square");
fermata(toFermata(e), xml);
}
}

Expand Down Expand Up @@ -6311,7 +6384,7 @@ void ExportMusicXml::writeMeasure(const Measure* const m,
repeatAtMeasureStop(_xml, m, strack, etrack, strack);
// note: don't use "m->repeatFlags() & Repeat::END" here, because more
// barline types need to be handled besides repeat end ("light-heavy")
barlineRight(m);
barlineRight(m, strack, etrack);
_xml.etag();
}

Expand Down
138 changes: 138 additions & 0 deletions mtest/musicxml/io/testBarlineFermatas.mscx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="3.01">
<programVersion>3.5.0</programVersion>
<programRevision>3543170</programRevision>
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<pageWidth>8.27</pageWidth>
<pageHeight>11.69</pageHeight>
<pagePrintableWidth>7.4826</pagePrintableWidth>
<Spatium>1.76389</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2020-01-09</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="platform">Microsoft Windows</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Piano</trackName>
<Instrument>
<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>
<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">
<Measure>
<voice>
<TimeSig>
<sigN>2</sigN>
<sigD>8</sigD>
</TimeSig>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>72</pitch>
<tpc>14</tpc>
</Note>
</Chord>
<Fermata>
<subtype>fermataAbove</subtype>
</Fermata>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>72</pitch>
<tpc>14</tpc>
</Note>
</Chord>
<Fermata>
<subtype>fermataBelow</subtype>
<placement>below</placement>
</Fermata>
</voice>
</Measure>
<Measure>
<voice>
<Rest>
<durationType>measure</durationType>
<duration>2/8</duration>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
Loading

0 comments on commit 075e6b5

Please sign in to comment.