]> git.donarmstrong.com Git - lilypond.git/commitdiff
note-spacing: stretch somewhat uniformly
authorKeith OHara <k-ohara5a5a@oco.net>
Wed, 18 Dec 2013 00:41:51 +0000 (16:41 -0800)
committerKeith OHara <k-ohara5a5a@oco.net>
Sat, 4 Jan 2014 04:20:36 +0000 (20:20 -0800)
Start with a basic spring based on the note duration, and apply optical
corrections to that.  This results in more consistent springs thus more
uniform stretching in polyphonic situations.

input/regression/spacing-multi-tuplet.ly
lily/include/note-spacing.hh
lily/include/spacing-spanner.hh
lily/note-spacing.cc
lily/spacing-basic.cc
lily/spacing-determine-loose-columns.cc
lily/spacing-loose-columns.cc
lily/spacing-spanner.cc

index bab9232a8d1b7113ec43676e601aaa1352c96622..4c84dad0d8b90947c91f6e1cc73b03704c73d545 100644 (file)
@@ -2,28 +2,18 @@
 
  \header{
 
-  texidoc = "Concurrent tuplets should be equidistant on all staves.
-Such equidistant spacing is at odds with elegant engraver spacing;
-hence it must be switched on explicitly with the
-@code{uniform-stretching} property of @code{SpacingSpanner}."
+  texidoc = "Concurrent tuplets should be equidistant on all staves."
 }
 
-\layout{
-  \context{
-    \Score
-    \override SpacingSpanner.uniform-stretching = ##t
-  }
-}
+\paper {ragged-right = ##f }
 
 \relative c' { 
   \context StaffGroup << 
     \new Staff  \context Voice { 
-      \tuplet 10/2 {  c8[ c c c c c c c c c] } 
-      \tuplet 10/2 {  c[  c c c c c c c c c] } 
+      \tuplet 10/8 {  c8[ c c c c c c c c c] }
     }
     \new Staff  \context Voice { 
-      \tuplet 11/2 {  c8[ c c c c c c c c c c] } 
-      \tuplet 11/2 {  c[  c c c c c c c c c c] } 
+      \tuplet 8/8 {  c8[ c c c c c c c] }
     }
   >>
 }
index 9b8a4fd922a576fda038ef8d456026862569eb24..945362ab06583e37e03c07dffbeeee8113b07b3a 100644 (file)
@@ -29,7 +29,7 @@ class Note_spacing
 public:
   DECLARE_GROB_INTERFACE ();
 
-  static Spring get_spacing (Grob *me, Item *, Real, Real);
+  static Spring get_spacing (Grob *me, Item *, Spring, Real);
   static void stem_dir_correction (Grob *me, Item *next_col, Real incr,
                                    Real *, Real *);
 };
index 165f04a8adbccecd2b72821b93f271ce6d6f9260..3f0590c4ee1bde98b03d250af9a7ef870d92b269 100644 (file)
@@ -45,7 +45,7 @@ private:
   static bool fills_measure (Grob *, Item *, Item *);
 public:
   static vector<Grob *> get_columns (Grob *me);
-  static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const *);
+  static Spring note_spacing (Grob *, Grob *, Grob *, Spacing_options const *);
   static Spring standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *);
 
   DECLARE_SCHEME_CALLBACK (set_springs, (SCM));
index 1d0d21fbbb502e5ae977c0e90781cfe63233aca2..e59aa6ec841f4660148a4e104759aeebae25afea 100644 (file)
   TODO: detect hshifts due to collisions, and account for them in
   spacing?
 */
-
+/*
+  Adjust the ideal and minimum distance between note columns,
+  based on the notehead size, skylines, and optical illusions.
+*/
 Spring
 Note_spacing::get_spacing (Grob *me, Item *right_col,
-                           Real base_space, Real increment)
+                           Spring base, Real increment)
 {
   vector<Item *> note_columns = Spacing_interface::left_note_columns (me);
   Real left_head_end = 0;
@@ -78,11 +81,12 @@ Note_spacing::get_spacing (Grob *me, Item *right_col,
     the full amount of space. We give them half the amount of space, but then
     adjust things so there are no collisions.
   */
+  Real ideal = base.distance () - increment + left_head_end;
   Drul_array<Skyline> skys = Spacing_interface::skylines (me, right_col);
   Real distance = skys[LEFT].distance (skys[RIGHT], robust_scm2double (right_col->get_property ("skyline-vertical-padding"), 0.0));
   Real min_dist = max (0.0, distance);
-  Real min_desired_space = left_head_end + (min_dist - left_head_end + base_space - increment) / 2;
-  Real ideal = base_space - increment + left_head_end;
+  Real min_desired_space = (ideal + min_dist) / 2;
+  base.set_min_distance (min_dist);
 
   /* If we have a NonMusical column on the right, we measure the ideal distance
      to the bar-line (if present), not the start of the column. */
@@ -107,12 +111,9 @@ Note_spacing::get_spacing (Grob *me, Item *right_col,
   ideal = max (ideal, min_desired_space);
   stem_dir_correction (me, right_col, increment, &ideal, &min_desired_space);
 
-  /* TODO: grace notes look bad when things are stretched. Should we increase
-     their stretch strength? */
-  Spring ret (max (0.0, ideal), min_dist);
-  ret.set_inverse_compress_strength (max (0.0, ideal - min_desired_space));
-  ret.set_inverse_stretch_strength (max (0.1, base_space - increment));
-  return ret;
+  base.set_distance (max (0.0, ideal));
+  base.set_inverse_compress_strength (max (0.0, ideal - min_desired_space));
+  return base;
 }
 
 static Real
index dd4003739012957e64e9db7d9af9800227992f04..c6b0199eb3ca047559727ef1c199f7c782a5d867 100644 (file)
@@ -101,7 +101,8 @@ get_measure_length (Grob *column)
   return 0;
 }
 
-Real
+/* Basic spring based on duration alone */
+Spring
 Spacing_spanner::note_spacing (Grob * /* me */,
                                Grob *lc,
                                Grob *rc,
@@ -144,30 +145,39 @@ Spacing_spanner::note_spacing (Grob * /* me */,
       shortest_playing_len = min (shortest_playing_len, *measure_len);
     }
 
-  Real dist = 0.0;
+  Spring ret;
   if (delta_t.main_part_ && !lwhen.grace_part_)
     {
-      dist = options->get_duration_space (shortest_playing_len.main_part_);
-      dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_);
+      // A spring of length and stiffness based on the controlling duration
+      Real len = options->get_duration_space (shortest_playing_len.main_part_);
+      Real min = options->increment_;  // canonical notehead width
+
+      // The portion of that spring proportional to the time between lc and rc
+      Real fraction = (delta_t.main_part_ / shortest_playing_len.main_part_);
+      ret = Spring (fraction * len, fraction * min);
+
+      // Stretch proportional to the space between canonical bare noteheads
+      ret.set_inverse_stretch_strength (fraction * max (0.0, (len - min)));
     }
   else if (delta_t.grace_part_)
     {
-      /*
-        Crude hack for spacing graces: we take the shortest space
-        available (namely the space for the global shortest note), and
-        multiply that by grace-space-factor
-      */
-      dist = options->get_duration_space (options->global_shortest_) / 2.0;
       Grob *grace_spacing = unsmob_grob (lc->get_object ("grace-spacing"));
       if (grace_spacing)
         {
           Spacing_options grace_opts;
           grace_opts.init_from_grob (grace_spacing);
-          dist = grace_opts.get_duration_space (delta_t.grace_part_);
+          Real len = grace_opts.get_duration_space (delta_t.grace_part_);
+          Real min = grace_opts.increment_;
+          ret = Spring (len, min);
+          // Grace notes should not stretch very much
+          ret.set_inverse_stretch_strength (grace_opts.increment_ / 2.0);
         }
-
+      else // Fallback to the old grace spacing: half that of the shortest note
+        ret = Spring (options->
+                      get_duration_space (options->global_shortest_) / 2.0,
+                      options->increment_ / 2.0);
     }
 
-  return dist;
+  return ret;
 }
 
index 2deae13b27dbf59568f8263e07c7c69e0e5748ba..25ed67fd4a1eeb37b639cbe5056a94b3ade4d1a5 100644 (file)
@@ -155,7 +155,7 @@ Spacing_spanner::set_distances_for_loose_col (Grob *me, Grob *c,
                 The note spacing should be taken from the musical
                 columns.
               */
-              Real base = note_spacing (me, lc, rc, options);
+              Spring base = note_spacing (me, lc, rc, options);
               Spring spring = Note_spacing::get_spacing (sp, rc, base, options->increment_);
 
               dists[d] = max (dists[d], spring.min_distance ());
index bf8e13593aa4ed71074dc1c2e52fc6a2b186baf0..5bdb8b8c5173f3b2c84e423b016d596b6b833ddb 100644 (file)
@@ -153,19 +153,14 @@ set_loose_columns (System *which, Column_x_positions const *posns)
           if (Paper_column::is_musical (next_col)
               && Paper_column::is_musical (loose_col))
             {
-              Real base = Spacing_spanner::note_spacing (spacing, loose_col, next_col,
-                                                         &options);
+              Spring spring = Spacing_spanner::note_spacing (spacing, loose_col,
+                                                             next_col, &options);
               if (Note_spacing::has_interface (spacing))
-                {
-                  Spring spring = Note_spacing::get_spacing (spacing, next_col, base, options.increment_);;
-                  base_note_space = spring.distance ();
-                  tight_note_space = spring.min_distance ();
-                }
-              else
-                {
-                  base_note_space = base;
-                  tight_note_space = base;
-                }
+                spring = Note_spacing::get_spacing (spacing, next_col,
+                                                    spring, options.increment_);
+
+              base_note_space = spring.distance ();
+              tight_note_space = spring.min_distance ();
             }
           else
             {
index 022c6a121949543fa05c7fd4b4fba680aa8b1fea..117ace071851fe946bb8f4907674ec23d76a73e5 100644 (file)
@@ -315,11 +315,13 @@ Spacing_spanner::musical_column_spacing (Grob *me,
                                          Item *right_col,
                                          Spacing_options const *options)
 {
-  Real base_note_space = note_spacing (me, left_col, right_col, options);
-  Spring spring;
+  Spring spring = note_spacing (me, left_col, right_col, options);
 
   if (options->stretch_uniformly_)
-    spring = Spring (base_note_space, 0.0);
+    {
+      spring.set_min_distance (0.0);
+      spring.set_default_strength ();
+    }
   else
     {
       vector<Spring> springs;
@@ -359,32 +361,20 @@ Spacing_spanner::musical_column_spacing (Grob *me,
                   grace_opts.init_from_grob (gsp);
                   inc = grace_opts.increment_;
                 }
-              springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, inc));
+              springs.push_back (Note_spacing::get_spacing (wish, right_col, spring, inc));
             }
         }
 
       if (springs.empty ())
         {
-
-          if (!Paper_column::is_musical (right_col))
-            {
-              /*
-                There used to be code that examined left_col->extent
-                (X_AXIS), but this is resulted in unexpected wide
-                spacing, because the width of s^"text" output is also
-                taken into account here.
-               */
-              spring = Spring (max (base_note_space, options->increment_),
-                               options->increment_);
-            }
-          else
+          if (Paper_column::is_musical (right_col))
             {
               /*
                 Min distance should be 0.0. If there are no spacing
                 wishes, we're probably dealing with polyphonic spacing
                 of hemiolas.
               */
-              spring = Spring (base_note_space, 0.0);
+              spring.set_min_distance (0.0);
             }
         }
       else