Merge pull request #5077 from lvinken/280607-musicxml-top-text-export

fix #280607 - Musicxml export - top texts don't export
This commit is contained in:
Dmitri Ovodok 2019-06-17 10:55:41 +02:00 committed by GitHub
commit e8670cc7eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 378 additions and 35 deletions

View file

@ -4227,6 +4227,29 @@ static const FretDiagram* findFretDiagram(int strack, int etrack, int track, Seg
return 0;
}
//---------------------------------------------------------
// commonAnnotations
//---------------------------------------------------------
static bool commonAnnotations(ExportMusicXml* exp, const Element* e, int sstaff)
{
if (e->isSymbol())
exp->symbol(toSymbol(e), sstaff);
else if (e->isTempoText())
exp->tempoText(toTempoText(e), sstaff);
else if (e->isStaffText() || e->isSystemText() || e->isText() || e->isInstrumentChange())
//exp->words(toText(e), sstaff); TODO
exp->words(static_cast<const Text*>(e), sstaff);
else if (e->isDynamic())
exp->dynamic(toDynamic(e), sstaff);
else if (e->isRehearsalMark())
exp->rehearsal(toRehearsalMark(e), sstaff);
else
return false;
return true;
}
//---------------------------------------------------------
// annotations
//---------------------------------------------------------
@ -4235,7 +4258,7 @@ static const FretDiagram* findFretDiagram(int strack, int etrack, int track, Seg
// in MusicXML they are combined in the harmony element. This means they have to be matched.
// TODO: replace/repair current algorithm (which can only handle one FRET_DIAGRAM and one HARMONY)
static void annotations(ExportMusicXml* exp, XmlWriter&, int strack, int etrack, int track, int sstaff, Segment* seg)
static void annotations(ExportMusicXml* exp, int strack, int etrack, int track, int sstaff, Segment* seg)
{
if (seg->segmentType() == SegmentType::ChordRest) {
@ -4250,40 +4273,20 @@ static void annotations(ExportMusicXml* exp, XmlWriter&, int strack, int etrack,
wtrack = findTrackForAnnotations(e->track(), seg);
if (track == wtrack) {
switch (e->type()) {
case ElementType::SYMBOL:
exp->symbol(static_cast<const Symbol*>(e), sstaff);
break;
case ElementType::TEMPO_TEXT:
exp->tempoText(static_cast<const TempoText*>(e), sstaff);
break;
case ElementType::STAFF_TEXT:
case ElementType::TEXT:
case ElementType::INSTRUMENT_CHANGE:
exp->words(static_cast<const Text*>(e), sstaff);
break;
case ElementType::DYNAMIC:
exp->dynamic(static_cast<const Dynamic*>(e), sstaff);
break;
case ElementType::HARMONY:
// qDebug("annotations seg %p found harmony %p", seg, e);
exp->harmony(static_cast<const Harmony*>(e), fd /*, sstaff */);
fd = 0; // make sure to write only once ...
break;
case ElementType::REHEARSAL_MARK:
exp->rehearsal(static_cast<const RehearsalMark*>(e), sstaff);
break;
case ElementType::FIGURED_BASS: // handled separately by figuredBass()
case ElementType::FRET_DIAGRAM: // handled using findFretDiagram()
case ElementType::JUMP: // ignore
break;
default:
qDebug("annotations: direction type %s at tick %d not implemented",
Element::name(e->type()), seg->tick().ticks());
break;
if (commonAnnotations(exp, e, sstaff))
; // already handled
else if (e->isHarmony()) {
// qDebug("annotations seg %p found harmony %p", seg, e);
exp->harmony(toHarmony(e), fd);
fd = nullptr; // make sure to write only once ...
}
else if (e->isFiguredBass() || e->isFretDiagram() || e->isJump())
; // handled separately by figuredBass(), findFretDiagram() or ignored
else
qDebug("annotations: direction type %s at tick %d not implemented",
Element::name(e->type()), seg->tick().ticks());
}
} // for
}
if (fd)
// found fd but no harmony, cannot write (MusicXML would be invalid)
qDebug("annotations seg %p found fretboard diagram %p w/o harmony: cannot write",
@ -5260,6 +5263,32 @@ static void writeInstrumentDetails(XmlWriter& xml, const Part* part)
}
}
//---------------------------------------------------------
// annotationsWithoutNote
//---------------------------------------------------------
/**
Write the annotations that could not be attached to notes.
*/
static void annotationsWithoutNote(ExportMusicXml* exp, const int strack, const int staves, const Measure* const measure)
{
for (auto segment = measure->first(); segment; segment = segment->next()) {
if (segment->segmentType() == SegmentType::ChordRest) {
for (const auto element : segment->annotations()) {
if (!element->isFiguredBass() && !element->isHarmony()) { // handled elsewhere
const auto wtrack = findTrackForAnnotations(element->track(), segment); // track to write annotation
if (strack <= element->track() && element->track() < (strack + VOICES * staves) && wtrack < 0) {
exp->moveToTick(element->tick());
commonAnnotations(exp, element, staves > 1 ? 1 : 0);
}
}
}
}
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
@ -5336,7 +5365,6 @@ void ExportMusicXml::write(QIODevice* dev)
continue;
Measure* m = static_cast<Measure*>(mb);
// pickup and other irregular measures need special care
QString measureTag = "measure number=";
if ((irregularMeasureNo + measureNo) == 2 && m->irregular()) {
@ -5430,7 +5458,7 @@ void ExportMusicXml::write(QIODevice* dev)
// handle annotations and spanners (directions attached to this note or rest)
if (el->isChordRest()) {
_attr.doAttr(_xml, false);
annotations(this, _xml, strack, etrack, st, sstaff, seg);
annotations(this, strack, etrack, st, sstaff, seg);
// look for more harmony
for (Segment* seg1 = seg->next(); seg1; seg1 = seg1->next()) {
if (seg1->isChordRestType()) {
@ -5459,6 +5487,10 @@ void ExportMusicXml::write(QIODevice* dev)
} // for (Segment* seg = ...
_attr.stop(_xml);
} // for (int st = ...
// write the annotations that could not be attached to notes
annotationsWithoutNote(this, strack, staves, m);
// move to end of measure (in case of incomplete last voice)
#ifdef DEBUG_TICK
qDebug("end of measure");

View file

@ -0,0 +1,310 @@
<?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-number>MuseScore testfile</work-number>
<work-title>Directions 2</work-title>
</work>
<identification>
<creator type="composer">Leon Vinken</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>Flute</part-name>
<part-abbreviation>Fl.</part-abbreviation>
<score-instrument id="P1-I1">
<instrument-name>Flute</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>74</midi-program>
<volume>78.7402</volume>
<pan>0</pan>
</midi-instrument>
</score-part>
<score-part id="P2">
<part-name>Piano</part-name>
<part-abbreviation>Pno.</part-abbreviation>
<score-instrument id="P2-I1">
<instrument-name>Piano</instrument-name>
</score-instrument>
<midi-device id="P2-I1" port="1"></midi-device>
<midi-instrument id="P2-I1">
<midi-channel>2</midi-channel>
<midi-program>1</midi-program>
<volume>78.7402</volume>
<pan>0</pan>
</midi-instrument>
</score-part>
<score-part id="P3">
<part-name>Contrabass</part-name>
<part-abbreviation>Cb.</part-abbreviation>
<score-instrument id="P3-I1">
<instrument-name>Contrabass</instrument-name>
</score-instrument>
<midi-device id="P3-I1" port="1"></midi-device>
<midi-instrument id="P3-I1">
<midi-channel>3</midi-channel>
<midi-program>44</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>
<words font-weight="bold" font-size="12">Lento</words>
</direction-type>
<sound tempo="52.5"/>
</direction>
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
</note>
</measure>
<measure number="2">
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
</note>
<backup>
<duration>3</duration>
</backup>
<direction placement="above">
<direction-type>
<words font-weight="bold" font-size="12">Andante</words>
</direction-type>
<sound tempo="91.9998"/>
</direction>
<forward>
<duration>3</duration>
</forward>
</measure>
<measure number="3">
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
</note>
<backup>
<duration>2</duration>
</backup>
<direction placement="above">
<direction-type>
<rehearsal font-weight="bold" font-size="14">A</rehearsal>
</direction-type>
</direction>
<forward>
<duration>2</duration>
</forward>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
<part id="P2">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<staves>2</staves>
<clef number="1">
<sign>G</sign>
<line>2</line>
</clef>
<clef number="2">
<sign>F</sign>
<line>4</line>
</clef>
</attributes>
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
<staff>1</staff>
</note>
<backup>
<duration>4</duration>
</backup>
<note>
<rest/>
<duration>4</duration>
<voice>5</voice>
<staff>2</staff>
</note>
</measure>
<measure number="2">
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
<staff>1</staff>
</note>
<backup>
<duration>4</duration>
</backup>
<note>
<rest/>
<duration>4</duration>
<voice>5</voice>
<staff>2</staff>
</note>
</measure>
<measure number="3">
<note>
<rest/>
<duration>4</duration>
<voice>1</voice>
<staff>1</staff>
</note>
<backup>
<duration>4</duration>
</backup>
<note>
<rest/>
<duration>4</duration>
<voice>5</voice>
<staff>2</staff>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
<part id="P3">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>F</sign>
<line>4</line>
</clef>
<transpose>
<diatonic>0</diatonic>
<chromatic>0</chromatic>
<octave-change>-1</octave-change>
</transpose>
</attributes>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
</measure>
<measure number="2">
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
</measure>
<measure number="3">
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<note>
<rest/>
<duration>1</duration>
<voice>1</voice>
<type>quarter</type>
</note>
<barline location="right">
<bar-style>light-heavy</bar-style>
</barline>
</measure>
</part>
</score-partwise>

View file

@ -69,6 +69,7 @@ private slots:
void dcalCoda() { mxmlIoTest("testDCalCoda"); }
void dcalFine() { mxmlIoTest("testDCalFine"); }
void directions1() { mxmlIoTest("testDirections1"); }
void directions2() { mxmlIoTest("testDirections2"); }
void divisionsDefinedTooLate1() { mxmlIoTestRef("testDivsDefinedTooLate1"); }
void divisionsDefinedTooLate2() { mxmlIoTestRef("testDivsDefinedTooLate2"); }
void doubleClefError() { mxmlIoTestRef("testDoubleClefError"); }