2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2007 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 "spaceable-grob.hh"
25 #include "spacing-interface.hh"
26 #include "staff-spacing.hh"
31 Spacing_spanner::get_columns (Grob *me_grob)
33 Spanner *me = dynamic_cast<Spanner*> (me_grob);
34 vector<Grob*> all (get_root_system (me)->used_columns ());
35 vsize start = binary_search (all, (Grob*)me->get_bound (LEFT),
36 &Paper_column::less_than);
37 vsize end = binary_search (all, (Grob*) me->get_bound (RIGHT),
38 &Paper_column::less_than);
40 all = vector<Grob*>::vector<Grob*> (all.begin () + start,
41 all.begin () + end + 1);
45 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
47 Spacing_spanner::set_springs (SCM smob)
49 Spanner *me = unsmob_spanner (smob);
52 can't use get_system () ? --hwn.
54 Spacing_options options;
55 options.init_from_grob (me);
56 vector<Grob*> cols = Spacing_spanner::get_columns (me);
57 set_explicit_neighbor_columns (cols);
59 prune_loose_columns (me, &cols, &options);
60 set_implicit_neighbor_columns (cols);
61 generate_springs (me, cols, &options);
63 return SCM_UNSPECIFIED;
67 We want the shortest note that is also "common" in the piece, so we
68 find the shortest in each measure, and take the most frequently
71 This probably gives weird effects with modern music, where every
72 note has a different duration, but hey, don't write that kind of
76 MAKE_SCHEME_CALLBACK (Spacing_spanner, calc_common_shortest_duration, 1);
78 Spacing_spanner::calc_common_shortest_duration (SCM grob)
80 Spanner *me = unsmob_spanner (grob);
82 vector<Grob*> cols (get_columns (me));
87 vector<Rational> durations;
90 Rational shortest_in_measure;
91 shortest_in_measure.set_infinite (1);
93 for (vsize i = 0; i < cols.size (); i++)
95 if (Paper_column::is_musical (cols[i]))
97 Moment *when = unsmob_moment (cols[i]->get_property ("when"));
100 ignore grace notes for shortest notes.
102 if (when && when->grace_part_)
105 SCM st = cols[i]->get_property ("shortest-starter-duration");
106 Moment this_shortest = *unsmob_moment (st);
107 assert (this_shortest.to_bool ());
108 shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
110 else if (!shortest_in_measure.is_infinity ()
111 && Paper_column::is_breakable (cols[i]))
114 for (; j < durations.size (); j++)
116 if (durations[j] > shortest_in_measure)
118 counts.insert (counts.begin () + j, 1);
119 durations.insert (durations.begin () + j, shortest_in_measure);
122 else if (durations[j] == shortest_in_measure)
129 if (durations.size () == j)
131 durations.push_back (shortest_in_measure);
132 counts.push_back (1);
135 shortest_in_measure.set_infinite (1);
141 for (vsize i = durations.size (); i--;)
143 if (counts[i] >= max_count)
146 max_count = counts[i];
150 SCM bsd = me->get_property ("base-shortest-duration");
151 Rational d = Rational (1, 8);
152 if (Moment *m = unsmob_moment (bsd))
156 d = min (d, durations[max_idx]);
158 return Moment (d).smobbed_copy ();
162 Spacing_spanner::generate_pair_spacing (Grob *me,
163 Paper_column *left_col, Paper_column *right_col,
164 Paper_column *after_right_col,
165 Spacing_options const *options)
167 if (Paper_column::is_musical (left_col))
169 if (!Paper_column::is_musical (right_col)
170 && options->float_nonmusical_columns_
172 && Paper_column::is_musical (after_right_col))
175 TODO: should generate rods to prevent collisions.
177 musical_column_spacing (me, left_col, after_right_col, options);
178 right_col->set_object ("between-cols", scm_cons (left_col->self_scm (),
179 after_right_col->self_scm ()));
182 musical_column_spacing (me, left_col, right_col, options);
184 if (Item *rb = right_col->find_prebroken_piece (LEFT))
185 musical_column_spacing (me, left_col, rb, options);
190 The case that the right part is broken as well is rather
191 rare, but it is possible, eg. with a single empty measure,
192 or if one staff finishes a tad earlier than the rest.
194 Item *lb = left_col->find_prebroken_piece (RIGHT);
195 Item *rb = right_col->find_prebroken_piece (LEFT);
197 if (left_col && right_col)
198 breakable_column_spacing (me, left_col, right_col, options);
201 breakable_column_spacing (me, lb, right_col, options);
204 breakable_column_spacing (me, left_col, rb, options);
207 breakable_column_spacing (me, lb, rb, options);
212 set_column_rods (vector<Grob*> const &cols, Real padding)
214 /* distances[i] will be the minimum distance between column i and column i+1 */
215 vector<Real> distances;
217 for (vsize i = 1; i < cols.size (); i++)
219 assert (distances.size () == i-1);
221 Item *r = dynamic_cast<Item*> (cols[i]);
222 Item *rb = r->find_prebroken_piece (LEFT);
224 if (Separation_item::is_empty (r) && (!rb || Separation_item::is_empty (rb)))
226 distances.push_back (0);
230 Skyline_pair *skys = Skyline_pair::unsmob (r->get_property ("horizontal-skylines"));
231 Real right_stickout = skys ? (*skys)[LEFT].max_height () : 0.0;
233 /* min rather than max because right-stickout will be negative if the right-hand column
234 sticks out a lot to the left */
235 right_stickout = min (right_stickout,
236 Separation_item::conditional_skyline (r, cols[i-1]).max_height ());
238 Drul_array<Item*> r_cols (r, rb);
239 Drul_array<Real> cur_dist (0.0, 0.0);
241 /* This is an inner loop and hence it is potentially quadratic. However, we only continue
242 as long as there is a rod to insert. Therefore, this loop will usually only execute
243 a constant number of times per iteration of the outer loop. */
244 for (vsize j = i; j--;)
246 Item *l = dynamic_cast<Item*> (cols[j]);
247 Item *lb = l->find_prebroken_piece (RIGHT);
248 Skyline_pair *skys = Skyline_pair::unsmob (l->get_property ("horizontal-skylines"));
249 Real left_stickout = skys ? (*skys)[RIGHT].max_height () : 0.0;
256 cur_dist[d] += distances[j];
258 Item *r_col = r_cols[d];
259 bool touches = right_stickout - left_stickout + cur_dist[d] < 0.0;
262 /* we set a distance for the line-starter column even if it's non-broken counterpart
263 doesn't touch the right column. */
265 Separation_item::set_distance (lb, r_col, padding);
267 if (touches || j == i-1)
268 dist = Separation_item::set_distance (l, r_col, padding);
270 if (j == i-1 && d == LEFT)
271 distances.push_back (dist);
274 cur_dist[d] = distances[j];
276 done = done && !touches;
278 while (flip (&d) != LEFT && rb);
280 /* we need the empty check for gregorian notation, where there are a lot of
281 extraneous paper-columns that we need to skip over */
282 if (done && !Separation_item::is_empty (l))
290 Spacing_spanner::generate_springs (Grob *me,
291 vector<Grob*> const &cols,
292 Spacing_options const *options)
294 Paper_column *prev = dynamic_cast<Paper_column*> (cols[0]);
295 for (vsize i = 1; i < cols.size (); i++)
297 Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
298 Paper_column *next = (i + 1 < cols.size ()) ? dynamic_cast<Paper_column *> (cols[i+1]) : 0;
300 generate_pair_spacing (me, prev, col, next, options);
305 set_column_rods (cols, 0.1); // FIXME: padding
309 Generate the space between two musical columns LEFT_COL and RIGHT_COL.
312 Spacing_spanner::musical_column_spacing (Grob *me,
315 Spacing_options const *options)
317 Real base_note_space = note_spacing (me, left_col, right_col, options);
320 if (options->stretch_uniformly_)
321 spring = Spring (base_note_space, 0.0);
324 vector<Spring> springs;
325 extract_grob_set (left_col, "right-neighbors", neighbors);
327 for (vsize i = 0; i < neighbors.size (); i++)
329 Grob *wish = neighbors[i];
331 Item *wish_rcol = Spacing_interface::right_column (wish);
332 if (Spacing_interface::left_column (wish) != left_col
333 || (wish_rcol != right_col && wish_rcol != right_col->original ()))
337 This is probably a waste of time in the case of polyphonic
339 if (Note_spacing::has_interface (wish))
340 springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_));
343 if (springs.empty ())
346 if (!Paper_column::is_musical (right_col))
349 There used to be code that examined left_col->extent
350 (X_AXIS), but this is resulted in unexpected wide
351 spacing, because the width of s^"text" output is also
352 taken into account here.
354 spring = Spring (max (base_note_space, options->increment_),
355 options->increment_);
360 Fixed should be 0.0. If there are no spacing wishes, we're
361 likely dealing with polyphonic spacing of hemiolas.
363 We used to have min_distance_ = options->increment_
365 but this can lead to numeric instability problems when we
368 inverse_strength = (distance_ - min_distance_)
371 spring = Spring (base_note_space, 0.0);
375 spring = merge_springs (springs);
378 if (Paper_column::when_mom (right_col).grace_part_
379 && !Paper_column::when_mom (left_col).grace_part_)
382 Ugh. 0.8 is arbitrary.
388 TODO: make sure that the space doesn't exceed the right margin.
390 if (options->packed_)
393 In packed mode, pack notes as tight as possible. This makes
394 sense mostly in combination with raggedright mode: the notes
395 are then printed at minimum distance. This is mostly useful
396 for ancient notation, but may also be useful for some flavours
397 of contemporary music. If not in raggedright mode, lily will
398 pack as much bars of music as possible into a line, but the
399 line will then be stretched to fill the whole linewidth.
401 spring.set_distance (spring.min_distance ());
402 spring.set_inverse_stretch_strength (1.0);
405 Spaceable_grob::add_spring (left_col, right_col, spring);
409 Check if COL fills the whole measure.
412 Spacing_spanner::fills_measure (Grob *me, Item *left, Item *col)
414 System *sys = get_root_system (me);
415 Item *next = sys->column (col->get_column ()->get_rank () + 1);
419 if (Paper_column::is_musical (next)
420 || Paper_column::is_musical (left)
421 || !Paper_column::is_musical (col)
422 || !Paper_column::is_used (next))
426 Paper_column::when_mom (next) - Paper_column::when_mom (col);
428 Moment *len = unsmob_moment (left->get_property ("measure-length"));
433 Don't check for exact measure length, since ending measures are
434 often shortened due to pickups.
436 if (dt.main_part_ > len->main_part_ / Rational (2)
437 && (next->is_broken ()
438 || next->break_status_dir ()))
445 Read hints from L and generate springs.
448 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
449 Spacing_options const *options)
451 vector<Spring> springs;
454 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
456 if (dt == Moment (0, 0))
458 extract_grob_set (l, "spacing-wishes", wishes);
460 for (vsize i = 0; i < wishes.size (); i++)
462 Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
464 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
468 column for the left one settings should be ok due automatic
471 assert (spacing_grob->get_column () == l);
473 springs.push_back (Staff_spacing::get_spacing (spacing_grob, r));
477 if (springs.empty ())
478 spring = standard_breakable_column_spacing (me, l, r, options);
480 spring = merge_springs (springs);
482 if (Paper_column::when_mom (r).grace_part_)
485 Correct for grace notes.
487 Ugh. The 0.8 is arbitrary.
492 if (Paper_column::is_musical (r)
493 && l->break_status_dir () == CENTER
494 && fills_measure (me, l, r))
496 spring.set_distance (spring.distance () + 1.0);
497 spring.set_default_strength ();
500 if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
502 spring.set_min_distance (0.0);
503 spring.set_default_strength ();
506 Spaceable_grob::add_spring (l, r, spring);
509 ADD_INTERFACE (Spacing_spanner,
510 "The space taken by a note is dependent on its duration. Doubling a\n"
511 "duration adds spacing-increment to the space. The most common shortest\n"
512 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
513 "spaced proportonial to their duration.\n"
515 "Typically, the increment is the width of a black note head. In a\n"
516 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
517 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
518 "head width) A 16th note is followed by 0.5 note head width. The\n"
519 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
522 "average-spacing-wishes "
523 "base-shortest-duration "
524 "common-shortest-duration "
526 "shortest-duration-space "
528 "strict-grace-spacing "
529 "strict-note-spacing "
530 "uniform-stretching "