2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
15 #include "output-def.hh"
16 #include "paper-score.hh"
17 #include "paper-column.hh"
19 #include "note-spacing.hh"
22 #include "staff-spacing.hh"
24 #include "paper-column.hh"
25 #include "spaceable-grob.hh"
26 #include "break-align-interface.hh"
27 #include "spacing-interface.hh"
30 TODO: this file/class is too complex. Should figure out how to chop
37 static void standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
38 Real *fixed, Real *space, Moment);
40 static Real default_bar_spacing (Grob *, Grob *, Grob *, Moment);
41 static Real note_spacing (Grob *, Grob *, Grob *, Moment, bool *);
42 static Real get_duration_space (Grob *, Moment dur, Rational shortest, bool *);
43 static Rational find_shortest (Grob *, Link_array<Grob> const &);
44 static void breakable_column_spacing (Grob *, Item *l, Item *r, Moment);
45 static void find_loose_columns () {}
46 static void prune_loose_columns (Grob *, Link_array<Grob> *cols, Rational);
47 static void find_loose_columns (Link_array<Grob> cols);
48 static void set_explicit_neighbor_columns (Link_array<Grob> cols);
49 static void set_implicit_neighbor_columns (Link_array<Grob> cols);
50 static void do_measure (Rational, Grob *me, Link_array<Grob> *cols);
51 static void musical_column_spacing (Grob *, Item *, Item *, Real, Rational);
52 DECLARE_SCHEME_CALLBACK (set_springs, (SCM));
53 static bool has_interface (Grob *);
57 Return whether COL is fixed to its neighbors by some kind of spacing
61 If in doubt, then we're not loose; the spacing engine should space
62 for it, risking suboptimal spacing.
64 (Otherwise, we might risk core dumps, and other weird stuff.)
67 loose_column (Grob *l, Grob *c, Grob *r)
69 SCM rns = c->get_property ("right-neighbors");
70 SCM lns = c->get_property ("left-neighbors");
73 If this column doesn't have a proper neighbor, we should really
74 make it loose, but spacing it correctly is more than we can
77 (this happens in the following situation:
88 the column containing the clef is really loose, and should be
89 attached right to the first column, but that is a lot of work for
90 such a borderline case.)
93 if (!scm_is_pair (lns) || !scm_is_pair (rns))
96 Item *l_neighbor = dynamic_cast<Item *> (unsmob_grob (scm_car (lns)));
97 Item *r_neighbor = dynamic_cast<Item *> (unsmob_grob (scm_car (rns)));
99 if (!l_neighbor || !r_neighbor)
102 l_neighbor = l_neighbor->get_column ();
103 r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
105 if (l == l_neighbor && r == r_neighbor)
108 if (!l_neighbor || !r_neighbor)
112 Only declare loose if the bounds make a little sense. This means
113 some cases (two isolated, consecutive clef changes) won't be
114 nicely folded, but hey, then don't do that.
116 if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
117 && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))))
123 A rather hairy check, but we really only want to move around clefs. (anything else?)
125 in any case, we don't want to move bar lines.
127 for (SCM e = c->get_property ("elements"); scm_is_pair (e); e = scm_cdr (e))
129 Grob *g = unsmob_grob (scm_car (e));
130 if (g && Break_align_interface::has_interface (g))
132 for (SCM s = g->get_property ("elements"); scm_is_pair (s);
135 Grob *h = unsmob_grob (scm_car (s));
138 ugh. -- fix staff-bar name?
140 if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
150 Remove columns that are not tightly fitting from COLS. In the
151 removed columns, set 'between-cols to the columns where it is in
155 Spacing_spanner::prune_loose_columns (Grob *me, Link_array<Grob> *cols, Rational shortest)
157 Link_array<Grob> newcols;
158 Real increment = robust_scm2double (me->get_property ("spacing-increment"), 1.2);
159 for (int i = 0; i < cols->size (); i++)
161 if (Item::is_breakable (cols->elem (i)) || Paper_column::is_musical (cols->elem (i)))
163 newcols.push (cols->elem (i));
167 Grob *c = cols->elem (i);
168 if (loose_column (cols->elem (i - 1), c, cols->elem (i + 1)))
170 SCM lns = c->get_property ("left-neighbors");
171 lns = scm_is_pair (lns) ? scm_car (lns) : SCM_BOOL_F;
173 SCM rns = c->get_property ("right-neighbors");
174 rns = scm_is_pair (rns) ? scm_car (rns) : SCM_BOOL_F;
177 Either object can be non existent, if the score ends
180 rns = scm_car (unsmob_grob (rns)->get_property ("right-items"));
181 c->set_property ("between-cols", scm_cons (lns,
185 Set distance constraints for loose columns
187 Drul_array<Grob *> next_door;
188 next_door[LEFT] = cols->elem (i - 1);
189 next_door[RIGHT] = cols->elem (i + 1);
191 Drul_array<Real> dists (0, 0);
196 Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
197 Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
199 for (SCM s = lc->get_property ("spacing-wishes");
200 scm_is_pair (s); s = scm_cdr (s))
202 Grob *sp = unsmob_grob (scm_car (s));
203 if (Note_spacing::left_column (sp) != lc
204 || Note_spacing::right_column (sp) != rc)
214 The note spacing should be taken from the musical
218 Real base = note_spacing (me, lc, rc, shortest, &dummy);
219 Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
223 dists[d] = dists[d] >? space;
227 Real space, fixed_space;
228 Staff_spacing::get_spacing_params (sp,
229 &space, &fixed_space);
231 dists[d] = dists[d] >? fixed_space;
236 while (flip (&d) != LEFT);
239 r.distance_ = dists[LEFT] + dists[RIGHT];
240 r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->elem (i - 1));
241 r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->elem (i + 1));
255 Set neighboring columns determined by the spacing-wishes grob property.
258 Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
260 for (int i = 0; i < cols.size (); i++)
262 SCM right_neighbors = SCM_EOL;
263 int min_rank = 100000; // inf.
266 SCM wishes = cols[i]->get_property ("spacing-wishes");
267 for (SCM s = wishes; scm_is_pair (s); s = scm_cdr (s))
269 Item *wish = dynamic_cast<Item *> (unsmob_grob (scm_car (s)));
271 Item *lc = wish->get_column ();
272 Grob *right = Note_spacing::right_column (wish);
277 Item *rc = dynamic_cast<Item *> (right);
279 int right_rank = Paper_column::get_rank (rc);
280 int left_rank = Paper_column::get_rank (lc);
283 update the left column.
285 if (right_rank <= min_rank)
287 if (right_rank < min_rank)
288 right_neighbors = SCM_EOL;
290 min_rank = right_rank;
291 right_neighbors = scm_cons (wish->self_scm (), right_neighbors);
295 update the right column of the wish.
298 SCM left_neighs = rc->get_property ("left-neighbors");
299 if (scm_is_pair (left_neighs)
300 && unsmob_grob (scm_car (left_neighs)))
302 Item *it = dynamic_cast<Item *> (unsmob_grob (scm_car (left_neighs)));
303 maxrank = Paper_column::get_rank (it->get_column ());
306 if (left_rank >= maxrank)
308 if (left_rank > maxrank)
309 left_neighs = SCM_EOL;
311 left_neighs = scm_cons (wish->self_scm (), left_neighs);
312 rc->set_property ("left-neighbors", right_neighbors);
316 if (scm_is_pair (right_neighbors))
318 cols[i]->set_property ("right-neighbors", right_neighbors);
324 Set neighboring columns that have no left/right-neighbor set
325 yet. Only do breakable non-musical columns, and musical columns.
328 Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> cols)
330 for (int i = 0; i < cols.size (); i++)
332 Item *it = dynamic_cast<Item *> (cols[i]);
333 if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
336 // it->breakable || it->musical
339 sloppy with typnig left/right-neighbors should take list, but paper-column found instead.
341 SCM ln = cols[i] ->get_property ("left-neighbors");
342 if (!scm_is_pair (ln) && i)
344 cols[i]->set_property ("left-neighbors", scm_cons (cols[i - 1]->self_scm (), SCM_EOL));
347 SCM rn = cols[i] ->get_property ("right-neighbors");
348 if (!scm_is_pair (rn) && i < cols.size () - 1)
350 cols[i]->set_property ("right-neighbors", scm_cons (cols[i + 1]->self_scm (), SCM_EOL));
355 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
357 Spacing_spanner::set_springs (SCM smob)
359 Grob *me = unsmob_grob (smob);
362 can't use get_system() ? --hwn.
364 Link_array<Grob> all (me->pscore_->system_->columns ());
366 set_explicit_neighbor_columns (all);
368 SCM preset_shortest = me->get_property ("common-shortest-duration");
369 Rational global_shortest;
370 if (unsmob_moment (preset_shortest))
372 global_shortest = unsmob_moment (preset_shortest)->main_part_;
376 global_shortest = find_shortest (me, all);
377 if (be_verbose_global)
378 progress_indication (_f ("Global shortest duration is %s", global_shortest.to_string ()) + "\n");
380 prune_loose_columns (me, &all, global_shortest);
381 set_implicit_neighbor_columns (all);
384 for (int i = 1; i < all.size (); i++)
387 if (Item::is_breakable (sc))
389 Link_array<Grob> measure (all.slice (j, i + 1));
390 do_measure (global_shortest, me, &measure);
395 return SCM_UNSPECIFIED;
399 We want the shortest note that is also "common" in the piece, so we
400 find the shortest in each measure, and take the most frequently
403 This probably gives weird effects with modern music, where every
404 note has a different duration, but hey, don't write that kind of
408 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
411 ascending in duration
413 Array<Rational> durations;
416 Rational shortest_in_measure;
417 shortest_in_measure.set_infinite (1);
419 for (int i = 0; i < cols.size (); i++)
421 if (Paper_column::is_musical (cols[i]))
423 Moment *when = unsmob_moment (cols[i]->get_property ("when"));
426 ignore grace notes for shortest notes.
428 if (when && when->grace_part_)
431 SCM st = cols[i]->get_property ("shortest-starter-duration");
432 Moment this_shortest = *unsmob_moment (st);
433 assert (this_shortest.to_bool ());
434 shortest_in_measure = shortest_in_measure <? this_shortest.main_part_;
436 else if (!shortest_in_measure.is_infinity ()
437 && Item::is_breakable (cols[i]))
440 for (; j < durations.size (); j++)
442 if (durations[j] > shortest_in_measure)
444 counts.insert (1, j);
445 durations.insert (shortest_in_measure, j);
448 else if (durations[j] == shortest_in_measure)
455 if (durations.size () == j)
457 durations.push (shortest_in_measure);
461 shortest_in_measure.set_infinite (1);
467 for (int i = durations.size (); i--;)
469 if (counts[i] >= max_count)
472 max_count = counts[i];
475 // printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
478 SCM bsd = me->get_property ("base-shortest-duration");
479 Rational d = Rational (1, 8);
480 if (Moment *m = unsmob_moment (bsd))
484 d = d <? durations[max_idx];
490 Generate spacing for a single measure. We used to have code that did
491 per-measure spacing. Now we have piecewise spacing. We should fix
492 this to support "spacing-regions": some regions have different notes
493 (different time sigs) than others, and should be spaced differently.
496 Spacing_spanner::do_measure (Rational global_shortest, Grob *me,
497 Link_array<Grob> *cols)
500 Real headwid = robust_scm2double (me->get_property ("spacing-increment"), 1);
501 for (int i = 0; i < cols->size () - 1; i++)
503 Item *l = dynamic_cast<Item *> (cols->elem (i));
504 Item *r = dynamic_cast<Item *> (cols->elem (i + 1));
506 Paper_column *lc = dynamic_cast<Paper_column *> (l);
507 Paper_column *rc = dynamic_cast<Paper_column *> (r);
509 if (!Paper_column::is_musical (l))
511 breakable_column_spacing (me, l, r, global_shortest);
514 The case that the right part is broken as well is rather
515 rare, but it is possible, eg. with a single empty measure,
516 or if one staff finishes a tad earlier than the rest.
519 Item *lb = l->find_prebroken_piece (RIGHT);
520 Item *rb = r->find_prebroken_piece (LEFT);
523 breakable_column_spacing (me, lb, r, global_shortest);
526 breakable_column_spacing (me, l, rb, global_shortest);
528 breakable_column_spacing (me, lb, rb, global_shortest);
532 musical_column_spacing (me, lc, rc, headwid, global_shortest);
533 if (Item *rb = r->find_prebroken_piece (LEFT))
534 musical_column_spacing (me, lc, rb, headwid, global_shortest);
540 Generate the space between two musical columns LC and RC, given
541 spacing parameters INCR and SHORTEST.
544 Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc, Real increment, Rational global_shortest)
546 bool expand_only = false;
547 Real base_note_space = note_spacing (me, lc, rc, global_shortest, &expand_only);
549 Real compound_note_space = 0.0;
550 Real compound_fixed_note_space = 0.0;
553 SCM seq = lc->get_property ("right-neighbors");
556 We adjust the space following a note only if the next note
557 happens after the current note (this is set in the grob
558 property SPACING-SEQUENCE.
560 for (SCM s = seq; scm_is_pair (s); s = scm_cdr (s))
562 Grob *wish = unsmob_grob (scm_car (s));
564 Item *wish_rcol = Note_spacing::right_column (wish);
565 if (Note_spacing::left_column (wish) != lc
566 || (wish_rcol != rc && wish_rcol != rc->original_))
570 This is probably a waste of time in the case of polyphonic
572 if (Note_spacing::has_interface (wish))
577 Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
579 compound_note_space = compound_note_space + space;
580 compound_fixed_note_space = compound_fixed_note_space + fixed;
586 if (Paper_column::when_mom (rc).grace_part_
587 && !Paper_column::when_mom (lc).grace_part_)
590 Ugh. 0.8 is arbitrary.
592 compound_note_space *= 0.8;
595 if (compound_note_space < 0 || wish_count == 0)
597 compound_note_space = base_note_space;
598 compound_fixed_note_space = increment;
602 compound_note_space /= wish_count;
603 compound_fixed_note_space /= wish_count;
607 Whatever we do, the fixed space is smaller than the real
610 TODO: this criterion is discontinuous in the derivative.
611 Maybe it should be continuous?
613 compound_fixed_note_space = compound_fixed_note_space <? compound_note_space;
615 bool packed = to_boolean (me->get_layout ()->c_variable ("packed"));
616 Real strength, distance;
619 TODO: make sure that the space doesn't exceed the right margin.
624 In packed mode, pack notes as tight as possible. This makes
625 sense mostly in combination with raggedright mode: the notes
626 are then printed at minimum distance. This is mostly useful
627 for ancient notation, but may also be useful for some flavours
628 of contemporary music. If not in raggedright mode, lily will
629 pack as much bars of music as possible into a line, but the
630 line will then be stretched to fill the whole linewidth.
633 distance = compound_fixed_note_space;
637 strength = 1 / (compound_note_space - compound_fixed_note_space);
638 distance = compound_note_space;
641 Spaceable_grob::add_spring (lc, rc, distance, strength);
645 The one-size-fits all spacing. It doesn't take into account
646 different spacing wishes from one to the next column.
649 Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
650 Real *fixed, Real *space,
655 Drul_array<Item *> cols (l, r);
659 if (!Paper_column::is_musical (cols[d]))
662 Tied accidentals over barlines cause problems, so lets see
663 what happens if we do this for non musical columns only.
665 Interval lext = cols[d]->extent (cols [d], X_AXIS);
666 if (!lext.is_empty ())
667 *fixed += -d * lext[-d];
670 while (flip (&d) != LEFT);
672 if (l->is_breakable (l) && r->is_breakable (r))
674 Moment *dt = unsmob_moment (l->get_property ("measure-length"));
679 Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
681 *space = *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
685 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
687 if (dt == Moment (0, 0))
690 In this case, Staff_spacing should handle the job,
691 using dt when it is 0 is silly.
693 *space = *fixed + 0.5;
698 *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
704 Read hints from L and generate springs.
707 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r, Moment shortest)
709 Real compound_fixed = 0.0;
710 Real compound_space = 0.0;
713 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
715 if (dt == Moment (0, 0))
717 for (SCM s = l->get_property ("spacing-wishes");
718 scm_is_pair (s); s = scm_cdr (s))
720 Item *spacing_grob = dynamic_cast<Item *> (unsmob_grob (scm_car (s)));
722 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
729 column for the left one settings should be ok due automatic
733 assert (spacing_grob-> get_column () == l);
735 Staff_spacing::get_spacing_params (spacing_grob,
736 &space, &fixed_space);
738 if (Paper_column::when_mom (r).grace_part_)
741 Correct for grace notes.
743 Ugh. The 0.8 is arbitrary.
748 compound_space += space;
749 compound_fixed += fixed_space;
754 if (compound_space <= 0.0 || !wish_count)
756 standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space,
762 compound_space /= wish_count;
763 compound_fixed /= wish_count;
766 assert (!isinf (compound_space));
767 compound_space = compound_space >? compound_fixed;
770 Hmm. we do 1/0 in the next thing. Perhaps we should check if this
771 works on all architectures.
775 There used to be code that changed spacing depending on
776 raggedright setting. Ugh.
778 Do it more cleanly, or rename the property.
781 Real strength = 1 / (compound_space - compound_fixed);
782 Real distance = compound_space;
783 Spaceable_grob::add_spring (l, r, distance, strength);
787 Get the measure wide ant for arithmetic spacing.
790 Spacing_spanner::get_duration_space (Grob *me, Moment d, Rational shortest, bool *expand_only)
792 Real k = robust_scm2double (me->get_property ("shortest-duration-space"), 1);
793 Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
798 We don't space really short notes using the log of the
799 duration, since it would disproportionally stretches the long
800 notes in a piece. In stead, we use geometric spacing with constant 0.5
803 This should probably be tunable, to use other base numbers.
805 In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
806 3.6 mm (total). head-width = 2.4, so we 1.2mm for 16th, 1.5
807 mm for 8th. (white space), suggesting that we use
809 (1.2 / 1.5)^{-log2(duration ratio)}
813 Rational ratio = d.main_part_ / shortest;
815 return ((k - 1) + double (ratio)) * incr;
820 John S. Gourlay. ``Spacing a Line of Music, '' Technical
821 Report OSU-CISRC-10/87-TR35, Department of Computer and
822 Information Science, The Ohio State University, 1987.
824 Real log = log_2 (shortest);
826 Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
827 *expand_only = false;
829 return (log_2 (compdur) + k) * incr;
834 Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc,
835 Moment shortest, bool *expand_only)
837 Moment shortest_playing_len = 0;
838 SCM s = lc->get_property ("shortest-playing-duration");
840 if (unsmob_moment (s))
841 shortest_playing_len = *unsmob_moment (s);
843 if (! shortest_playing_len.to_bool ())
845 programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
846 shortest_playing_len = 1;
849 Moment lwhen = Paper_column::when_mom (lc);
850 Moment rwhen = Paper_column::when_mom (rc);
852 Moment delta_t = rwhen - lwhen;
853 if (!Paper_column::is_musical (rc))
856 when toying with mmrests, it is possible to have musical
857 column on the left and non-musical on the right, spanning
861 Moment *dt = unsmob_moment (rc->get_property ("measure-length"));
864 delta_t = delta_t <? *dt;
867 The following is an extra safety measure, such that
868 the length of a mmrest event doesn't cause havoc.
870 shortest_playing_len = shortest_playing_len <? *dt;
876 In normal situations, the next column is at most
877 SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
878 with durations, invalidating this assumption. Here we kludge
879 around to get chord tremolos to behave properly.
882 shortest_playing_len = shortest_playing_len >? delta_t;
883 if (delta_t.main_part_ && !lwhen.grace_part_)
885 dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
886 dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
888 else if (delta_t.grace_part_)
891 TODO: figure out how to space grace notes.
893 dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
896 = robust_scm2double (me->get_property ("grace-space-factor"), 1);
904 ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
905 "The space taken by a note is dependent on its duration. Doubling a\n"
906 "duration adds spacing-increment to the space. The most common shortest\n"
907 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
908 "spaced proportonial to their duration.\n"
910 "Typically, the increment is the width of a black note head. In a\n"
911 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
912 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
913 "head width) A 16th note is followed by 0.5 note head width. The\n"
914 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
915 "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space common-shortest-duration");
917 ADD_INTERFACE (Spacing_interface, "spacing-interface",
918 "Something to do with line breaking and spacing. Kill this one after determining line breaks.",