From 280a81b2b73ea7fe891b96124f1a2aba07186960 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Sun, 1 Jun 2008 17:44:59 +1000 Subject: [PATCH] Take invisible beams into account when beaming. --- lily/auto-beam-engraver.cc | 3 +- lily/beam-engraver.cc | 3 +- lily/beaming-pattern.cc | 104 ++++++++++++++++++++++++++++---- lily/include/beaming-pattern.hh | 7 ++- 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc index 7c9927d467..d299d2e6e7 100644 --- a/lily/auto-beam-engraver.cc +++ b/lily/auto-beam-engraver.cc @@ -385,7 +385,8 @@ Auto_beam_engraver::acknowledge_stem (Grob_info info) return; grouping_->add_stem (now - beam_start_moment_ + beam_start_location_, - durlog - 2); + durlog - 2, + Stem::is_invisible (stem)); stems_->push_back (stem); last_add_mom_ = now; extend_mom_ = max (extend_mom_, now) + get_event_length (ev, now); diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc index 609b3798c1..111a8f9187 100644 --- a/lily/beam-engraver.cc +++ b/lily/beam-engraver.cc @@ -262,7 +262,8 @@ Beam_engraver::acknowledge_stem (Grob_info info) scm_from_int (durlog)); Moment stem_location = now - beam_start_mom_ + beam_start_location_; beam_info_->add_stem (stem_location, - max (durlog- 2, 0)); + max (durlog- 2, 0), + Stem::is_invisible (stem)); Beam::add_stem (beam_, stem); } diff --git a/lily/beaming-pattern.cc b/lily/beaming-pattern.cc index 37ef6ee614..b87b863656 100644 --- a/lily/beaming-pattern.cc +++ b/lily/beaming-pattern.cc @@ -1,6 +1,13 @@ /* beaming-info.cc -- implement Beam_rhythmic_element, Beaming_pattern + A Beaming_pattern object takes a set of stems at given moments and calculates + the pattern of their beam. That is, it works out, for each stem, how many + beams should be connected to the right and left sides of that stem. In + calculating this, Beaming_pattern takes into account + - the rhythmic position of the stems + - the options that are defined in Beaming_options + source file of the GNU LilyPond music typesetter (c) 1999--2007 Han-Wen Nienhuys @@ -14,14 +21,16 @@ Beam_rhythmic_element::Beam_rhythmic_element () start_moment_ = 0; beam_count_drul_[LEFT] = 0; beam_count_drul_[RIGHT] = 0; + invisible_ = false; } -Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i) +Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv) { start_moment_ = m; beam_count_drul_[LEFT] = i; beam_count_drul_[RIGHT] = i; + invisible_ = inv; } @@ -48,19 +57,49 @@ count_factor_twos (int x) return c; } +bool +Beaming_pattern::is_next_to_invisible_stem (vsize i) const +{ + return infos_[i].invisible_ + || (i > 0 && infos_[i-1].invisible_); +} + +/* + Finds the best point at which to subdivide a beam. In order of priority + (highest to lowest) this is + - before or after an invisible beam + - at the start of a beat group + - at the start of a beat + - whose position in its beat has the smallest denominator (that is, + a stem that starts halfway through a beat will be preferred over stems + that start 1/3 or 2/3s of the way through the beat). + - any other beam + - at the start of a beat group + - at the start of a beat + - whose position in its beat has the smallest denominator + + If the split point occurs at the start of a beat group or at the start of a + beat, at_boundary will be set to true. Otherwise, it will be set to false. +*/ int Beaming_pattern::best_splitpoint_index (bool *at_boundary) const { + bool require_invisible = false; + for (vsize i = 0; i < infos_.size (); i++) + require_invisible |= infos_[i].invisible_; + *at_boundary = true; for (vsize i = 1; i < infos_.size (); i++) { - if (infos_[i].group_start_ == infos_[i].start_moment_) + if (infos_[i].group_start_ == infos_[i].start_moment_ + && (!require_invisible || is_next_to_invisible_stem (i))) return i; } for (vsize i = 1; i < infos_.size (); i++) { - if (infos_[i].beat_start_ == infos_[i].start_moment_) + if (infos_[i].beat_start_ == infos_[i].start_moment_ + && (!require_invisible || is_next_to_invisible_stem (i))) return i; } @@ -83,7 +122,8 @@ Beaming_pattern::best_splitpoint_index (bool *at_boundary) const dt /= infos_[i].beat_length_; - if (dt.den () < min_den) + if (dt.den () < min_den + && (!require_invisible || is_next_to_invisible_stem (i))) { min_den = dt.den (); min_index = i; @@ -117,6 +157,8 @@ Beaming_pattern::de_grace () void Beaming_pattern::beamify (Beaming_options const &options) { + unbeam_invisible_stems (); + if (infos_.size () <= 1) return; @@ -132,6 +174,7 @@ Beaming_pattern::beamify (Beaming_options const &options) vector group_starts; vector beat_starts; + // Find the starting moments of the beats and the groups. SCM grouping = options.grouping_; while (measure_pos <= infos_.back ().start_moment_) { @@ -149,7 +192,8 @@ Beaming_pattern::beamify (Beaming_options const &options) } measure_pos += options.beat_length_ * count; } - + + // Set the group_start_ and beam_start_ properties of each stem. vsize j = 0; vsize k = 0; for (vsize i = 0; i < infos_.size (); i++) @@ -174,6 +218,18 @@ Beaming_pattern::beamify (Beaming_options const &options) } +/* + Determines beaming patterns by splitting the list of stems recursively. + + Given a list of stems, we split it at the most 'natural' place (eg. at + the beginning of a beat) as determined by best_splitpoint_index. We + then beamify both subsets of beams. Finally, we determine the number of + beams between the subsets. + + Note: if one of the subsets has only one element, we will not modify its + beams. This ensure that, for every stem, we will modify its beam count on at + most one side. +*/ void Beaming_pattern::beamify (bool subdivide_beams) { @@ -186,9 +242,9 @@ Beaming_pattern::beamify (bool subdivide_beams) int m = best_splitpoint_index (&at_boundary); splits[LEFT].infos_ = vector (infos_.begin (), - infos_.begin () + m); + infos_.begin () + m); splits[RIGHT].infos_ = vector (infos_.begin () + m, - infos_.end ()); + infos_.end ()); Direction d = LEFT; @@ -198,10 +254,10 @@ Beaming_pattern::beamify (bool subdivide_beams) } while (flip (&d) != LEFT); - int middle_beams = ((at_boundary && subdivide_beams) + int middle_beams = (at_boundary && subdivide_beams) ? 1 : min (splits[RIGHT].beam_extend_count (LEFT), - splits[LEFT].beam_extend_count (RIGHT))); + splits[LEFT].beam_extend_count (RIGHT)); do { @@ -217,10 +273,36 @@ Beaming_pattern::beamify (bool subdivide_beams) } +/* + Invisible stems should be treated as though they have the same number of + beams as their least-beamed neighbour. Here we go through the stems and + modify the invisible stems to satisfy this requirement. +*/ +void +Beaming_pattern::unbeam_invisible_stems () +{ + for (vsize i = 1; i < infos_.size (); i++) + if (infos_[i].invisible_) + { + int b = infos_[i-1].beam_count_drul_[LEFT]; + infos_[i].beam_count_drul_[LEFT] = b; + infos_[i].beam_count_drul_[RIGHT] = b; + } + + for (vsize i = infos_.size (); i--;) + if (infos_[i].invisible_) + { + int b = min (infos_[i].beam_count_drul_[LEFT], infos_[i+1].beam_count_drul_[LEFT]); + infos_[i].beam_count_drul_[LEFT] = b; + infos_[i].beam_count_drul_[RIGHT] = b; + } +} + + void -Beaming_pattern::add_stem (Moment m, int b) +Beaming_pattern::add_stem (Moment m, int b, bool invisible) { - infos_.push_back (Beam_rhythmic_element (m, b)); + infos_.push_back (Beam_rhythmic_element (m, b, invisible)); } Beaming_pattern::Beaming_pattern () diff --git a/lily/include/beaming-pattern.hh b/lily/include/beaming-pattern.hh index 4a9eae6198..f69857482a 100644 --- a/lily/include/beaming-pattern.hh +++ b/lily/include/beaming-pattern.hh @@ -32,8 +32,9 @@ struct Beam_rhythmic_element Moment beat_start_; Moment beat_length_; Moment group_start_; + bool invisible_; - Beam_rhythmic_element (Moment, int); + Beam_rhythmic_element (Moment, int, bool); Beam_rhythmic_element (); int count (Direction d); @@ -51,7 +52,7 @@ public: void beamify (Beaming_options const&); void de_grace (); - void add_stem (Moment d, int beams); + void add_stem (Moment d, int beams, bool invisible); int beamlet_count (int idx, Direction d) const; private: @@ -59,6 +60,8 @@ private: void beamify (bool); int beam_extend_count (Direction) const; int best_splitpoint_index (bool *split) const; + void unbeam_invisible_stems (); + bool is_next_to_invisible_stem (vsize) const; }; #endif /* BEAMING_PATTERN_HH */ -- 2.39.2