2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
14 #include "spacing-spanner.hh"
15 #include "paper-column.hh"
16 #include "output-def.hh"
17 #include "paper-score.hh"
20 #include "note-spacing.hh"
23 #include "pointer-group-interface.hh"
24 #include "spaceable-grob.hh"
25 #include "staff-spacing.hh"
26 #include "spacing-interface.hh"
36 Spacing_spanner::effective_shortest_duration (Grob *me,
37 Link_array<Grob> const &all)
39 SCM preset_shortest = me->get_property ("common-shortest-duration");
40 Rational global_shortest;
41 if (unsmob_moment (preset_shortest))
42 global_shortest = unsmob_moment (preset_shortest)->main_part_;
45 global_shortest = Spacing_spanner::find_shortest (me, all);
46 if (be_verbose_global)
47 message (_f ("Global shortest duration is %s", global_shortest.to_string ()) + "\n");
50 return global_shortest;
54 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
56 Spacing_spanner::set_springs (SCM smob)
58 Grob *me = unsmob_grob (smob);
61 can't use get_system() ? --hwn.
63 Link_array<Grob> all (get_root_system (me)->columns ());
65 set_explicit_neighbor_columns (all);
67 Spacing_options options;
68 options.init_from_grob (me);
69 options.global_shortest_ = effective_shortest_duration (me, all);
71 prune_loose_columns (me, &all, &options);
72 set_implicit_neighbor_columns (all);
73 generate_springs (me, all, &options);
75 return SCM_UNSPECIFIED;
79 We want the shortest note that is also "common" in the piece, so we
80 find the shortest in each measure, and take the most frequently
83 This probably gives weird effects with modern music, where every
84 note has a different duration, but hey, don't write that kind of
88 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
93 Array<Rational> durations;
96 Rational shortest_in_measure;
97 shortest_in_measure.set_infinite (1);
99 for (int i = 0; i < cols.size (); i++)
101 if (Paper_column::is_musical (cols[i]))
103 Moment *when = unsmob_moment (cols[i]->get_property ("when"));
106 ignore grace notes for shortest notes.
108 if (when && when->grace_part_)
111 SCM st = cols[i]->get_property ("shortest-starter-duration");
112 Moment this_shortest = *unsmob_moment (st);
113 assert (this_shortest.to_bool ());
114 shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
116 else if (!shortest_in_measure.is_infinity ()
117 && Item::is_breakable (cols[i]))
120 for (; j < durations.size (); j++)
122 if (durations[j] > shortest_in_measure)
124 counts.insert (1, j);
125 durations.insert (shortest_in_measure, j);
128 else if (durations[j] == shortest_in_measure)
135 if (durations.size () == j)
137 durations.push (shortest_in_measure);
141 shortest_in_measure.set_infinite (1);
147 for (int i = durations.size (); i--;)
149 if (counts[i] >= max_count)
152 max_count = counts[i];
155 // printf ("duration %d/%d, count %d\n",
156 // durations[i].num (), durations[i].den (), counts[i]);
159 SCM bsd = me->get_property ("base-shortest-duration");
160 Rational d = Rational (1, 8);
161 if (Moment *m = unsmob_moment (bsd))
165 d = min (d, durations[max_idx]);
171 Spacing_spanner::generate_pair_spacing (Grob *me,
172 Paper_column *left_col, Paper_column *right_col,
173 Paper_column *after_right_col,
174 Spacing_options const *options)
176 if (Paper_column::is_musical (left_col))
178 bool skip_unbroken_right = false;
180 if (!Paper_column::is_musical (right_col)
181 && options->float_nonmusical_columns_
183 && Paper_column::is_musical (after_right_col))
184 skip_unbroken_right = true;
186 if (skip_unbroken_right)
189 TODO: should generate rods to prevent collisions.
191 musical_column_spacing (me, left_col, after_right_col, options);
192 right_col->set_object ("between-cols", scm_cons (left_col->self_scm (),
193 after_right_col->self_scm ()));
196 musical_column_spacing (me, left_col, right_col, options);
198 if (Item *rb = right_col->find_prebroken_piece (LEFT))
199 musical_column_spacing (me, left_col, rb, options);
204 The case that the right part is broken as well is rather
205 rare, but it is possible, eg. with a single empty measure,
206 or if one staff finishes a tad earlier than the rest.
208 Item *lb = left_col->find_prebroken_piece (RIGHT);
209 Item *rb = right_col->find_prebroken_piece (LEFT);
211 if (left_col && right_col)
212 breakable_column_spacing (me, left_col, right_col, options);
215 breakable_column_spacing (me, lb, right_col, options);
218 breakable_column_spacing (me, left_col, rb, options);
221 breakable_column_spacing (me, lb, rb, options);
226 Spacing_spanner::generate_springs (Grob *me,
227 Link_array<Grob> const &cols,
228 Spacing_options const *options)
230 Paper_column *next = 0;
231 Paper_column *next_next = 0;
232 for (int i = cols.size (); i--;)
234 Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
236 generate_pair_spacing (me, col, next, next_next, options);
244 Generate the space between two musical columns LEFT_COL and RIGHT_COL, given
245 spacing parameters INCR and SHORTEST.
248 Spacing_spanner::musical_column_spacing (Grob *me,
251 Spacing_options const *options)
253 bool expand_only = false;
254 Real base_note_space = note_spacing (me, left_col, right_col, options, &expand_only);
258 Real compound_note_space = 0.0;
259 Real compound_fixed_note_space = 0.0;
261 if (options->stretch_uniformly_)
262 compound_note_space = base_note_space;
267 extract_grob_set (left_col, "right-neighbors", neighbors);
270 We adjust the space following a note only if the next note
271 happens after the current note (this is set in the grob
272 property SPACING-SEQUENCE.
274 for (int i = 0; i < neighbors.size (); i++)
276 Grob *wish = neighbors[i];
278 Item *wish_rcol = Note_spacing::right_column (wish);
279 if (Note_spacing::left_column (wish) != left_col
280 || (wish_rcol != right_col && wish_rcol != right_col->original ()))
284 This is probably a waste of time in the case of polyphonic
286 if (Note_spacing::has_interface (wish))
291 Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed);
294 max_space = max (max_space, space);
295 max_fixed = max (max_fixed, fixed);
297 compound_note_space += space;
298 compound_fixed_note_space += fixed;
303 if (Paper_column::when_mom (right_col).grace_part_
304 && !Paper_column::when_mom (left_col).grace_part_)
307 Ugh. 0.8 is arbitrary.
309 compound_note_space *= 0.8;
312 if (compound_note_space < 0 || wish_count == 0)
314 compound_note_space = base_note_space;
315 compound_fixed_note_space = options->increment_;
317 else if (to_boolean (me->get_property ("average-spacing-wishes")))
319 compound_note_space /= wish_count;
320 compound_fixed_note_space /= wish_count;
324 compound_fixed_note_space = max_fixed;
325 compound_note_space = max_space;
329 Whatever we do, the fixed space is smaller than the real
332 TODO: this criterion is discontinuous in the derivative.
333 Maybe it should be continuous?
335 compound_fixed_note_space = min (compound_fixed_note_space,
336 compound_note_space);
339 Real inverse_strength = 1.0;
343 TODO: make sure that the space doesn't exceed the right margin.
345 if (options->packed_)
348 In packed mode, pack notes as tight as possible. This makes
349 sense mostly in combination with raggedright mode: the notes
350 are then printed at minimum distance. This is mostly useful
351 for ancient notation, but may also be useful for some flavours
352 of contemporary music. If not in raggedright mode, lily will
353 pack as much bars of music as possible into a line, but the
354 line will then be stretched to fill the whole linewidth.
356 inverse_strength = 1.0;
357 distance = compound_fixed_note_space;
361 inverse_strength = (compound_note_space - compound_fixed_note_space);
362 distance = compound_note_space;
365 Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength);
369 Read hints from L and generate springs.
372 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
373 Spacing_options const *options)
375 Real compound_fixed = 0.0;
376 Real compound_space = 0.0;
377 Real max_fixed = 0.0;
378 Real max_space = 0.0;
382 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
384 if (dt == Moment (0, 0))
386 extract_grob_set (l, "spacing-wishes", wishes);
388 for (int i = 0; i < wishes.size (); i++)
390 Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
392 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
399 column for the left one settings should be ok due automatic
403 assert (spacing_grob->get_column () == l);
405 Staff_spacing::get_spacing_params (spacing_grob,
406 &space, &fixed_space);
408 if (Paper_column::when_mom (r).grace_part_)
411 Correct for grace notes.
413 Ugh. The 0.8 is arbitrary.
418 max_space = max (max_space, space);
419 max_fixed = max (max_fixed, fixed_space);
421 compound_space += space;
422 compound_fixed += fixed_space;
427 if (compound_space <= 0.0 || !wish_count)
429 standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space,
435 if (to_boolean (me->get_property ("average-spacing-wishes")))
437 compound_space /= wish_count;
438 compound_fixed /= wish_count;
442 compound_fixed = max_fixed;
443 compound_space = max_space;
448 if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
449 compound_fixed = 0.0;
451 assert (!isinf (compound_space));
452 compound_space = max (compound_space, compound_fixed);
455 There used to be code that changed spacing depending on
456 raggedright setting. Ugh.
458 Do it more cleanly, or rename the property.
461 Real inverse_strength = (compound_space - compound_fixed);
462 Real distance = compound_space;
463 Spaceable_grob::add_spring (l, r, distance, inverse_strength);
466 ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
467 "The space taken by a note is dependent on its duration. Doubling a\n"
468 "duration adds spacing-increment to the space. The most common shortest\n"
469 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
470 "spaced proportonial to their duration.\n"
472 "Typically, the increment is the width of a black note head. In a\n"
473 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
474 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
475 "head width) A 16th note is followed by 0.5 note head width. The\n"
476 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
478 "average-spacing-wishes "
479 "grace-space-factor "
481 "base-shortest-duration "
482 "strict-note-spacing "
483 "shortest-duration-space "
484 "common-shortest-duration "
485 "uniform-stretching "
489 ADD_INTERFACE (Spacing_interface, "spacing-interface",
490 "Something to do with line breaking and spacing. "
491 "Kill this one after determining line breaks.",