From f8416b959b1eb78740a329681d4d58ac6c090854 Mon Sep 17 00:00:00 2001 From: Keith OHara Date: Tue, 17 Dec 2013 16:41:51 -0800 Subject: [PATCH] note-spacing: stretch somewhat uniformly 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 | 18 +++--------- lily/include/note-spacing.hh | 2 +- lily/include/spacing-spanner.hh | 2 +- lily/note-spacing.cc | 21 +++++++------- lily/spacing-basic.cc | 36 +++++++++++++++--------- lily/spacing-determine-loose-columns.cc | 2 +- lily/spacing-loose-columns.cc | 19 +++++-------- lily/spacing-spanner.cc | 26 ++++++----------- 8 files changed, 56 insertions(+), 70 deletions(-) diff --git a/input/regression/spacing-multi-tuplet.ly b/input/regression/spacing-multi-tuplet.ly index bab9232a8d..4c84dad0d8 100644 --- a/input/regression/spacing-multi-tuplet.ly +++ b/input/regression/spacing-multi-tuplet.ly @@ -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] } } >> } diff --git a/lily/include/note-spacing.hh b/lily/include/note-spacing.hh index 9b8a4fd922..945362ab06 100644 --- a/lily/include/note-spacing.hh +++ b/lily/include/note-spacing.hh @@ -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 *); }; diff --git a/lily/include/spacing-spanner.hh b/lily/include/spacing-spanner.hh index 165f04a8ad..3f0590c4ee 100644 --- a/lily/include/spacing-spanner.hh +++ b/lily/include/spacing-spanner.hh @@ -45,7 +45,7 @@ private: static bool fills_measure (Grob *, Item *, Item *); public: static vector 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)); diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc index 1d0d21fbbb..e59aa6ec84 100644 --- a/lily/note-spacing.cc +++ b/lily/note-spacing.cc @@ -39,10 +39,13 @@ 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 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 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 diff --git a/lily/spacing-basic.cc b/lily/spacing-basic.cc index dd40037390..c6b0199eb3 100644 --- a/lily/spacing-basic.cc +++ b/lily/spacing-basic.cc @@ -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; } diff --git a/lily/spacing-determine-loose-columns.cc b/lily/spacing-determine-loose-columns.cc index 2deae13b27..25ed67fd4a 100644 --- a/lily/spacing-determine-loose-columns.cc +++ b/lily/spacing-determine-loose-columns.cc @@ -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 ()); diff --git a/lily/spacing-loose-columns.cc b/lily/spacing-loose-columns.cc index bf8e13593a..5bdb8b8c51 100644 --- a/lily/spacing-loose-columns.cc +++ b/lily/spacing-loose-columns.cc @@ -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 { diff --git a/lily/spacing-spanner.cc b/lily/spacing-spanner.cc index 022c6a1219..117ace0718 100644 --- a/lily/spacing-spanner.cc +++ b/lily/spacing-spanner.cc @@ -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 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 -- 2.39.2