Skip to content

Commit

Permalink
fix #281591 - Mid-measure barlines are not exported to musicxml
Browse files Browse the repository at this point in the history
  • Loading branch information
lvinken committed Aug 14, 2019
1 parent 5d2f1d5 commit 3a865b8
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 35 deletions.
92 changes: 90 additions & 2 deletions mscore/exportxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ class ExportMusicXml {
void timesig(TimeSig* tsig);
void keysig(const KeySig* ks, ClefType ct, int staff = 0, bool visible = true);
void barlineLeft(Measure* m);
void barlineMiddle(const BarLine* bl);
void barlineRight(Measure* m);
void lyrics(const std::vector<Lyrics*>* ll, const int trk);
void work(const MeasureBase* measure);
Expand Down Expand Up @@ -1468,6 +1469,79 @@ void ExportMusicXml::barlineLeft(Measure* m)
_xml.etag();
}

//---------------------------------------------------------
// shortBarlineStyle -- recognize normal but shorter barline styles
//---------------------------------------------------------

static QString shortBarlineStyle(const BarLine* bl)
{
if (bl->barLineType() == BarLineType::NORMAL && !bl->spanStaff()) {
if (bl->spanTo() < 0) {
// lowest point of barline above lowest staff line
if (bl->spanFrom() < 0) {
return "tick"; // highest point of barline above highest staff line
}
else
return "short"; // highest point of barline below highest staff line
}
}

return "";
}

//---------------------------------------------------------
// normalBarlineStyle -- recognize other barline styles
//---------------------------------------------------------

static QString normalBarlineStyle(const BarLine* bl)
{
const auto bst = bl->barLineType();

switch (bst) {
case BarLineType::NORMAL:
return "regular";
case BarLineType::DOUBLE:
return "light-light";
case BarLineType::END_REPEAT:
return "light-heavy";
case BarLineType::BROKEN:
return "dashed";
case BarLineType::DOTTED:
return "dotted";
case BarLineType::END:
case BarLineType::END_START_REPEAT:
return "light-heavy";
default:
qDebug("bar subtype %d not supported", int(bst));
}

return "";
}

//---------------------------------------------------------
// barlineMiddle -- handle barline middle
//---------------------------------------------------------

void ExportMusicXml::barlineMiddle(const BarLine* bl)
{
auto vis = bl->visible();
auto shortStyle = shortBarlineStyle(bl);
auto normalStyle = normalBarlineStyle(bl);
QString barStyle;
if (!vis)
barStyle = "none";
else if (shortStyle != "")
barStyle = shortStyle;
else
barStyle = normalStyle;

if (barStyle != "") {
_xml.stag(QString("barline location=\"middle\""));
_xml.tag("bar-style", barStyle);
_xml.etag();
}
}

//---------------------------------------------------------
// barlineRight -- search for and handle barline right
//---------------------------------------------------------
Expand Down Expand Up @@ -5114,6 +5188,15 @@ static void partList(XmlWriter& xml, Score* score, const QList<Part*>& il, MxmlI

}

//---------------------------------------------------------
// tickIsInMiddleOfMeasure
//---------------------------------------------------------

static bool tickIsInMiddleOfMeasure(const Fraction ti, const Measure* m)
{
return ti != m->tick() && ti != m->endTick();
}

//---------------------------------------------------------
// writeElement
//---------------------------------------------------------
Expand All @@ -5137,7 +5220,7 @@ void ExportMusicXml::writeElement(Element* el, const Measure* m, int sstaff, boo
if (el->generated()) {
clefDebug("exportxml: generated clef not exported");
}
else if (!el->generated() && ti != m->tick() && ti != m->endTick())
else if (!el->generated() && tickIsInMiddleOfMeasure(ti, m))
clef(sstaff, cle->clefType(), color2xml(cle));
else
clefDebug("exportxml: clef not exported");
Expand All @@ -5161,7 +5244,12 @@ void ExportMusicXml::writeElement(Element* el, const Measure* m, int sstaff, boo
if (!(r->isGap()))
rest(r, sstaff);
}
else if (el->isKeySig() || el->isTimeSig() || el->isBarLine() || el->isBreath()) {
else if (el->isBarLine()) {
const auto barln = toBarLine(el);
if (tickIsInMiddleOfMeasure(barln->tick(), m))
barlineMiddle(barln);
}
else if (el->isKeySig() || el->isTimeSig() || el->isBreath()) {
// handled elsewhere
}
else
Expand Down
115 changes: 83 additions & 32 deletions mscore/importmxmlpass2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================

#include <memory>
#include <utility>

#include "libmscore/arpeggio.h"
#include "libmscore/accidental.h"
#include "libmscore/breath.h"
Expand Down Expand Up @@ -2148,7 +2151,7 @@ void MusicXMLParserPass2::measure(const QString& partId,
_e.skipCurrentElement();
}
else if (_e.name() == "barline")
barline(partId, measure);
barline(partId, measure, time + mTime);
else if (_e.name() == "print")
print(measure);
else
Expand Down Expand Up @@ -3238,10 +3241,8 @@ static bool determineBarLineType(const QString& barStyle, const QString& repeat,
else if (barStyle == "heavy-heavy")
;
*/
else if (barStyle == "none") {
type = BarLineType::NORMAL;
else if (barStyle == "none")
visible = false;
}
else if (barStyle == "") {
if (repeat == "backward")
type = BarLineType::END_REPEAT;
Expand All @@ -3252,9 +3253,8 @@ static bool determineBarLineType(const QString& barStyle, const QString& repeat,
return false;
}
}
else if (barStyle == "tick") {
}
else if (barStyle == "short") {
else if (barStyle == "tick" || "short") {
// handled later (as normal barline with different parameters)
}
else {
qDebug("unsupported bar type <%s>", qPrintable(barStyle)); // TODO
Expand All @@ -3264,6 +3264,52 @@ static bool determineBarLineType(const QString& barStyle, const QString& repeat,
return true;
}

//---------------------------------------------------------
// createBarline
//---------------------------------------------------------

/*
* Create a barline of the specified type.
*/

static std::unique_ptr<BarLine> createBarline(Score* score, const int track, const BarLineType type, const bool visible, const QString& barStyle)
{
std::unique_ptr<BarLine> barline(new BarLine(score));
barline->setTrack(track);
barline->setBarLineType(type);
barline->setSpanStaff(0);
barline->setVisible(visible);
if (barStyle == "tick") {
barline->setSpanFrom(BARLINE_SPAN_TICK1_FROM);
barline->setSpanTo(BARLINE_SPAN_TICK1_TO);
}
else if (barStyle == "short") {
barline->setSpanFrom(BARLINE_SPAN_SHORT1_FROM);
barline->setSpanTo(BARLINE_SPAN_SHORT1_TO);
}
return barline;
}

//---------------------------------------------------------
// addBarlineToMeasure
//---------------------------------------------------------

/*
* Add barline to the measure at tick.
*/

static void addBarlineToMeasure(Measure* measure, const Fraction tick, std::unique_ptr<BarLine> barline)
{
auto st = SegmentType::BarLine;
if (tick == measure->endTick())
st = SegmentType::EndBarLine;
else if (tick == measure->tick())
st = SegmentType::BeginBarLine;
const auto segment = measure->getSegment(st, tick);
barline->layout();
segment->add(barline.release());
}

//---------------------------------------------------------
// barline
//---------------------------------------------------------
Expand All @@ -3272,7 +3318,23 @@ static bool determineBarLineType(const QString& barStyle, const QString& repeat,
Parse the /score-partwise/part/measure/barline node.
*/

void MusicXMLParserPass2::barline(const QString& partId, Measure* measure)
/*
Following barline types are automatically generated by MuseScore in an EndBarLine segment at the end of a measure:
- normal (excluding tick and short)
- start repeat
- end-start repeat
- end repeat
- final (at the end of the score only)
The other barline types can also be in an EndBarLine segment at the end of a measure, but are NOT generated
Mid-measure barlines are in a BarLine segment and are NOT generated
Following barline types can only be at the end of a measure:
- start repeat
- end-start repeat
- end repeat
- final
*/

void MusicXMLParserPass2::barline(const QString& partId, Measure* measure, const Fraction& tick)
{
Q_ASSERT(_e.isStartElement() && _e.name() == "barline");

Expand Down Expand Up @@ -3310,6 +3372,7 @@ void MusicXMLParserPass2::barline(const QString& partId, Measure* measure)
BarLineType type = BarLineType::NORMAL;
bool visible = true;
if (determineBarLineType(barStyle, repeat, type, visible)) {
const auto track = _pass1.trackForPart(partId);
if (type == BarLineType::START_REPEAT) {
// combine start_repeat flag with current state initialized during measure parsing
measure->setRepeatStart(true);
Expand All @@ -3318,32 +3381,20 @@ void MusicXMLParserPass2::barline(const QString& partId, Measure* measure)
// combine end_repeat flag with current state initialized during measure parsing
measure->setRepeatEnd(true);
}
else if (type == BarLineType::END) {
measure->setEndBarLineType(type, track, visible);
}
else {
int track = _pass1.trackForPart(partId);
if (barStyle == "tick") {
BarLine* b = new BarLine(measure->score());
b->setTrack(track);
b->setBarLineType(BarLineType::NORMAL);
b->setSpanStaff(false);
b->setSpanFrom(BARLINE_SPAN_TICK1_FROM);
b->setSpanTo(BARLINE_SPAN_TICK1_TO);
Segment* segment = measure->getSegment(SegmentType::EndBarLine, measure->endTick());
segment->add(b);
}
else if (barStyle == "short") {
BarLine* b = new BarLine(measure->score());
b->setTrack(track);
b->setBarLineType(BarLineType::NORMAL);
b->setSpanStaff(0);
b->setSpanFrom(BARLINE_SPAN_SHORT1_FROM);
b->setSpanTo(BARLINE_SPAN_SHORT1_TO);
Segment* segment = measure->getSegment(SegmentType::EndBarLine, measure->endTick());
segment->add(b);
if (barStyle == "tick"
|| barStyle == "short"
|| barStyle == "none"
|| barStyle == "dashed"
|| barStyle == "dotted"
|| barStyle == "light-light"
|| barStyle == "regular") {
auto b = createBarline(measure->score(), track, type, visible, barStyle);
addBarlineToMeasure(measure, tick, std::move(b));
}
else if (loc == "right")
measure->setEndBarLineType(type, track, visible);
else if (measure->prevMeasure())
measure->prevMeasure()->setEndBarLineType(type, track, visible);
}
}

Expand Down
2 changes: 1 addition & 1 deletion mscore/importmxmlpass2.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class MusicXMLParserPass2 {
void attributes(const QString& partId, Measure* measure, const Fraction& tick);
void measureStyle(Measure* measure);
void print(Measure* measure);
void barline(const QString& partId, Measure* measure);
void barline(const QString& partId, Measure* measure, const Fraction& tick);
void key(const QString& partId, Measure* measure, const Fraction& tick);
void clef(const QString& partId, Measure* measure, const Fraction& tick);
void time(const QString& partId, Measure* measure, const Fraction& tick);
Expand Down
Loading

0 comments on commit 3a865b8

Please sign in to comment.