]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fixes Issue 1504, allowing feather beam line breaking.
authorMike Solomon <mike@apollinemike.com>
Wed, 16 Mar 2011 19:07:34 +0000 (15:07 -0400)
committerMike Solomon <mike@apollinemike.com>
Wed, 16 Mar 2011 19:07:34 +0000 (15:07 -0400)
Makes it such that the degree of feathering at the end of a system
is preserved at the beginning of the next system.

Adds a normalized-endpoints property to Spanner, which calculates
the portion of a spanner (normalized from 0 to 1) taken up by any
broken child.

input/regression/beam-feather-breaking.ly [new file with mode: 0644]
lily/beam.cc
lily/include/spanner.hh
lily/spanner.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

diff --git a/input/regression/beam-feather-breaking.ly b/input/regression/beam-feather-breaking.ly
new file mode 100644 (file)
index 0000000..1b3aae0
--- /dev/null
@@ -0,0 +1,137 @@
+\version "2.13.55"
+\header  {
+  texidoc = "Feathered beams should have the same progress of their feathering
+at the end of a line break as they do at the beginning of the next line."
+}
+
+\paper {
+  left-margin = 2\cm
+  line-width = 10\cm
+  ragged-right = ##t
+  indent = 0\cm
+}
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d e f g a ]
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a[ g f e d c b a]  \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d \bar "" \break e f g a b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d e f g a \bar "" \break b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d e f g a b c d \bar "" \break e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d \bar "" \break e f g a b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d e f g a \bar "" \break b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d e f g a b c d \bar "" \break e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d \bar "" \break e f g a b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d e f g a \bar "" \break b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #RIGHT
+    a32[ b c d e f g a b c d \bar "" \break e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d \bar "" \break e f g a b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d e f g a \bar "" \break b c d e f g a ] \bar "|"
+} >>
+
+\new Staff <<
+  \relative c' {
+    \cadenzaOn
+    \override Staff . TimeSignature #'stencil = ##f
+    \override Voice . Stem #'direction = #DOWN
+    \override Voice . Beam #'breakable = ##t
+    \once \override Voice . Beam #'grow-direction = #LEFT
+    a32[ b c d e f g a b c d \bar "" \break e f g a ] \bar "|"
+} >>
index 53fda8174319205db9cf61ebf5151765ea674577..e3135dadfa92609362dccfd467e5f164dde1bde7 100644 (file)
@@ -590,24 +590,72 @@ Beam::print (SCM grob)
 
   Direction feather_dir = to_dir (me->get_property ("grow-direction"));
 
+  Interval placements = robust_scm2interval (me->get_property ("normalized-endpoints"), Interval (0.0, 0.0));
+
   Stencil the_beam;
+
+  int extreme = (segments[0].vertical_count_ == 0
+                 ? segments[0].vertical_count_
+                 : segments.back ().vertical_count_);
+
   for (vsize i = 0; i < segments.size (); i ++)
     {
       Real local_slope = slope;
+      /*
+        Makes local slope proportional to the ratio of the length of this beam
+        to the total length.
+      */
       if (feather_dir)
-       {
-         local_slope += feather_dir * segments[i].vertical_count_ * beam_dy / span.length ();
-       }
+        local_slope += (feather_dir * segments[i].vertical_count_
+                                    * beam_dy
+                                    * placements.length ()
+                        / span.length ());
 
       Stencil b = Lookup::beam (local_slope, segments[i].horizontal_.length (), beam_thickness, blot);
 
       b.translate_axis (segments[i].horizontal_[LEFT], X_AXIS);
+      Real multiplier = feather_dir ? placements[LEFT] : 1.0;
+
+      Interval weights (1 - multiplier, multiplier);
+
+      if (feather_dir != LEFT)
+        weights.swap ();
+
+      // we need two translations: the normal one and
+      // the one of the lowest segment
+      int idx[] = {i, extreme};
+      Real translations[2];
+
+      for (int j = 0; j < 2; j++)
+        translations[j] = slope
+                          * (segments[idx[j]].horizontal_[LEFT] - span.linear_combination (CENTER))
+                          + pos.linear_combination (CENTER)
+                          + beam_dy * segments[idx[j]].vertical_count_;
+
+      Real weighted_average = translations[0] * weights[LEFT] + translations[1] * weights[RIGHT];
+
+      /*
+        Tricky.  The manipulation of the variable `weighted_average' below ensures
+        that beams with a RIGHT grow direction will start from the position of the
+        lowest segment at 0, and this error will decrease and decrease over the
+        course of the beam.  Something with a LEFT grow direction, on the other
+        hand, will always start in the correct place but progressively accrue
+        error at broken places.  This code shifts beams up given where they are
+        in the total span length (controlled by the variable `multiplier').  To
+        better understand what it does, try commenting it out: you'll see that
+        all of the RIGHT growing beams immediately start too low and get better
+        over line breaks, whereas all of the LEFT growing beams start just right
+        and get worse over line breaks.
+      */
+      Real factor = Interval (multiplier, 1 - multiplier).linear_combination (feather_dir);
+
+      if (segments[0].vertical_count_ < 0 && feather_dir)
+        weighted_average += beam_dy * (segments.size () - 1) * factor;
+
+      b.translate_axis (weighted_average, Y_AXIS);
 
-      b.translate_axis (local_slope
-                       * (segments[i].horizontal_[LEFT] - span.linear_combination (feather_dir))
-                       + pos.linear_combination (feather_dir)
-                       + beam_dy * segments[i].vertical_count_, Y_AXIS);
       the_beam.add_stencil (b);
+
     }
 
 #if (DEBUG_BEAM_SCORING)
@@ -626,7 +674,7 @@ Beam::print (SCM grob)
 
       properties = scm_cons(scm_acons (ly_symbol2scm ("font-size"), scm_from_int (-5), SCM_EOL),
                             properties);
-      
+
       Direction stem_dir = stems.size () ? to_dir (stems[0]->get_property ("direction")) : UP;
 
       Stencil score = *unsmob_stencil (Text_interface::interpret_markup
@@ -1088,7 +1136,7 @@ Beam::shift_region_to_valid (SCM grob, SCM posns)
       Real x = s->relative_coordinate (common[X_AXIS], X_AXIS) - x_span[LEFT];
       x_posns.push_back (x);
     }
-  
+
   Grob *lvs = last_normal_stem (me);
   x_span[RIGHT] = lvs->relative_coordinate (common[X_AXIS], X_AXIS);
 
index e0f461a7dbc137acd7bf015cbf4984ea36dbba90..7bda060c864d20d3920837b0ce861fac92d2ee25 100644 (file)
@@ -48,6 +48,7 @@ class Spanner : public Grob
 
 public:
   DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM));
+  DECLARE_SCHEME_CALLBACK (calc_normalized_endpoints, (SCM));
   DECLARE_SCHEME_CALLBACK (bounds_width, (SCM));
   DECLARE_SCHEME_CALLBACK (kill_zero_spanned_time, (SCM));
 
index 6083c67461ecc110fcd681959d57e8859fb8175d..d3fd5a0955dd00df7cf78215f0452623748447c8 100644 (file)
@@ -398,6 +398,53 @@ Spanner::set_spacing_rods (SCM smob)
   return SCM_UNSPECIFIED;
 }
 
+MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
+SCM
+Spanner::calc_normalized_endpoints (SCM smob)
+{
+  Spanner *me = unsmob_spanner (smob);
+  SCM result = SCM_EOL;
+
+  Spanner *orig = dynamic_cast<Spanner *> (me->original ());
+
+  orig = orig ? orig : me;
+
+  if (orig->is_broken ())
+    {
+      Real total_width = 0.0;
+      vector<Real> span_data;
+
+      if (!orig->is_broken ())
+        span_data.push_back (orig->spanner_length ());
+      else
+        for (vsize i = 0; i < orig->broken_intos_.size (); i++)
+          span_data.push_back (orig->broken_intos_[i]->spanner_length ());
+
+      vector<Interval> unnormalized_endpoints;
+
+      for (vsize i = 0; i < span_data.size (); i++)
+        {
+          unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
+          total_width += span_data[i];
+        }
+
+      for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
+        {
+          SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
+          orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
+          if (me->get_break_index () == i)
+            result = t;
+        }
+    }
+  else
+    {
+      result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
+      orig->set_property ("normalized-endpoints", result);
+    }
+
+  return result;
+}
+
 Spanner *
 unsmob_spanner (SCM s)
 {
@@ -479,6 +526,7 @@ ADD_INTERFACE (Spanner,
               " point of the spanner.",
 
               /* properties */
+              "normalized-endpoints "
               "minimum-length "
               "to-barline "
               );
index 879a1c780d105bcb72c1dc97514fbcb87d7f1a5f..83b327413dc1cb2eca4b3ea79283b1a79e21ab31 100644 (file)
@@ -616,6 +616,9 @@ the nearest staff in the opposite direction from
 between the two, and @code{staff-affinity} is either @code{UP} or
 @code{DOWN}.  See @code{staff-staff-spacing} for a description of
 the alist structure.")
+     (normalized-endpoints ,pair? "Represents left and right placement
+over the total spanner, where the width of the spanner is normalized
+between 0 and 1.")
      (note-names ,vector? "Vector of strings containing names for
 easy-notation note heads.")
 
index 6e4faedf405734df2ab216b63f5190efa9395377..8b9564f41e1776e00814887a7d4516b95dba4465 100644 (file)
      . (
        ;; todo: clean this up a bit: the list is getting
        ;; rather long.
-
        (auto-knee-gap . 5.5)
        (beam-thickness . 0.48) ; in staff-space
 
            (round-to-zero-slope . 0.02)))
        (direction . ,ly:beam::calc-direction)
 
+       (normalized-endpoints . ,ly:spanner::calc-normalized-endpoints)
        ;; only for debugging.
        (font-family . roman)