\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] }
}
>>
}
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 *);
};
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));
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;
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. */
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
return 0;
}
-Real
+/* Basic spring based on duration alone */
+Spring
Spacing_spanner::note_spacing (Grob * /* me */,
Grob *lc,
Grob *rc,
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;
}
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 ());
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
{
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;
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