]> git.donarmstrong.com Git - lilypond.git/commitdiff
Take invisible beams into account when beaming.
authorJoe Neeman <joeneeman@gmail.com>
Sun, 1 Jun 2008 07:44:59 +0000 (17:44 +1000)
committerJoe Neeman <joeneeman@gmail.com>
Sun, 1 Jun 2008 07:44:59 +0000 (17:44 +1000)
lily/auto-beam-engraver.cc
lily/beam-engraver.cc
lily/beaming-pattern.cc
lily/include/beaming-pattern.hh

index 7c9927d467eaf5713b0e563f80daf5e6842a0887..d299d2e6e704c8679dfcfe2b055082c072e174cd 100644 (file)
@@ -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);
index 609b3798c106314d86b9effafef6f5fc218f93d6..111a8f9187198de1f55413ebf9bb42bbd7e6dbaf 100644 (file)
@@ -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);
 }
 
index 37ef6ee614e76cf52629e7ebb073a0c88f536fc4..b87b863656047ae56358cb5b56901599e9344b35 100644 (file)
@@ -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 <hanwen@xs4all.nl>
@@ -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<Moment> group_starts;
   vector<Moment> 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<Beam_rhythmic_element> (infos_.begin (),
-                                             infos_.begin () + m);
+                                                      infos_.begin () + m);
   splits[RIGHT].infos_ = vector<Beam_rhythmic_element> (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 ()
index 4a9eae6198c7eb8ab61b0a8cbea846e6953641e0..f69857482acc867ebb6a102fd04782038aa5741e 100644 (file)
@@ -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 */