fix #280095, fix #278964: rework duration types hanling with tremolo

This commit is contained in:
Dmitri Ovodok 2018-12-19 15:36:02 +02:00
parent 96fbafde91
commit 62f5d132bf
9 changed files with 122 additions and 41 deletions

View file

@ -274,8 +274,12 @@ Chord::Chord(const Chord& c, bool link)
Tremolo* t = new Tremolo(*(c._tremolo));
if (link) {
score()->undo(new Link(t, const_cast<Tremolo*>(c._tremolo)));
if (c._tremolo->twoNotes())
t->setChords(0, 0);
if (c._tremolo->twoNotes()) {
if (c._tremolo->chord1() == &c)
t->setChords(this, nullptr);
else
t->setChords(nullptr, this);
}
}
add(t);
}
@ -420,6 +424,60 @@ QPointF Chord::stemPosBeam() const
return p;
}
//---------------------------------------------------------
// setTremolo
//---------------------------------------------------------
void Chord::setTremolo(Tremolo* tr)
{
if (tr == _tremolo)
return;
if (_tremolo) {
if (_tremolo->twoNotes()) {
TDuration d;
const Fraction f = duration();
if (f.numerator() > 0)
d = TDuration(f);
else {
d = _tremolo->durationType();
const int dots = d.dots();
d = d.shift(1);
d.setDots(dots);
}
setDurationType(d);
Chord* other = _tremolo->chord1() == this ? _tremolo->chord2() : _tremolo->chord1();
_tremolo = nullptr;
if (other)
other->setTremolo(nullptr);
}
else
_tremolo = nullptr;
}
if (tr) {
if (tr->twoNotes()) {
TDuration d = tr->durationType();
if (!d.isValid()) {
d = durationType();
const int dots = d.dots();
d = d.shift(-1);
d.setDots(dots);
tr->setDurationType(d);
}
setDurationType(d);
Chord* other = tr->chord1() == this ? tr->chord2() : tr->chord1();
_tremolo = tr;
if (other)
other->setTremolo(tr);
}
else
_tremolo = tr;
}
}
//---------------------------------------------------------
// add
//---------------------------------------------------------
@ -459,24 +517,7 @@ void Chord::add(Element* e)
_arpeggio = toArpeggio(e);
break;
case ElementType::TREMOLO:
{
Tremolo* tr = toTremolo(e);
if (tr->twoNotes()) {
if (!(_tremolo && _tremolo->twoNotes())) {
TDuration d = durationType();
int dots = d.dots();
d = d.shift(-1);
d.setDots(dots);
if (tr->chord1())
tr->chord1()->setDurationType(d);
if (tr->chord2())
tr->chord2()->setDurationType(d);
}
if (tr->chord2())
tr->chord2()->setTremolo(tr);
}
_tremolo = tr;
}
setTremolo(toTremolo(e));
break;
case ElementType::GLISSANDO:
_endsGlissando = true;
@ -559,25 +600,7 @@ void Chord::remove(Element* e)
_arpeggio = 0;
break;
case ElementType::TREMOLO:
{
Tremolo* tremolo = toTremolo(e);
if (tremolo->twoNotes()) {
TDuration d = durationType();
int dots = d.dots();
d = d.shift(1);
d.setDots(dots);
Fraction f = duration();
if (f.numerator() > 0)
d = TDuration(f);
if (tremolo->chord1())
tremolo->chord1()->setDurationType(d);
if (tremolo->chord2()) {
tremolo->chord2()->setDurationType(d);
tremolo->chord2()->setTremolo(0);
}
}
_tremolo = 0;
}
setTremolo(nullptr);
break;
case ElementType::GLISSANDO:
_endsGlissando = false;
@ -1075,6 +1098,7 @@ bool Chord::readProperties(XmlReader& e)
_tremolo->setTrack(track());
_tremolo->read(e);
_tremolo->setParent(this);
_tremolo->setDurationType(durationType());
}
else if (tag == "tickOffset") // obsolete
;

View file

@ -138,7 +138,7 @@ class Chord final : public ChordRest {
Stem* stem() const { return _stem; }
Arpeggio* arpeggio() const { return _arpeggio; }
Tremolo* tremolo() const { return _tremolo; }
void setTremolo(Tremolo* t) { _tremolo = t; }
void setTremolo(Tremolo* t);
bool endsGlissando() const { return _endsGlissando; }
void setEndsGlissando (bool val) { _endsGlissando = val; }
void updateEndsGlissando();

View file

@ -2333,6 +2333,50 @@ void layoutDrumsetChord(Chord* c, const Drumset* drumset, const StaffType* st, q
}
}
//---------------------------------------------------------
// connectTremolo
// Connect two-notes tremolo and update duration types
// for the involved chords.
//---------------------------------------------------------
static void connectTremolo(Measure* m)
{
const int ntracks = m->score()->ntracks();
constexpr SegmentType st = SegmentType::ChordRest;
for (Segment* s = m->first(st); s; s = s->next(st)) {
for (int i = 0; i < ntracks; ++i) {
Element* e = s->element(i);
if (!e || !e->isChord())
continue;
Chord* c = toChord(e);
Tremolo* tremolo = c->tremolo();
if (tremolo && tremolo->twoNotes()) {
// Ensure correct duration type for chord
c->setDurationType(tremolo->durationType());
// If it is the first tremolo's chord, find the second
// chord for tremolo, if needed.
if (!tremolo->chord1())
tremolo->setChords(c, tremolo->chord2());
else if (tremolo->chord1() != c || tremolo->chord2())
continue;
for (Segment* ls = s->next(st); ls; ls = ls->next(st)) {
if (Element* element = ls->element(i)) {
if (!element->isChord())
qDebug("cannot connect tremolo");
Chord* nc = toChord(element);
tremolo->setChords(c, nc);
nc->setTremolo(tremolo);
break;
}
}
}
}
}
}
//---------------------------------------------------------
// getNextMeasure
//---------------------------------------------------------
@ -2407,6 +2451,8 @@ void Score::getNextMeasure(LayoutContext& lc)
if (measure->sectionBreak() && measure->pause() != 0.0)
setPause(measure->endTick(), measure->pause());
connectTremolo(measure);
//
// calculate accidentals and note lines,
// create stem and set stem direction

View file

@ -13,6 +13,7 @@
#include "score.h"
#include "page.h"
#include "system.h"
#include "tremolo.h"
#include "measure.h"
#include "layout.h"
#include "bracket.h"

View file

@ -23,7 +23,6 @@
#include "noteevent.h"
#include "pitchspelling.h"
#include "shape.h"
#include "tremolo.h"
#include "key.h"
namespace Ms {

View file

@ -1065,6 +1065,7 @@ static void readChord(Measure* m, Chord* chord, XmlReader& e)
}
else if (tag == "Tremolo") {
Tremolo* tremolo = new Tremolo(chord->score());
tremolo->setDurationType(chord->durationType());
chord->setTremolo(tremolo);
tremolo->setTrack(chord->track());
readTremolo(tremolo, e);

View file

@ -1991,6 +1991,7 @@ bool readChordProperties206(XmlReader& e, Chord* ch)
tremolo->setTrack(ch->track());
tremolo->read(e);
tremolo->setParent(ch);
tremolo->setDurationType(ch->durationType());
ch->setTremolo(tremolo);
}
else if (tag == "tickOffset") // obsolete

View file

@ -53,6 +53,7 @@ Tremolo::Tremolo(const Tremolo& t)
setTremoloType(t.tremoloType());
_chord1 = t.chord1();
_chord2 = t.chord2();
_durationType = t._durationType;
}
//---------------------------------------------------------
@ -243,6 +244,8 @@ void Tremolo::layout()
//
// two chord tremolo
//
#if 0 // Needs to be done earlier, see connectTremolo in layout.cpp
Segment* s = _chord1->segment()->next();
while (s) {
if (s->element(track()) && (s->element(track())->isChord()))
@ -256,6 +259,7 @@ void Tremolo::layout()
_chord2 = toChord(s->element(track()));
_chord2->setTremolo(this);
#endif
Stem* stem1 = _chord1->stem();
Stem* stem2 = _chord2->stem();

View file

@ -13,6 +13,7 @@
#ifndef __TREMOLO_H__
#define __TREMOLO_H__
#include "durationtype.h"
#include "symbol.h"
namespace Ms {
@ -34,6 +35,7 @@ class Tremolo final : public Element {
TremoloType _tremoloType;
Chord* _chord1;
Chord* _chord2;
TDuration _durationType;
QPainterPath path;
int _lines; // derived from _subtype
@ -67,6 +69,9 @@ class Tremolo final : public Element {
Chord* chord1() const { return _chord1; }
Chord* chord2() const { return _chord2; }
TDuration durationType() const { return _durationType; }
void setDurationType(TDuration d) { _durationType = d; }
void setChords(Chord* c1, Chord* c2) {
_chord1 = c1;
_chord2 = c2;