beam beats in X/4 according to minimum durations

This commit is contained in:
Marc Sabatella 2014-11-15 09:23:20 -07:00
parent d477e585f4
commit fef82c1a10
15 changed files with 79 additions and 20 deletions

View file

@ -1568,9 +1568,10 @@ void Beam::layout2(QList<ChordRest*>crl, SpannerSegmentType, int frag)
++i;
for (; i < n; ++i) {
ChordRest* c = crl[i];
ChordRest* p = i ? crl[i - 1] : 0;
int l = c->durationType().hooks() - 1;
Mode bm = Groups::endBeam(c);
Mode bm = Groups::endBeam(c, p);
bool b32 = (beamLevel >= 1) && (bm == Mode::BEGIN32);
bool b64 = (beamLevel >= 2) && (bm == Mode::BEGIN64);

View file

@ -66,7 +66,7 @@ static std::vector<NoteGroup> noteGroups {
// endBeam
//---------------------------------------------------------
Beam::Mode Groups::endBeam(ChordRest* cr)
Beam::Mode Groups::endBeam(ChordRest* cr, ChordRest* prev)
{
if (cr->isGrace() || cr->beamMode() != Beam::Mode::AUTO)
return cr->beamMode();
@ -76,7 +76,23 @@ Beam::Mode Groups::endBeam(ChordRest* cr)
const Groups& g = cr->staff()->group(cr->tick());
Fraction stretch = cr->staff()->timeStretch(cr->tick());
int tick = (cr->rtick() * stretch.numerator()) / stretch.denominator();
return g.beamMode(tick, d.type());
Beam::Mode val = g.beamMode(tick, d.type());
// context-dependent checks
if (val == Beam::Mode::AUTO && tick) {
// if current or previous cr is in tuplet (but not both in same tuplet):
// consider it as if this were next shorter duration
if (prev && (cr->tuplet() != prev->tuplet()) && (d == prev->durationType())) {
if (d >= TDuration::DurationType::V_EIGHTH)
val = g.beamMode(tick, TDuration::DurationType::V_16TH);
else if (d == TDuration::DurationType::V_16TH)
val = g.beamMode(tick, TDuration::DurationType::V_32ND);
else
val = g.beamMode(tick, TDuration::DurationType::V_64TH);
}
}
return val;
}
//---------------------------------------------------------

View file

@ -68,7 +68,7 @@ class Groups : public std::vector<GroupNode> {
void dump(const char*) const;
static const Groups& endings(const Fraction& f);
static Beam::Mode endBeam(ChordRest* cr);
static Beam::Mode endBeam(ChordRest* cr, ChordRest* prev = 0);
};

View file

@ -1162,34 +1162,76 @@ void Score::layoutStage2()
Beam* beam = 0; // current beam
Measure* measure = 0;
Beam::Mode bm = Beam::Mode::AUTO;
Beam::Mode bm = Beam::Mode::AUTO;
Segment::Type st = Segment::Type::ChordRest;
ChordRest* prev = 0;
ChordRest* prev = 0;
bool checkBeats = false;
Fraction stretch = 1;
QHash<int, TDuration> beatSubdivision;
for (Segment* segment = firstSegment(st); segment; segment = segment->next1(st)) {
ChordRest* cr = static_cast<ChordRest*>(segment->element(track));
if (cr == 0)
continue;
// handle grace notes and cross-measure beaming
if (cr->type() == Element::Type::CHORD) {
Chord* chord = static_cast<Chord*>(cr);
beamGraceNotes(chord, false); // grace before
beamGraceNotes(chord, true); // grace after
beamGraceNotes(chord, false); // grace before
beamGraceNotes(chord, true); // grace after
// set up for cross-measure values as soon as possible
// to have all computations (stems, hooks, ...) consistent with it
if (!chord->isGrace())
chord->crossMeasureSetup(crossMeasure);
}
bm = Groups::endBeam(cr);
// if this is a new measure, and it's simple meter (actually X/4),
// then perform a prepass to determine the subdivision of each beat
if (segment->measure() != measure) {
Measure* m = segment->measure();
TimeSig* ts = cr->staff()->timeSig(m->tick());
beatSubdivision.clear();
checkBeats = false;
stretch = ts ? ts->stretch() : 1;
if (ts && ts->denominator() == 4) {
checkBeats = true;
for (Segment* s = m->first(st); s; s = s->next(st)) {
ChordRest* mcr = static_cast<ChordRest*>(s->element(track));
if (mcr == 0)
continue;
int beat = ((mcr->rtick() * stretch.numerator()) / stretch.denominator()) / MScore::division;
if (beatSubdivision.contains(beat))
beatSubdivision[beat] = qMin(beatSubdivision[beat], mcr->durationType());
else
beatSubdivision[beat] = mcr->durationType();
}
}
}
// get defaults from time signature properties
bm = Groups::endBeam(cr, prev);
// perform additional context-dependent checks
if (bm == Beam::Mode::AUTO) {
// check if we need to break beams according to minimum duration in current / previous beat
if (checkBeats && cr->rtick()) {
int tick = (cr->rtick() * stretch.numerator()) / stretch.denominator();
// check if on the beat
if (tick % MScore::division == 0) {
int beat = tick / MScore::division;
// get minimum duration for this & previous beat
TDuration minDuration = qMin(beatSubdivision[beat], beatSubdivision[beat - 1]);
// re-calculate beam as if this were the duration of current chordrest
TDuration saveDuration = cr->durationType();
cr->setDurationType(minDuration);
bm = Groups::endBeam(cr, prev);
cr->setDurationType(saveDuration);
}
}
}
// end beam at new tuplet or end tuplet, if the next/prev duration type is different
if (cr->tuplet()
&& !cr->tuplet()->elements().isEmpty()
&& cr->tuplet()->elements().front() == cr
&& prev && prev->durationType() == cr->durationType())
bm = Beam::Mode::BEGIN;
else if (prev && prev->tuplet() && !prev->tuplet()->elements().isEmpty()
&& prev->tuplet()->elements().last() == prev && prev->durationType() == cr->durationType())
bm = Beam::Mode::BEGIN;
prev = cr;
// if chord has hooks and is 2nd element of a cross-measure value

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 10 KiB

BIN
vtest/beams-4-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
vtest/beams-4.mscz Normal file

Binary file not shown.

BIN
vtest/beams-5-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
vtest/beams-5.mscz Normal file

Binary file not shown.

BIN
vtest/beams-6-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
vtest/beams-6.mscz Normal file

Binary file not shown.

BIN
vtest/beams-7-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
vtest/beams-7.mscz Normal file

Binary file not shown.

View file

@ -39,7 +39,7 @@ else
accidental-1 accidental-2 accidental-3 accidental-4 accidental-5\
accidental-6 accidental-7 accidental-8 accidental-9\
tie-1 tie-2 tie-3 grace-1 grace-2 grace-3 harmony-1 harmony-2 harmony-3 harmony-4\
beams-1 beams-2 beams-3\
beams-1 beams-2 beams-3 beams-4 beams-5 beams-6 beams-7\
user-offset-1 user-offset-2 chord-space-1 tablature-1 image-1\
lyrics-1 lyrics-2 lyrics-3 voice-1"
fi

View file

@ -20,7 +20,7 @@ set SRC=mmrest-1,bravura-mmrest,gonville-mmrest,mmrest-2,mmrest-4,mmrest-5,mmres
accidental-1,accidental-2,accidental-3,accidental-4,accidental-5, ^
accidental-6,accidental-7,accidental-8,accidental-9, ^
tie-1,tie-2,tie-3,grace-1,grace-2,grace-3,harmony-1,harmony-2,harmony-3,harmony-4, ^
beams-1,beams-2,beams-3, ^
beams-1,beams-2,beams-3,beams-4,beams-5,beams-6,beams-7, ^
user-offset-1,user-offset-2,chord-space-1,tablature-1,image-1, ^
lyrics-1,lyrics-2,lyrics-3,voice-1