Merge pull request #12214 from asattely/beamlet-directions

Fix #10205: Beam groups calculation fix
This commit is contained in:
RomanPudashkin 2022-07-04 14:45:23 +03:00 committed by GitHub
commit f6d12d96eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 9 deletions

View file

@ -978,11 +978,13 @@ void Beam::createBeamSegments(const std::vector<ChordRest*>& chordRests)
bool breakBeam = false;
bool previousBreak32 = false;
bool previousBreak64 = false;
int prevRests = 0;
for (uint i = 0; i < chordRests.size(); i++) {
ChordRest* chordRest = chordRests[i];
ChordRest* prevChordRest = i < 1 ? nullptr : chordRests[i - 1];
if (!chordRest->isChord()) {
prevRests++;
continue;
}
Chord* chord = toChord(chordRest);
@ -1002,7 +1004,7 @@ void Beam::createBeamSegments(const std::vector<ChordRest*>& chordRests)
} else {
if (startChord && endChord) {
if (startChord == endChord) {
bool isBeamletBefore = calcIsBeamletBefore(startChord, i - 1, level, previousBreak32, previousBreak64);
bool isBeamletBefore = calcIsBeamletBefore(startChord, i - 1 - prevRests, level, previousBreak32, previousBreak64);
createBeamletSegment(startChord, isBeamletBefore, level);
} else {
createBeamSegment(startChord, endChord, level);
@ -1013,6 +1015,7 @@ void Beam::createBeamSegments(const std::vector<ChordRest*>& chordRests)
}
previousBreak32 = isBroken32;
previousBreak64 = isBroken64;
prevRests = 0;
}
// if the beam ends on the last chord

View file

@ -97,21 +97,39 @@ BeamMode Groups::endBeam(const ChordRest* cr, const ChordRest* prev)
}
assert(cr->staff());
TDuration d = cr->durationType();
const Groups& g = cr->staff()->group(cr->tick());
Fraction stretch = cr->staff()->timeStretch(cr->tick());
Fraction tick = cr->rtick() * stretch;
// we need to figure out the longest note value beat upon which cr falls in the measure
int maxTickLen = std::max(cr->ticks().ticks(), prev ? prev->ticks().ticks() : 0);
int smallestTickLen = Fraction(1, 8).ticks(); // start with 8th
int tickLenLimit = Fraction(1, 32).ticks(); // only check up to 32nds because that's all thats available
// in timesig properties
while (smallestTickLen > maxTickLen || cr->tick().ticks() % smallestTickLen != 0) {
smallestTickLen /= 2; // proceed to 16th, 32nd, etc
if (smallestTickLen < tickLenLimit) {
smallestTickLen = cr->ticks().ticks();
break;
}
}
DurationType bigBeatDuration = TDuration(Fraction::fromTicks(smallestTickLen)).type();
BeamMode val = g.beamMode(tick.ticks(), d.type());
TDuration crDuration = cr->durationType();
const Groups& g = cr->staff()->group(cr->tick());
Fraction stretch = cr->staff()->timeStretch(cr->tick());
Fraction tick = cr->rtick() * stretch;
// We can choose to break beams based on its place in the measure, or by its duration. These
// can be consolidated mostly, with bias towards its duration.
BeamMode byType = g.beamMode(tick.ticks(), crDuration.type());
BeamMode byPos = g.beamMode(tick.ticks(), bigBeatDuration);
BeamMode val = byType == BeamMode::AUTO ? byPos : byType;
// context-dependent checks
if (val == BeamMode::AUTO && tick.isNotZero()) {
// 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 >= DurationType::V_EIGHTH) {
if (prev && (cr->tuplet() != prev->tuplet()) && (crDuration == prev->durationType())) {
if (crDuration >= DurationType::V_EIGHTH) {
val = g.beamMode(tick.ticks(), DurationType::V_16TH);
} else if (d == DurationType::V_16TH) {
} else if (crDuration == DurationType::V_16TH) {
val = g.beamMode(tick.ticks(), DurationType::V_32ND);
} else {
val = g.beamMode(tick.ticks(), DurationType::V_64TH);