2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "spacing-spanner.hh"
14 #include "spacing-options.hh"
15 #include "international.hh"
18 #include "note-spacing.hh"
19 #include "output-def.hh"
20 #include "paper-column.hh"
21 #include "paper-score.hh"
22 #include "pointer-group-interface.hh"
23 #include "separation-item.hh"
24 #include "skyline-pair.hh"
25 #include "spaceable-grob.hh"
26 #include "spacing-interface.hh"
27 #include "staff-spacing.hh"
32 Spacing_spanner::get_columns (Grob
*me_grob
)
34 Spanner
*me
= dynamic_cast<Spanner
*> (me_grob
);
35 vector
<Grob
*> all (get_root_system (me
)->used_columns ());
36 vsize start
= binary_search (all
, (Grob
*)me
->get_bound (LEFT
),
37 &Paper_column::less_than
);
38 vsize end
= binary_search (all
, (Grob
*) me
->get_bound (RIGHT
),
39 &Paper_column::less_than
);
41 all
= vector
<Grob
*>::vector
<Grob
*> (all
.begin () + start
,
42 all
.begin () + end
+ 1);
46 MAKE_SCHEME_CALLBACK (Spacing_spanner
, set_springs
, 1);
48 Spacing_spanner::set_springs (SCM smob
)
50 Spanner
*me
= unsmob_spanner (smob
);
53 can't use get_system () ? --hwn.
55 Spacing_options options
;
56 options
.init_from_grob (me
);
57 vector
<Grob
*> cols
= Spacing_spanner::get_columns (me
);
58 set_explicit_neighbor_columns (cols
);
60 prune_loose_columns (me
, &cols
, &options
);
61 set_implicit_neighbor_columns (cols
);
62 generate_springs (me
, cols
, &options
);
64 return SCM_UNSPECIFIED
;
68 We want the shortest note that is also "common" in the piece, so we
69 find the shortest in each measure, and take the most frequently
72 This probably gives weird effects with modern music, where every
73 note has a different duration, but hey, don't write that kind of
77 MAKE_SCHEME_CALLBACK (Spacing_spanner
, calc_common_shortest_duration
, 1);
79 Spacing_spanner::calc_common_shortest_duration (SCM grob
)
81 Spanner
*me
= unsmob_spanner (grob
);
83 vector
<Grob
*> cols (get_columns (me
));
88 vector
<Rational
> durations
;
91 Rational shortest_in_measure
;
92 shortest_in_measure
.set_infinite (1);
94 for (vsize i
= 0; i
< cols
.size (); i
++)
96 if (Paper_column::is_musical (cols
[i
]))
98 Moment
*when
= unsmob_moment (cols
[i
]->get_property ("when"));
101 ignore grace notes for shortest notes.
103 if (when
&& when
->grace_part_
)
106 SCM st
= cols
[i
]->get_property ("shortest-starter-duration");
107 Moment this_shortest
= *unsmob_moment (st
);
108 assert (this_shortest
.to_bool ());
109 shortest_in_measure
= min (shortest_in_measure
, this_shortest
.main_part_
);
111 else if (!shortest_in_measure
.is_infinity ()
112 && Paper_column::is_breakable (cols
[i
]))
115 for (; j
< durations
.size (); j
++)
117 if (durations
[j
] > shortest_in_measure
)
119 counts
.insert (counts
.begin () + j
, 1);
120 durations
.insert (durations
.begin () + j
, shortest_in_measure
);
123 else if (durations
[j
] == shortest_in_measure
)
130 if (durations
.size () == j
)
132 durations
.push_back (shortest_in_measure
);
133 counts
.push_back (1);
136 shortest_in_measure
.set_infinite (1);
140 vsize max_idx
= VPOS
;
142 for (vsize i
= durations
.size (); i
--;)
144 if (counts
[i
] >= max_count
)
147 max_count
= counts
[i
];
151 SCM bsd
= me
->get_property ("base-shortest-duration");
152 Rational d
= Rational (1, 8);
153 if (Moment
*m
= unsmob_moment (bsd
))
157 d
= min (d
, durations
[max_idx
]);
159 return Moment (d
).smobbed_copy ();
163 Spacing_spanner::generate_pair_spacing (Grob
*me
,
164 Paper_column
*left_col
, Paper_column
*right_col
,
165 Paper_column
*after_right_col
,
166 Spacing_options
const *options
)
168 if (Paper_column::is_musical (left_col
))
170 if (!Paper_column::is_musical (right_col
)
171 && (options
->float_nonmusical_columns_
|| to_boolean (right_col
->get_property ("maybe-loose")))
173 && Paper_column::is_musical (after_right_col
))
176 TODO: should generate rods to prevent collisions.
178 musical_column_spacing (me
, left_col
, after_right_col
, options
);
179 right_col
->set_object ("between-cols", scm_cons (left_col
->self_scm (),
180 after_right_col
->self_scm ()));
183 musical_column_spacing (me
, left_col
, right_col
, options
);
185 if (Item
*rb
= right_col
->find_prebroken_piece (LEFT
))
186 musical_column_spacing (me
, left_col
, rb
, options
);
191 The case that the right part is broken as well is rather
192 rare, but it is possible, eg. with a single empty measure,
193 or if one staff finishes a tad earlier than the rest.
195 Item
*lb
= left_col
->find_prebroken_piece (RIGHT
);
196 Item
*rb
= right_col
->find_prebroken_piece (LEFT
);
198 if (left_col
&& right_col
)
199 breakable_column_spacing (me
, left_col
, right_col
, options
);
202 breakable_column_spacing (me
, lb
, right_col
, options
);
205 breakable_column_spacing (me
, left_col
, rb
, options
);
208 breakable_column_spacing (me
, lb
, rb
, options
);
213 set_column_rods (vector
<Grob
*> const &cols
, Real padding
)
215 /* distances[i] will be the minimum distance between column i and column i+1 */
216 vector
<Real
> distances
;
218 for (vsize i
= 1; i
< cols
.size (); i
++)
220 assert (distances
.size () == i
-1);
222 Item
*r
= dynamic_cast<Item
*> (cols
[i
]);
223 Item
*rb
= r
->find_prebroken_piece (LEFT
);
225 if (Separation_item::is_empty (r
) && (!rb
|| Separation_item::is_empty (rb
)))
227 distances
.push_back (0);
231 Skyline_pair
*skys
= Skyline_pair::unsmob (r
->get_property ("horizontal-skylines"));
232 Real right_stickout
= skys
? (*skys
)[LEFT
].max_height () : 0.0;
234 /* min rather than max because right-stickout will be negative if the right-hand column
235 sticks out a lot to the left */
236 right_stickout
= min (right_stickout
,
237 Separation_item::conditional_skyline (r
, cols
[i
-1]).max_height ());
239 Drul_array
<Item
*> r_cols (r
, rb
);
240 Drul_array
<Real
> cur_dist (0.0, 0.0);
242 /* This is an inner loop and hence it is potentially quadratic. However, we only continue
243 as long as there is a rod to insert. Therefore, this loop will usually only execute
244 a constant number of times per iteration of the outer loop. */
245 for (vsize j
= i
; j
--;)
247 Item
*l
= dynamic_cast<Item
*> (cols
[j
]);
248 Item
*lb
= l
->find_prebroken_piece (RIGHT
);
249 Skyline_pair
*skys
= Skyline_pair::unsmob (l
->get_property ("horizontal-skylines"));
250 Real left_stickout
= skys
? (*skys
)[RIGHT
].max_height () : 0.0;
257 cur_dist
[d
] += distances
[j
];
259 Item
*r_col
= r_cols
[d
];
260 bool touches
= right_stickout
- left_stickout
+ cur_dist
[d
] < 0.0;
263 /* we set a distance for the line-starter column even if it's non-broken counterpart
264 doesn't touch the right column. */
266 Separation_item::set_distance (lb
, r_col
, padding
);
268 if (touches
|| j
== i
-1)
269 dist
= Separation_item::set_distance (l
, r_col
, padding
);
271 if (j
== i
-1 && d
== LEFT
)
272 distances
.push_back (dist
);
275 cur_dist
[d
] = distances
[j
];
277 done
= done
&& !touches
;
279 while (flip (&d
) != LEFT
&& rb
);
281 /* we need the empty check for gregorian notation, where there are a lot of
282 extraneous paper-columns that we need to skip over */
283 if (done
&& !Separation_item::is_empty (l
))
291 Spacing_spanner::generate_springs (Grob
*me
,
292 vector
<Grob
*> const &cols
,
293 Spacing_options
const *options
)
295 Paper_column
*prev
= dynamic_cast<Paper_column
*> (cols
[0]);
296 for (vsize i
= 1; i
< cols
.size (); i
++)
298 Paper_column
*col
= dynamic_cast<Paper_column
*> (cols
[i
]);
299 Paper_column
*next
= (i
+ 1 < cols
.size ()) ? dynamic_cast<Paper_column
*> (cols
[i
+1]) : 0;
301 generate_pair_spacing (me
, prev
, col
, next
, options
);
306 Real padding
= robust_scm2double (prev
->get_property ("padding"), 0.1);
307 set_column_rods (cols
, padding
);
311 Generate the space between two musical columns LEFT_COL and RIGHT_COL.
314 Spacing_spanner::musical_column_spacing (Grob
*me
,
317 Spacing_options
const *options
)
319 Real base_note_space
= note_spacing (me
, left_col
, right_col
, options
);
322 if (options
->stretch_uniformly_
)
323 spring
= Spring (base_note_space
, 0.0);
326 vector
<Spring
> springs
;
327 extract_grob_set (left_col
, "spacing-wishes", wishes
);
329 for (vsize i
= 0; i
< wishes
.size (); i
++)
331 Grob
*wish
= wishes
[i
];
332 if (Spacing_interface::left_column (wish
) != left_col
)
334 /* This shouldn't really happen, but the ancient music
335 stuff really messes up the spacing code, grrr
340 extract_grob_set (wish
, "right-items", right_items
);
341 bool found_matching_column
= false;
342 for (vsize j
= 0; j
< right_items
.size (); j
++)
344 Item
*it
= dynamic_cast<Item
*> (right_items
[j
]);
345 if (it
&& (right_col
== it
->get_column ()
346 || right_col
->original () == it
->get_column ()))
347 found_matching_column
= true;
351 This is probably a waste of time in the case of polyphonic
353 if (found_matching_column
&& Note_spacing::has_interface (wish
))
355 Real inc
= options
->increment_
;
356 Grob
*gsp
= unsmob_grob (left_col
->get_object ("grace-spacing"));
357 if (gsp
&& Paper_column::when_mom (left_col
).grace_part_
)
359 Spacing_options grace_opts
;
360 grace_opts
.init_from_grob (gsp
);
361 inc
= grace_opts
.increment_
;
363 springs
.push_back (Note_spacing::get_spacing (wish
, right_col
, base_note_space
, inc
));
367 if (springs
.empty ())
370 if (!Paper_column::is_musical (right_col
))
373 There used to be code that examined left_col->extent
374 (X_AXIS), but this is resulted in unexpected wide
375 spacing, because the width of s^"text" output is also
376 taken into account here.
378 spring
= Spring (max (base_note_space
, options
->increment_
),
379 options
->increment_
);
384 Min distance should be 0.0. If there are no spacing
385 wishes, we're probably dealing with polyphonic spacing
388 spring
= Spring (base_note_space
, 0.0);
392 spring
= merge_springs (springs
);
395 if (Paper_column::when_mom (right_col
).grace_part_
396 && !Paper_column::when_mom (left_col
).grace_part_
)
399 Ugh. 0.8 is arbitrary.
405 TODO: make sure that the space doesn't exceed the right margin.
407 if (options
->packed_
)
410 In packed mode, pack notes as tight as possible. This makes
411 sense mostly in combination with ragged-right mode: the notes
412 are then printed at minimum distance. This is mostly useful
413 for ancient notation, but may also be useful for some flavours
414 of contemporary music. If not in ragged-right mode, lily will
415 pack as many bars of music as possible into a line, but the
416 line will then be stretched to fill the whole linewidth.
418 Note that we don't actually pack things as tightly as possible:
419 we don't allow the next column to begin before this one ends.
421 /* FIXME: the else clause below is the "right" thing to do,
422 but we can't do it because of all the empty columns that the
423 ligature-engravers leave lying around. In that case, the extent of
424 the column is incorrect because it includes note-heads that aren't
425 there. We get around this by only including the column extent if
426 the left-hand column is "genuine". This is a dirty hack and it
427 should be fixed in the ligature-engravers. --jneem
429 if (Paper_column::is_extraneous_column_from_ligature (left_col
))
430 spring
.set_distance (spring
.min_distance ());
432 spring
.set_distance (max (left_col
->extent (left_col
, X_AXIS
)[RIGHT
],
433 spring
.min_distance ()));
435 spring
.set_inverse_stretch_strength (1.0);
438 Spaceable_grob::add_spring (left_col
, right_col
, spring
);
442 Check if COL fills the whole measure.
445 Spacing_spanner::fills_measure (Grob
*me
, Item
*left
, Item
*col
)
447 System
*sys
= get_root_system (me
);
448 Item
*next
= sys
->column (col
->get_column ()->get_rank () + 1);
452 if (Paper_column::is_musical (next
)
453 || Paper_column::is_musical (left
)
454 || !Paper_column::is_musical (col
)
455 || !Paper_column::is_used (next
))
459 Paper_column::when_mom (next
) - Paper_column::when_mom (col
);
461 Moment
*len
= unsmob_moment (left
->get_property ("measure-length"));
466 Don't check for exact measure length, since ending measures are
467 often shortened due to pickups.
469 if (dt
.main_part_
> len
->main_part_
/ Rational (2)
470 && (next
->is_broken ()
471 || next
->break_status_dir ()))
478 Read hints from L and generate springs.
481 Spacing_spanner::breakable_column_spacing (Grob
*me
, Item
*l
, Item
*r
,
482 Spacing_options
const *options
)
484 vector
<Spring
> springs
;
487 Moment dt
= Paper_column::when_mom (r
) - Paper_column::when_mom (l
);
489 if (dt
== Moment (0, 0))
491 extract_grob_set (l
, "spacing-wishes", wishes
);
493 for (vsize i
= 0; i
< wishes
.size (); i
++)
495 Item
*spacing_grob
= dynamic_cast<Item
*> (wishes
[i
]);
497 if (!spacing_grob
|| !Staff_spacing::has_interface (spacing_grob
))
501 column for the left one settings should be ok due automatic
504 assert (spacing_grob
->get_column () == l
);
506 springs
.push_back (Staff_spacing::get_spacing (spacing_grob
, r
));
510 if (springs
.empty ())
511 spring
= standard_breakable_column_spacing (me
, l
, r
, options
);
513 spring
= merge_springs (springs
);
515 if (Paper_column::when_mom (r
).grace_part_
)
518 Correct for grace notes.
520 Ugh. The 0.8 is arbitrary.
525 if (Paper_column::is_musical (r
)
526 && l
->break_status_dir () == CENTER
527 && fills_measure (me
, l
, r
))
529 Real full_measure_extra_space
= robust_scm2double (l
->get_property ("full-measure-extra-space"), 1.0);
530 spring
.set_distance (spring
.distance () + full_measure_extra_space
);
531 spring
.set_default_strength ();
534 if (options
->stretch_uniformly_
&& l
->break_status_dir () != RIGHT
)
536 spring
.set_min_distance (0.0);
537 spring
.set_default_strength ();
540 Spaceable_grob::add_spring (l
, r
, spring
);
543 ADD_INTERFACE (Spacing_spanner
,
544 "The space taken by a note is dependent on its duration."
545 " Doubling a duration adds @code{spacing-increment} to the"
546 " space. The most common shortest note gets"
547 " @code{shortest-duration-space}. Notes that are even shorter"
548 " are spaced proportonial to their duration.\n"
550 "Typically, the increment is the width of a black note head."
551 " In a piece with lots of 8th notes, and some 16th notes, the"
552 " eighth note gets a 2@tie{}note heads width (i.e., the space"
553 " following a note is a 1@tie{}note head width). A 16th note"
554 " is followed by 0.5 note head width. The quarter note is"
555 " followed by 3@tie{}NHW, the half by 4@tie{}NHW, etc.",
558 "average-spacing-wishes "
559 "base-shortest-duration "
560 "common-shortest-duration "
562 "shortest-duration-space "
564 "strict-grace-spacing "
565 "strict-note-spacing "
566 "uniform-stretching "