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"
29 Spacing_spanner::effective_shortest_duration (Grob *me,
30 Link_array<Grob> const &all)
32 SCM preset_shortest = me->get_property ("common-shortest-duration");
33 Rational global_shortest;
34 if (unsmob_moment (preset_shortest))
35 global_shortest = unsmob_moment (preset_shortest)->main_part_;
38 global_shortest = Spacing_spanner::find_shortest (me, all);
39 if (be_verbose_global)
40 message (_f ("Global shortest duration is %s", global_shortest.to_string ()) + "\n");
43 return global_shortest;
47 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
49 Spacing_spanner::set_springs (SCM smob)
51 Grob *me = unsmob_grob (smob);
54 can't use get_system() ? --hwn.
56 Link_array<Grob> all (get_root_system (me)->columns ());
58 set_explicit_neighbor_columns (all);
60 Spacing_options options;
61 options.init_from_grob (me);
62 options.global_shortest_ = effective_shortest_duration (me, all);
64 prune_loose_columns (me, &all, &options);
65 set_implicit_neighbor_columns (all);
66 generate_springs (me, all, &options);
68 return SCM_UNSPECIFIED;
72 We want the shortest note that is also "common" in the piece, so we
73 find the shortest in each measure, and take the most frequently
76 This probably gives weird effects with modern music, where every
77 note has a different duration, but hey, don't write that kind of
81 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
86 Array<Rational> durations;
89 Rational shortest_in_measure;
90 shortest_in_measure.set_infinite (1);
92 for (int i = 0; i < cols.size (); i++)
94 if (Paper_column::is_musical (cols[i]))
96 Moment *when = unsmob_moment (cols[i]->get_property ("when"));
99 ignore grace notes for shortest notes.
101 if (when && when->grace_part_)
104 SCM st = cols[i]->get_property ("shortest-starter-duration");
105 Moment this_shortest = *unsmob_moment (st);
106 assert (this_shortest.to_bool ());
107 shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
109 else if (!shortest_in_measure.is_infinity ()
110 && Item::is_breakable (cols[i]))
113 for (; j < durations.size (); j++)
115 if (durations[j] > shortest_in_measure)
117 counts.insert (1, j);
118 durations.insert (shortest_in_measure, j);
121 else if (durations[j] == shortest_in_measure)
128 if (durations.size () == j)
130 durations.push (shortest_in_measure);
134 shortest_in_measure.set_infinite (1);
140 for (int i = durations.size (); i--;)
142 if (counts[i] >= max_count)
145 max_count = counts[i];
148 // printf ("duration %d/%d, count %d\n",
149 // durations[i].num (), durations[i].den (), counts[i]);
152 SCM bsd = me->get_property ("base-shortest-duration");
153 Rational d = Rational (1, 8);
154 if (Moment *m = unsmob_moment (bsd))
158 d = min (d, durations[max_idx]);
164 Spacing_spanner::generate_pair_spacing (Grob *me,
165 Paper_column *left_col, Paper_column *right_col,
166 Paper_column *after_right_col,
167 Spacing_options const *options)
169 if (Paper_column::is_musical (left_col))
171 bool skip_unbroken_right = false;
173 if (!Paper_column::is_musical (right_col)
174 && options->float_nonmusical_columns_
176 && Paper_column::is_musical (after_right_col))
177 skip_unbroken_right = true;
179 if (skip_unbroken_right)
182 TODO: should generate rods to prevent collisions.
184 musical_column_spacing (me, left_col, after_right_col, options);
185 right_col->set_object ("between-cols", scm_cons (left_col->self_scm (),
186 after_right_col->self_scm ()));
189 musical_column_spacing (me, left_col, right_col, options);
191 if (Item *rb = right_col->find_prebroken_piece (LEFT))
192 musical_column_spacing (me, left_col, rb, options);
197 The case that the right part is broken as well is rather
198 rare, but it is possible, eg. with a single empty measure,
199 or if one staff finishes a tad earlier than the rest.
201 Item *lb = left_col->find_prebroken_piece (RIGHT);
202 Item *rb = right_col->find_prebroken_piece (LEFT);
204 if (left_col && right_col)
205 breakable_column_spacing (me, left_col, right_col, options);
208 breakable_column_spacing (me, lb, right_col, options);
211 breakable_column_spacing (me, left_col, rb, options);
214 breakable_column_spacing (me, lb, rb, options);
219 Spacing_spanner::generate_springs (Grob *me,
220 Link_array<Grob> const &cols,
221 Spacing_options const *options)
223 Paper_column *next = 0;
224 Paper_column *next_next = 0;
225 for (int i = cols.size (); i--;)
227 Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
229 generate_pair_spacing (me, col, next, next_next, options);
237 Generate the space between two musical columns LEFT_COL and RIGHT_COL, given
238 spacing parameters INCR and SHORTEST.
241 Spacing_spanner::musical_column_spacing (Grob *me,
244 Spacing_options const *options)
246 bool expand_only = false;
247 Real base_note_space = note_spacing (me, left_col, right_col, options, &expand_only);
251 Real compound_note_space = 0.0;
252 Real compound_fixed_note_space = 0.0;
254 if (options->stretch_uniformly_)
255 compound_note_space = base_note_space;
260 extract_grob_set (left_col, "right-neighbors", neighbors);
263 We adjust the space following a note only if the next note
264 happens after the current note (this is set in the grob
265 property SPACING-SEQUENCE.
267 for (int i = 0; i < neighbors.size (); i++)
269 Grob *wish = neighbors[i];
271 Item *wish_rcol = Note_spacing::right_column (wish);
272 if (Note_spacing::left_column (wish) != left_col
273 || (wish_rcol != right_col && wish_rcol != right_col->original ()))
277 This is probably a waste of time in the case of polyphonic
279 if (Note_spacing::has_interface (wish))
284 Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed);
287 max_space = max (max_space, space);
288 max_fixed = max (max_fixed, fixed);
290 compound_note_space += space;
291 compound_fixed_note_space += fixed;
296 if (Paper_column::when_mom (right_col).grace_part_
297 && !Paper_column::when_mom (left_col).grace_part_)
300 Ugh. 0.8 is arbitrary.
302 compound_note_space *= 0.8;
305 if (compound_note_space < 0 || wish_count == 0)
307 compound_note_space = base_note_space;
308 compound_fixed_note_space = options->increment_;
310 else if (to_boolean (me->get_property ("average-spacing-wishes")))
312 compound_note_space /= wish_count;
313 compound_fixed_note_space /= wish_count;
317 compound_fixed_note_space = max_fixed;
318 compound_note_space = max_space;
322 Whatever we do, the fixed space is smaller than the real
325 TODO: this criterion is discontinuous in the derivative.
326 Maybe it should be continuous?
328 compound_fixed_note_space = min (compound_fixed_note_space,
329 compound_note_space);
332 Real inverse_strength = 1.0;
336 TODO: make sure that the space doesn't exceed the right margin.
338 if (options->packed_)
341 In packed mode, pack notes as tight as possible. This makes
342 sense mostly in combination with raggedright mode: the notes
343 are then printed at minimum distance. This is mostly useful
344 for ancient notation, but may also be useful for some flavours
345 of contemporary music. If not in raggedright mode, lily will
346 pack as much bars of music as possible into a line, but the
347 line will then be stretched to fill the whole linewidth.
349 inverse_strength = 1.0;
350 distance = compound_fixed_note_space;
354 inverse_strength = (compound_note_space - compound_fixed_note_space);
355 distance = compound_note_space;
358 Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength);
362 Read hints from L and generate springs.
365 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
366 Spacing_options const *options)
368 Real compound_fixed = 0.0;
369 Real compound_space = 0.0;
370 Real max_fixed = 0.0;
371 Real max_space = 0.0;
375 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
377 if (dt == Moment (0, 0))
379 extract_grob_set (l, "spacing-wishes", wishes);
381 for (int i = 0; i < wishes.size (); i++)
383 Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
385 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
392 column for the left one settings should be ok due automatic
396 assert (spacing_grob->get_column () == l);
398 Staff_spacing::get_spacing_params (spacing_grob,
399 &space, &fixed_space);
401 if (Paper_column::when_mom (r).grace_part_)
404 Correct for grace notes.
406 Ugh. The 0.8 is arbitrary.
411 max_space = max (max_space, space);
412 max_fixed = max (max_fixed, fixed_space);
414 compound_space += space;
415 compound_fixed += fixed_space;
420 if (compound_space <= 0.0 || !wish_count)
422 standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space,
428 if (to_boolean (me->get_property ("average-spacing-wishes")))
430 compound_space /= wish_count;
431 compound_fixed /= wish_count;
435 compound_fixed = max_fixed;
436 compound_space = max_space;
441 if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
442 compound_fixed = 0.0;
444 assert (!isinf (compound_space));
445 compound_space = max (compound_space, compound_fixed);
448 There used to be code that changed spacing depending on
449 raggedright setting. Ugh.
451 Do it more cleanly, or rename the property.
454 Real inverse_strength = (compound_space - compound_fixed);
455 Real distance = compound_space;
456 Spaceable_grob::add_spring (l, r, distance, inverse_strength);
459 ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
460 "The space taken by a note is dependent on its duration. Doubling a\n"
461 "duration adds spacing-increment to the space. The most common shortest\n"
462 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
463 "spaced proportonial to their duration.\n"
465 "Typically, the increment is the width of a black note head. In a\n"
466 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
467 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
468 "head width) A 16th note is followed by 0.5 note head width. The\n"
469 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
471 "average-spacing-wishes "
472 "grace-space-factor "
474 "base-shortest-duration "
475 "strict-note-spacing "
476 "shortest-duration-space "
477 "common-shortest-duration "
478 "uniform-stretching "
482 ADD_INTERFACE (Spacing_interface, "spacing-interface",
483 "Something to do with line breaking and spacing. "
484 "Kill this one after determining line breaks.",