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))
341 Real inc = options->increment_;
342 Grob *gsp = unsmob_grob (left_col->get_object ("grace-spacing"));
343 if (gsp && Paper_column::when_mom (left_col).grace_part_)
345 Spacing_options grace_opts;
346 grace_opts.init_from_grob (gsp);
347 inc = grace_opts.increment_;
349 springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, inc));
353 if (springs.empty ())
356 if (!Paper_column::is_musical (right_col))
359 There used to be code that examined left_col->extent
360 (X_AXIS), but this is resulted in unexpected wide
361 spacing, because the width of s^"text" output is also
362 taken into account here.
364 spring = Spring (max (base_note_space, options->increment_),
365 options->increment_);
370 Fixed should be 0.0. If there are no spacing wishes, we're
371 likely dealing with polyphonic spacing of hemiolas.
373 We used to have min_distance_ = options->increment_
375 but this can lead to numeric instability problems when we
378 inverse_strength = (distance_ - min_distance_)
381 spring = Spring (base_note_space, 0.0);
385 spring = merge_springs (springs);
388 if (Paper_column::when_mom (right_col).grace_part_
389 && !Paper_column::when_mom (left_col).grace_part_)
392 Ugh. 0.8 is arbitrary.
398 TODO: make sure that the space doesn't exceed the right margin.
400 if (options->packed_)
403 In packed mode, pack notes as tight as possible. This makes
404 sense mostly in combination with raggedright mode: the notes
405 are then printed at minimum distance. This is mostly useful
406 for ancient notation, but may also be useful for some flavours
407 of contemporary music. If not in raggedright mode, lily will
408 pack as much bars of music as possible into a line, but the
409 line will then be stretched to fill the whole linewidth.
411 spring.set_distance (spring.min_distance ());
412 spring.set_inverse_stretch_strength (1.0);
415 Spaceable_grob::add_spring (left_col, right_col, spring);
419 Check if COL fills the whole measure.
422 Spacing_spanner::fills_measure (Grob *me, Item *left, Item *col)
424 System *sys = get_root_system (me);
425 Item *next = sys->column (col->get_column ()->get_rank () + 1);
429 if (Paper_column::is_musical (next)
430 || Paper_column::is_musical (left)
431 || !Paper_column::is_musical (col)
432 || !Paper_column::is_used (next))
436 Paper_column::when_mom (next) - Paper_column::when_mom (col);
438 Moment *len = unsmob_moment (left->get_property ("measure-length"));
443 Don't check for exact measure length, since ending measures are
444 often shortened due to pickups.
446 if (dt.main_part_ > len->main_part_ / Rational (2)
447 && (next->is_broken ()
448 || next->break_status_dir ()))
455 Read hints from L and generate springs.
458 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
459 Spacing_options const *options)
461 vector<Spring> springs;
464 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
466 if (dt == Moment (0, 0))
468 extract_grob_set (l, "spacing-wishes", wishes);
470 for (vsize i = 0; i < wishes.size (); i++)
472 Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
474 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
478 column for the left one settings should be ok due automatic
481 assert (spacing_grob->get_column () == l);
483 springs.push_back (Staff_spacing::get_spacing (spacing_grob, r));
487 if (springs.empty ())
488 spring = standard_breakable_column_spacing (me, l, r, options);
490 spring = merge_springs (springs);
492 if (Paper_column::when_mom (r).grace_part_)
495 Correct for grace notes.
497 Ugh. The 0.8 is arbitrary.
502 if (Paper_column::is_musical (r)
503 && l->break_status_dir () == CENTER
504 && fills_measure (me, l, r))
506 spring.set_distance (spring.distance () + 1.0);
507 spring.set_default_strength ();
510 if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
512 spring.set_min_distance (0.0);
513 spring.set_default_strength ();
516 Spaceable_grob::add_spring (l, r, spring);
519 ADD_INTERFACE (Spacing_spanner,
520 "The space taken by a note is dependent on its duration. Doubling a\n"
521 "duration adds spacing-increment to the space. The most common shortest\n"
522 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
523 "spaced proportonial to their duration.\n"
525 "Typically, the increment is the width of a black note head. In a\n"
526 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
527 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
528 "head width) A 16th note is followed by 0.5 note head width. The\n"
529 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
532 "average-spacing-wishes "
533 "base-shortest-duration "
534 "common-shortest-duration "
536 "shortest-duration-space "
538 "strict-grace-spacing "
539 "strict-note-spacing "
540 "uniform-stretching "