2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
14 #include "paper-def.hh"
15 #include "paper-score.hh"
16 #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"
37 static void standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
38 Real * fixed, Real * space, Moment);
41 static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment);
42 static Real note_spacing (Grob*,Grob*,Grob*,Moment, bool*);
43 static Real get_duration_space (Grob*,Moment dur, Rational shortest, bool*);
44 static Rational find_shortest (Grob *, Link_array<Grob> const &);
45 static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment);
46 static void find_loose_columns () {}
47 static void prune_loose_colunms (Grob*,Link_array<Grob> *cols, Rational);
48 static void find_loose_columns (Link_array<Grob> cols);
49 static void set_explicit_neighbor_columns (Link_array<Grob> cols);
50 static void set_implicit_neighbor_columns (Link_array<Grob> cols);
51 static void do_measure (Rational, Grob*me,Link_array<Grob> *cols);
52 static void musical_column_spacing (Grob*,Item*,Item*, Real, Rational);
53 DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
54 static bool has_interface (Grob*);
58 Return whether COL is fixed to its neighbors by some kind of spacing
62 loose_column (Grob *l, Grob *c, Grob *r)
64 SCM rns = c->get_grob_property ("right-neighbors");
65 SCM lns = c->get_grob_property ("left-neighbors");
68 If this column doesn't have a proper neighbor, we should really
69 make it loose, but spacing it correctly is more than we can
72 (this happens in the following situation:
83 the column containing the clef is really loose, and should be
84 attached right to the first column, but that is a lot of work for
85 such a borderline case.)
88 if (!gh_pair_p (lns) || !gh_pair_p (rns))
91 Item * l_neighbor = dynamic_cast<Item*> (unsmob_grob (gh_car (lns)));
92 Item * r_neighbor = dynamic_cast<Item*> (unsmob_grob (gh_car (rns)));
94 if (!l_neighbor || !r_neighbor)
97 l_neighbor = l_neighbor->column_l();
98 r_neighbor = dynamic_cast<Item*> (Note_spacing::right_column (r_neighbor));
100 if (l == l_neighbor && r == r_neighbor)
103 if (!l_neighbor || !r_neighbor)
108 A rather hairy check, but we really only want to move around clefs. (anything else?)
110 in any case, we don't want to move bar lines.
112 for (SCM e = c->get_grob_property ("elements"); gh_pair_p (e); e = gh_cdr (e))
114 Grob * g = unsmob_grob (gh_car (e));
115 if (g && Break_align_interface::has_interface (g))
117 for (SCM s = g->get_grob_property ("elements"); gh_pair_p (s);
120 Grob *h = unsmob_grob (gh_car (s));
122 if (h && h->get_grob_property ("break-align-symbol") == ly_symbol2scm ("bar-line"))
129 Only declare loose if the bounds make a little sense. This means
130 some cases (two isolated, consecutive clef changes) won't be
131 nicely folded, but hey, then don't do that.
133 if ((Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
134 && (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_neighbor)))
141 If in doubt: we're not loose; the spacing engine should space for
142 it, risking suboptimal spacing.
144 (Otherwise, we might risk core dumps, and other weird stuff.)
151 Remove columns that are not tightly fitting from COLS. In the
152 removed columns, set 'between-cols to the columns where it is in
156 Spacing_spanner::prune_loose_colunms (Grob*me,Link_array<Grob> *cols, Rational shortest)
158 Link_array<Grob> newcols;
159 Real increment = gh_scm2double (me->get_grob_property ("spacing-increment"));
160 for (int i=0; i < cols->size (); i++)
162 if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
164 newcols.push (cols->elem(i));
168 Grob *c = cols->elem(i);
169 if (loose_column (cols->elem (i-1), c, cols->elem (i+1)))
171 SCM lns = c->get_grob_property ("left-neighbors");
172 lns = gh_pair_p (lns) ? gh_car (lns) : SCM_BOOL_F;
174 SCM rns = c->get_grob_property ("right-neighbors");
175 rns = gh_pair_p (rns) ? gh_car (rns) : SCM_BOOL_F;
178 Either object can be non existent, if the score ends
181 rns = gh_car (unsmob_grob (rns)->get_grob_property ("right-items"));
182 c->set_grob_property ("between-cols", gh_cons (lns,
186 Set distance constraints for loose columns
188 Drul_array<Grob*> next_door;
189 next_door[LEFT] =cols->elem (i - 1);
190 next_door[RIGHT] =cols->elem (i + 1);
192 Drul_array<Real> dists(0,0);
197 Item *lc = dynamic_cast<Item*> ((d == LEFT) ? next_door[LEFT] : c);
198 Item *rc = dynamic_cast<Item*> (d == LEFT ? c : next_door[RIGHT]);
200 for (SCM s = lc->get_grob_property ("spacing-wishes");
201 gh_pair_p (s); s = gh_cdr (s))
203 Grob *sp = unsmob_grob (gh_car (s));
204 if (Note_spacing::left_column (sp) != lc
205 || Note_spacing::right_column (sp) != rc)
215 The note spacing should be taken from the musical
219 Real base = note_spacing (me, lc, rc, shortest, &dummy);
220 Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
224 dists[d] = dists[d] >? space;
228 Real space, fixed_space;
229 Staff_spacing::get_spacing_params (sp,
230 &space, &fixed_space);
232 dists[d] = dists[d] >? fixed_space;
237 while (flip (&d) != LEFT);
240 r.distance_f_ = dists[LEFT] + dists[RIGHT];
241 r.item_l_drul_[LEFT] = dynamic_cast<Item*> (cols->elem(i-1));
242 r.item_l_drul_[RIGHT] = dynamic_cast<Item*> (cols->elem (i+1));
256 Set neighboring columns determined by the spacing-wishes grob property.
259 Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
261 for (int i=0; i < cols.size(); i++)
263 SCM right_neighbors = SCM_EOL;
264 int min_rank = 100000; // inf.
267 SCM wishes= cols[i]->get_grob_property ("spacing-wishes");
268 for (SCM s =wishes; gh_pair_p (s); s = gh_cdr (s))
270 Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
272 Item * lc = wish->column_l ();
273 Grob * right = Note_spacing::right_column (wish);
278 Item * rc = dynamic_cast<Item*> (right);
280 int right_rank = Paper_column::rank_i (rc);
281 int left_rank = Paper_column::rank_i (lc);
284 update the left column.
286 if (right_rank <= min_rank)
288 if (right_rank < min_rank)
289 right_neighbors =SCM_EOL;
291 min_rank = right_rank;
292 right_neighbors = gh_cons (wish->self_scm (), right_neighbors);
296 update the right column of the wish.
299 SCM left_neighs = rc->get_grob_property ("left-neighbors");
300 if (gh_pair_p (left_neighs)
301 && unsmob_grob (gh_car (left_neighs)))
303 Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
304 maxrank = Paper_column::rank_i (it->column_l());
307 if (left_rank >= maxrank)
309 if (left_rank > maxrank)
310 left_neighs = SCM_EOL;
312 left_neighs = gh_cons (wish->self_scm (), left_neighs);
313 rc->set_grob_property ("left-neighbors", right_neighbors);
317 if (gh_pair_p (right_neighbors))
319 cols[i]->set_grob_property ("right-neighbors", right_neighbors);
325 Set neighboring columns that have no left/right-neighbor set
326 yet. Only do breakable non-musical columns, and musical columns.
329 Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> cols)
331 for (int i = 0; i < cols.size (); i++)
333 Item * it = dynamic_cast<Item*>(cols[i]);
334 if (!Item::breakable_b (it) && !Paper_column::musical_b (it))
337 // it->breakable || it->musical
340 sloppy with typnig left/right-neighbors should take list, but paper-column found instead.
342 SCM ln = cols[i] ->get_grob_property ("left-neighbors");
343 if (!gh_pair_p (ln) && i )
345 cols[i]->set_grob_property ("left-neighbors", gh_cons (cols[i-1]->self_scm(), SCM_EOL));
348 SCM rn = cols[i] ->get_grob_property ("right-neighbors");
349 if (!gh_pair_p (rn) && i < cols.size () - 1)
351 cols[i]->set_grob_property ("right-neighbors", gh_cons (cols[i + 1]->self_scm(), SCM_EOL));
357 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs,1);
359 Spacing_spanner::set_springs (SCM smob)
361 Grob *me = unsmob_grob (smob);
363 Link_array<Grob> all (me->pscore_l_->line_l_->column_l_arr ()) ;
365 set_explicit_neighbor_columns (all);
367 Rational global_shortest = find_shortest (me, all);
368 prune_loose_colunms (me, &all, global_shortest);
369 set_implicit_neighbor_columns (all);
373 for (int i = 1; i < all.size (); i++)
376 if (Item::breakable_b (sc))
378 Link_array<Grob> measure (all.slice (j, i+1));
379 do_measure (global_shortest, me, &measure);
384 return SCM_UNSPECIFIED;
389 We want the shortest note that is also "common" in the piece, so we
390 find the shortest in each measure, and take the most frequently
393 This probably gives weird effects with modern music, where every
394 note has a different duration, but hey, don't write that kind of
399 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
402 ascending in duration
404 Array<Rational> durations;
407 Rational shortest_in_measure;
408 shortest_in_measure.set_infinite (1);
410 for (int i =0 ; i < cols.size (); i++)
412 if (Paper_column::musical_b (cols[i]))
414 Moment *when = unsmob_moment (cols[i]->get_grob_property ("when"));
417 ignore grace notes for shortest notes.
419 if (when && when->grace_part_)
422 SCM st = cols[i]->get_grob_property ("shortest-starter-duration");
423 Moment this_shortest = *unsmob_moment (st);
424 assert (this_shortest.to_bool());
425 shortest_in_measure = shortest_in_measure <? this_shortest.main_part_;
427 else if (!shortest_in_measure.infty_b()
428 && Item::breakable_b (cols[i]))
431 for (; j < durations.size(); j++)
433 if (durations[j] > shortest_in_measure)
435 counts.insert (1, j);
436 durations.insert (shortest_in_measure, j);
439 else if (durations[j] == shortest_in_measure)
446 if (durations.size() == j)
448 durations.push (shortest_in_measure);
452 shortest_in_measure.set_infinite(1);
458 for (int i =durations.size(); i--;)
460 if (counts[i] >= max_count)
463 max_count = counts[i];
466 // printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
469 SCM bsd = me->get_grob_property ("base-shortest-duration");
470 Rational d = Rational (1,8);
471 if (Moment *m = unsmob_moment (bsd))
475 d = d <? durations[max_idx] ;
481 Generate spacing for a single measure. We used to have code that did
482 per-measure spacing. Now we have piecewise spacing. We should fix
483 this to support "spacing-regions": some regions have different notes
484 (different time sigs) than others, and should be spaced differently.
487 Spacing_spanner::do_measure (Rational shortest, Grob*me, Link_array<Grob> *cols)
490 Real headwid = gh_scm2double (me->get_grob_property ("spacing-increment"));
491 for (int i= 0; i < cols->size () - 1; i++)
493 Item * l = dynamic_cast<Item*> (cols->elem (i));
494 Item * r = dynamic_cast<Item*> (cols->elem (i+1));
496 Paper_column * lc = dynamic_cast<Paper_column*> (l);
497 Paper_column * rc = dynamic_cast<Paper_column*> (r);
499 if (!Paper_column::musical_b (l))
501 breakable_column_spacing (me, l, r, shortest);
505 The case that the right part is broken as well is rather
506 rare, but it is possible, eg. with a single empty measure,
507 or if one staff finishes a tad earlier than the rest.
510 Item *lb = l->find_prebroken_piece (RIGHT);
511 Item *rb = r->find_prebroken_piece (LEFT);
514 breakable_column_spacing (me, lb,r, shortest);
517 breakable_column_spacing (me, l, rb, shortest);
519 breakable_column_spacing (me, lb, rb, shortest);
525 musical_column_spacing (me, lc, rc, headwid, shortest);
526 if (Item *rb = r->find_prebroken_piece (LEFT))
527 musical_column_spacing (me, lc, rb, headwid, shortest);
533 Generate the space between two musical columns LC and RC, given
534 spacing parameters INCR and SHORTEST.
537 Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real increment, Rational shortest)
539 bool expand_only = false;
540 Real base_note_space = note_spacing (me, lc, rc, shortest, &expand_only);
542 Real max_note_space = -infinity_f;
543 Real max_fixed_note_space = -infinity_f;
545 SCM seq = lc->get_grob_property ("right-neighbors");
548 We adjust the space following a note only if the next note
549 happens after the current note (this is set in the grob
550 property SPACING-SEQUENCE.
552 for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
554 Grob * wish = unsmob_grob (gh_car (s));
556 Item *wish_rcol = Note_spacing::right_column (wish);
557 if (Note_spacing::left_column (wish) != lc
558 || (wish_rcol != rc && wish_rcol != rc->original_l_))
562 This is probably a waste of time in the case of polyphonic
564 if (Note_spacing::has_interface (wish))
569 Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
570 max_note_space = max_note_space >? space;
571 max_fixed_note_space = max_fixed_note_space >? fixed;
575 if (max_note_space < 0)
577 max_note_space = base_note_space;
578 max_fixed_note_space = increment;
581 bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright"));
584 Whatever we do, the fixed space is smaller than the real
587 TODO: this criterion is discontinuous in the derivative.
588 Maybe it should be continuous?
590 max_fixed_note_space = max_fixed_note_space <? max_note_space;
592 Real strength = (ragged) ? 1.0 : 1 / (max_note_space - max_fixed_note_space);
593 Real distance = (ragged) ? max_fixed_note_space : max_note_space;
594 // Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only);
596 Spaceable_grob::add_spring (lc, rc, distance, strength, false);
601 The one-size-fits all spacing. It doesn't take into account
602 different spacing wishes from one to the next column.
605 Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
606 Real * fixed, Real * space,
609 *fixed = l->extent (l, X_AXIS)[RIGHT] - r->extent (r, X_AXIS)[LEFT];
611 if (l->breakable_b (l) && r->breakable_b(r))
613 Moment *dt = unsmob_moment (l->get_grob_property ("measure-length"));
618 Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
620 *space = *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
624 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
627 *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
635 Read hints from L and generate springs.
638 Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
640 Real max_fixed = -infinity_f;
641 Real max_space = -infinity_f;
643 standard_breakable_column_spacing (me, l, r, &max_fixed, &max_space ,
646 for (SCM s = l->get_grob_property ("spacing-wishes");
647 gh_pair_p (s); s = gh_cdr (s))
649 Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
651 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
658 column for the left one settings should be ok due automatic
662 assert (spacing_grob-> column_l () == l);
664 Staff_spacing::get_spacing_params (spacing_grob,
665 &space, &fixed_space);
666 if (space > max_space)
669 max_fixed = fixed_space;
676 if (isinf (max_space))
679 One situation where this can happen is when there is a column
680 that only serves as a spanning point for a short staff-symbol.
687 (here no StaffSpacing from Y to X is found.)
689 programming_error ("No StaffSpacing wishes found");
695 if (l->break_status_dir() == RIGHT
696 && Paper_column::when_mom (l) == Paper_column::when_mom (r))
698 /* Start of line: this space is not stretchable */
699 max_fixed = max_space;
703 Hmm. we do 1/0 in the next thing. Perhaps we should check if this
704 works on all architectures.
707 bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright"));
708 Real strength = (ragged) ? 1.0 : 1 / (max_space - max_fixed);
709 Real distance = (ragged) ? max_fixed : max_space;
710 Spaceable_grob::add_spring (l, r, distance, strength, false);
715 Get the measure wide ant for arithmetic spacing.
718 Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only)
720 Real k = gh_scm2double (me->get_grob_property ("shortest-duration-space"));
721 Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
726 We don't space really short notes using the log of the
727 duration, since it would disproportionally stretches the long
728 notes in a piece. In stead, we use geometric spacing with constant 0.5
731 This should probably be tunable, to use other base numbers.
733 In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
734 3.6 mm (total). head-width = 2.4, so we 1.2mm for 16th, 1.5
735 mm for 8th. (white space), suggesting that we use
737 (1.2 / 1.5)^{-log2(duration ratio)}
741 Rational ratio = d.main_part_ / shortest;
744 return ((k-1) + double (ratio)) * incr;
749 John S. Gourlay. ``Spacing a Line of Music,'' Technical
750 Report OSU-CISRC-10/87-TR35, Department of Computer and
751 Information Science, The Ohio State University, 1987.
753 Real log = log_2 (shortest);
755 Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
756 *expand_only = false;
758 return (log_2 (compdur) + k) * incr;
763 Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
764 Moment shortest, bool * expand_only)
766 Moment shortest_playing_len = 0;
767 SCM s = lc->get_grob_property ("shortest-playing-duration");
769 if (unsmob_moment (s))
770 shortest_playing_len = *unsmob_moment (s);
772 if (! shortest_playing_len.to_bool ())
774 programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ());
775 shortest_playing_len = 1;
778 Moment lwhen = Paper_column::when_mom (lc);
779 Moment rwhen = Paper_column::when_mom (rc);
781 Moment delta_t = rwhen - lwhen;
785 In normal situations, the next column is at most
786 SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
787 with durations, invalidating this assumption. Here we kludge
788 around to get chord tremolos to behave properly.
791 shortest_playing_len = shortest_playing_len >? delta_t;
792 if (delta_t.main_part_ && !lwhen.grace_part_)
794 dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
795 dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
797 else if (delta_t.grace_part_)
800 TODO: figure out how to space grace notes.
802 dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
804 Real grace_fact = 1.0;
805 SCM gf = me->get_grob_property ("grace-space-factor");
806 if (gh_number_p (gf))
807 grace_fact = gh_scm2double (gf);
818 ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
820 The space taken by a note is dependent on its duration. Doubling a
821 duration adds spacing-increment to the space. The most common shortest
822 note gets shortest-duration-space. Notes that are even shorter are
823 spaced proportonial to their duration.
825 Typically, the increment is the width of a black note head. In a
826 piece with lots of 8th notes, and some 16th notes, the eighth note
827 gets 2 note heads width (i.e. the space following a note is 1 note
828 head width) A 16th note is followed by 0.5 note head width. The
829 quarter note is followed by 3 NHW, the half by 4 NHW, etc.
831 "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space");