(all-grob-descriptions): remove gap from
[lilypond.git] / lily / spacing-spanner.cc
blob139ba29f0f17c8ecf6c4646038cda0a40fb061c2
1 /*
2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
10 #include <math.h>
11 #include <stdio.h>
13 #include "main.hh"
14 #include "system.hh"
15 #include "warn.hh"
16 #include "paper-def.hh"
17 #include "paper-score.hh"
18 #include "paper-column.hh"
19 #include "item.hh"
20 #include "moment.hh"
21 #include "note-spacing.hh"
22 #include "misc.hh"
23 #include "warn.hh"
24 #include "staff-spacing.hh"
25 #include "spring.hh"
26 #include "paper-column.hh"
27 #include "spaceable-grob.hh"
28 #include "break-align-interface.hh"
29 #include "spacing-interface.hh"
33 TODO: this file/class is too complex. Should figure out how to chop
34 this up even more.
38 class Spacing_spanner
40 public:
41 static void standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
42 Real * fixed, Real * space, Moment);
45 static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment);
46 static Real note_spacing (Grob*,Grob*,Grob*,Moment, bool*);
47 static Real get_duration_space (Grob*,Moment dur, Rational shortest, bool*);
48 static Rational find_shortest (Grob *, Link_array<Grob> const &);
49 static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment);
50 static void find_loose_columns () {}
51 static void prune_loose_columns (Grob*,Link_array<Grob> *cols, Rational);
52 static void find_loose_columns (Link_array<Grob> cols);
53 static void set_explicit_neighbor_columns (Link_array<Grob> cols);
54 static void set_implicit_neighbor_columns (Link_array<Grob> cols);
55 static void do_measure (Rational, Grob*me,Link_array<Grob> *cols);
56 static void musical_column_spacing (Grob*,Item*,Item*, Real, Rational);
57 DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
58 static bool has_interface (Grob*);
62 Return whether COL is fixed to its neighbors by some kind of spacing
63 constraint.
66 If in doubt, then we're not loose; the spacing engine should space
67 for it, risking suboptimal spacing.
69 (Otherwise, we might risk core dumps, and other weird stuff.)
72 static bool
73 loose_column (Grob *l, Grob *c, Grob *r)
75 SCM rns = c->get_property ("right-neighbors");
76 SCM lns = c->get_property ("left-neighbors");
79 If this column doesn't have a proper neighbor, we should really
80 make it loose, but spacing it correctly is more than we can
81 currently can handle.
83 (this happens in the following situation:
86 | clef G
89 | | ||
90 | | ||
91 O O ||
94 the column containing the clef is really loose, and should be
95 attached right to the first column, but that is a lot of work for
96 such a borderline case.)
98 */
99 if (!gh_pair_p (lns) || !gh_pair_p (rns))
100 return false;
102 Item * l_neighbor = dynamic_cast<Item*> (unsmob_grob (gh_car (lns)));
103 Item * r_neighbor = dynamic_cast<Item*> (unsmob_grob (gh_car (rns)));
105 if (!l_neighbor || !r_neighbor)
106 return false;
108 l_neighbor = l_neighbor->get_column ();
109 r_neighbor = dynamic_cast<Item*> (Note_spacing::right_column (r_neighbor));
111 if (l == l_neighbor && r == r_neighbor)
112 return false;
114 if (!l_neighbor || !r_neighbor)
115 return false;
120 Only declare loose if the bounds make a little sense. This means
121 some cases (two isolated, consecutive clef changes) won't be
122 nicely folded, but hey, then don't do that.
124 if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
125 && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))) )
127 return false;
132 A rather hairy check, but we really only want to move around clefs. (anything else?)
134 in any case, we don't want to move bar lines.
136 for (SCM e = c->get_property ("elements"); gh_pair_p (e); e = gh_cdr (e))
138 Grob * g = unsmob_grob (gh_car (e));
139 if (g && Break_align_interface::has_interface (g))
141 for (SCM s = g->get_property ("elements"); gh_pair_p (s);
142 s = gh_cdr (s))
144 Grob *h = unsmob_grob (gh_car (s));
147 ugh. -- fix staff-bar name?
149 if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
150 return false;
155 return true;
159 Remove columns that are not tightly fitting from COLS. In the
160 removed columns, set 'between-cols to the columns where it is in
161 between.
163 void
164 Spacing_spanner::prune_loose_columns (Grob*me,Link_array<Grob> *cols, Rational shortest)
166 Link_array<Grob> newcols;
167 Real increment = robust_scm2double (me->get_property ("spacing-increment"), 1.2);
168 for (int i=0; i < cols->size (); i++)
170 if (Item::is_breakable (cols->elem (i)) || Paper_column::is_musical (cols->elem (i)))
172 newcols.push (cols->elem (i));
173 continue;
176 Grob *c = cols->elem (i);
177 if (loose_column (cols->elem (i-1), c, cols->elem (i+1)))
179 SCM lns = c->get_property ("left-neighbors");
180 lns = gh_pair_p (lns) ? gh_car (lns) : SCM_BOOL_F;
182 SCM rns = c->get_property ("right-neighbors");
183 rns = gh_pair_p (rns) ? gh_car (rns) : SCM_BOOL_F;
186 Either object can be non existent, if the score ends
187 prematurely.
189 rns = gh_car (unsmob_grob (rns)->get_property ("right-items"));
190 c->set_property ("between-cols", gh_cons (lns,
191 rns));
194 Set distance constraints for loose columns
196 Drul_array<Grob*> next_door;
197 next_door[LEFT] =cols->elem (i - 1);
198 next_door[RIGHT] =cols->elem (i + 1);
199 Direction d = LEFT;
200 Drul_array<Real> dists (0,0);
204 dists[d] = 0.0;
205 Item *lc = dynamic_cast<Item*> ((d == LEFT) ? next_door[LEFT] : c);
206 Item *rc = dynamic_cast<Item*> (d == LEFT ? c : next_door[RIGHT]);
208 for (SCM s = lc->get_property ("spacing-wishes");
209 gh_pair_p (s); s = gh_cdr (s))
211 Grob *sp = unsmob_grob (gh_car (s));
212 if (Note_spacing::left_column (sp) != lc
213 || Note_spacing::right_column (sp) != rc)
214 continue;
216 Real space, fixed;
217 fixed = 0.0;
218 bool dummy;
220 if (d == LEFT)
223 The note spacing should be taken from the musical
224 columns.
227 Real base = note_spacing (me, lc, rc, shortest, &dummy);
228 Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
230 space -= increment;
232 dists[d] = dists[d] >? space;
234 else
236 Real space, fixed_space;
237 Staff_spacing::get_spacing_params (sp,
238 &space, &fixed_space);
240 dists[d] = dists[d] >? fixed_space;
245 while (flip (&d) != LEFT);
247 Rod r;
248 r.distance_ = dists[LEFT] + dists[RIGHT];
249 r.item_l_drul_[LEFT] = dynamic_cast<Item*> (cols->elem (i-1));
250 r.item_l_drul_[RIGHT] = dynamic_cast<Item*> (cols->elem (i+1));
252 r.add_to_cols ();
254 else
256 newcols.push (c);
260 *cols = newcols;
264 Set neighboring columns determined by the spacing-wishes grob property.
266 void
267 Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
269 for (int i=0; i < cols.size (); i++)
271 SCM right_neighbors = SCM_EOL;
272 int min_rank = 100000; // inf.
275 SCM wishes= cols[i]->get_property ("spacing-wishes");
276 for (SCM s =wishes; gh_pair_p (s); s = gh_cdr (s))
278 Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
280 Item * lc = wish->get_column ();
281 Grob * right = Note_spacing::right_column (wish);
283 if (!right)
284 continue;
286 Item * rc = dynamic_cast<Item*> (right);
288 int right_rank = Paper_column::get_rank (rc);
289 int left_rank = Paper_column::get_rank (lc);
292 update the left column.
294 if (right_rank <= min_rank)
296 if (right_rank < min_rank)
297 right_neighbors =SCM_EOL;
299 min_rank = right_rank;
300 right_neighbors = gh_cons (wish->self_scm (), right_neighbors);
304 update the right column of the wish.
306 int maxrank = 0;
307 SCM left_neighs = rc->get_property ("left-neighbors");
308 if (gh_pair_p (left_neighs)
309 && unsmob_grob (gh_car (left_neighs)))
311 Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
312 maxrank = Paper_column::get_rank (it->get_column ());
315 if (left_rank >= maxrank)
317 if (left_rank > maxrank)
318 left_neighs = SCM_EOL;
320 left_neighs = gh_cons (wish->self_scm (), left_neighs);
321 rc->set_property ("left-neighbors", right_neighbors);
325 if (gh_pair_p (right_neighbors))
327 cols[i]->set_property ("right-neighbors", right_neighbors);
333 Set neighboring columns that have no left/right-neighbor set
334 yet. Only do breakable non-musical columns, and musical columns.
336 void
337 Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> cols)
339 for (int i = 0; i < cols.size (); i++)
341 Item * it = dynamic_cast<Item*>(cols[i]);
342 if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
343 continue;
345 // it->breakable || it->musical
348 sloppy with typnig left/right-neighbors should take list, but paper-column found instead.
350 SCM ln = cols[i] ->get_property ("left-neighbors");
351 if (!gh_pair_p (ln) && i )
353 cols[i]->set_property ("left-neighbors", gh_cons (cols[i-1]->self_scm (), SCM_EOL));
356 SCM rn = cols[i] ->get_property ("right-neighbors");
357 if (!gh_pair_p (rn) && i < cols.size () - 1)
359 cols[i]->set_property ("right-neighbors", gh_cons (cols[i + 1]->self_scm (), SCM_EOL));
365 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs,1);
367 Spacing_spanner::set_springs (SCM smob)
369 Grob *me = unsmob_grob (smob);
371 Link_array<Grob> all (me->pscore_->system_->columns ());
373 set_explicit_neighbor_columns (all);
375 SCM preset_shortest = me->get_property ("common-shortest-duration");
376 Rational global_shortest;
377 if (unsmob_moment (preset_shortest))
379 global_shortest = unsmob_moment (preset_shortest)->main_part_;
381 else
383 global_shortest = find_shortest (me, all);
384 if (verbose_global_b)
386 progress_indication (_f ("Global shortest duration is %s\n", global_shortest.to_string ()));
389 prune_loose_columns (me, &all, global_shortest);
390 set_implicit_neighbor_columns (all);
393 int j = 0;
394 for (int i = 1; i < all.size (); i++)
396 Grob *sc = all[i];
397 if (Item::is_breakable (sc))
399 Link_array<Grob> measure (all.slice (j, i+1));
400 do_measure (global_shortest, me, &measure);
401 j = i;
405 return SCM_UNSPECIFIED;
410 We want the shortest note that is also "common" in the piece, so we
411 find the shortest in each measure, and take the most frequently
412 found duration.
414 This probably gives weird effects with modern music, where every
415 note has a different duration, but hey, don't write that kind of
416 stuff, then.
419 Rational
420 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
423 ascending in duration
425 Array<Rational> durations;
426 Array<int> counts;
428 Rational shortest_in_measure;
429 shortest_in_measure.set_infinite (1);
431 for (int i =0 ; i < cols.size (); i++)
433 if (Paper_column::is_musical (cols[i]))
435 Moment *when = unsmob_moment (cols[i]->get_property ("when"));
438 ignore grace notes for shortest notes.
440 if (when && when->grace_part_)
441 continue;
443 SCM st = cols[i]->get_property ("shortest-starter-duration");
444 Moment this_shortest = *unsmob_moment (st);
445 assert (this_shortest.to_bool ());
446 shortest_in_measure = shortest_in_measure <? this_shortest.main_part_;
448 else if (!shortest_in_measure.is_infinity ()
449 && Item::is_breakable (cols[i]))
451 int j = 0;
452 for (; j < durations.size (); j++)
454 if (durations[j] > shortest_in_measure)
456 counts.insert (1, j);
457 durations.insert (shortest_in_measure, j);
458 break;
460 else if (durations[j] == shortest_in_measure)
462 counts[j]++;
463 break;
467 if (durations.size () == j)
469 durations.push (shortest_in_measure);
470 counts.push (1);
473 shortest_in_measure.set_infinite (1);
477 int max_idx = -1;
478 int max_count = 0;
479 for (int i =durations.size (); i--;)
481 if (counts[i] >= max_count)
483 max_idx = i;
484 max_count = counts[i];
487 // printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
490 SCM bsd = me->get_property ("base-shortest-duration");
491 Rational d = Rational (1,8);
492 if (Moment *m = unsmob_moment (bsd))
493 d = m->main_part_;
495 if (max_idx >= 0)
496 d = d <? durations[max_idx] ;
498 return d;
502 Generate spacing for a single measure. We used to have code that did
503 per-measure spacing. Now we have piecewise spacing. We should fix
504 this to support "spacing-regions": some regions have different notes
505 (different time sigs) than others, and should be spaced differently.
507 void
508 Spacing_spanner::do_measure (Rational global_shortest, Grob*me, Link_array<Grob> *cols)
511 Real headwid = robust_scm2double (me->get_property ("spacing-increment"), 1);
512 for (int i= 0; i < cols->size () - 1; i++)
514 Item * l = dynamic_cast<Item*> (cols->elem (i));
515 Item * r = dynamic_cast<Item*> (cols->elem (i+1));
517 Paper_column * lc = dynamic_cast<Paper_column*> (l);
518 Paper_column * rc = dynamic_cast<Paper_column*> (r);
520 if (!Paper_column::is_musical (l))
522 breakable_column_spacing (me, l, r, global_shortest);
526 The case that the right part is broken as well is rather
527 rare, but it is possible, eg. with a single empty measure,
528 or if one staff finishes a tad earlier than the rest.
531 Item *lb = l->find_prebroken_piece (RIGHT);
532 Item *rb = r->find_prebroken_piece (LEFT);
534 if (lb)
535 breakable_column_spacing (me, lb,r, global_shortest);
537 if (rb)
538 breakable_column_spacing (me, l, rb, global_shortest);
539 if (lb && rb)
540 breakable_column_spacing (me, lb, rb, global_shortest);
542 continue ;
546 musical_column_spacing (me, lc, rc, headwid, global_shortest);
547 if (Item *rb = r->find_prebroken_piece (LEFT))
548 musical_column_spacing (me, lc, rb, headwid, global_shortest);
554 Generate the space between two musical columns LC and RC, given
555 spacing parameters INCR and SHORTEST.
557 void
558 Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real increment, Rational global_shortest)
560 bool expand_only = false;
561 Real base_note_space = note_spacing (me, lc, rc, global_shortest, &expand_only);
563 Real compound_note_space = 0.0;
564 Real compound_fixed_note_space = 0.0;
565 int wish_count = 0;
567 SCM seq = lc->get_property ("right-neighbors");
570 We adjust the space following a note only if the next note
571 happens after the current note (this is set in the grob
572 property SPACING-SEQUENCE.
574 for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
576 Grob * wish = unsmob_grob (gh_car (s));
578 Item *wish_rcol = Note_spacing::right_column (wish);
579 if (Note_spacing::left_column (wish) != lc
580 || (wish_rcol != rc && wish_rcol != rc->original_))
581 continue;
584 This is probably a waste of time in the case of polyphonic
585 music. */
586 if (Note_spacing::has_interface (wish))
588 Real space =0.0;
589 Real fixed =0.0;
591 Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
594 compound_note_space = compound_note_space + space;
595 compound_fixed_note_space = compound_fixed_note_space + fixed;
596 wish_count ++;
601 if (Paper_column::when_mom (rc).grace_part_ &&
602 !Paper_column::when_mom (lc).grace_part_)
605 Ugh. 0.8 is arbitrary.
607 compound_note_space *= 0.8;
610 if (compound_note_space < 0 || wish_count == 0)
612 compound_note_space = base_note_space;
613 compound_fixed_note_space = increment;
615 else
617 compound_note_space /= wish_count;
618 compound_fixed_note_space /= wish_count;
622 Whatever we do, the fixed space is smaller than the real
623 space.
625 TODO: this criterion is discontinuous in the derivative.
626 Maybe it should be continuous?
628 compound_fixed_note_space = compound_fixed_note_space <? compound_note_space;
630 bool packed = to_boolean (me->get_paper ()->get_scmvar ("packed"));
631 Real strength, distance;
634 TODO: make sure that the space doesn't exceed the right margin.
636 if (packed)
639 In packed mode, pack notes as tight as possible. This makes
640 sense mostly in combination with raggedright mode: the notes
641 are then printed at minimum distance. This is mostly useful
642 for ancient notation, but may also be useful for some flavours
643 of contemporary music. If not in raggedright mode, lily will
644 pack as much bars of music as possible into a line, but the
645 line will then be stretched to fill the whole linewidth.
647 strength = 1.0;
648 distance = compound_fixed_note_space;
650 else
652 strength = 1 / (compound_note_space - compound_fixed_note_space);
653 distance = compound_note_space;
656 // Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only);
658 Spaceable_grob::add_spring (lc, rc, distance, strength, false);
663 The one-size-fits all spacing. It doesn't take into account
664 different spacing wishes from one to the next column.
666 void
667 Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
668 Real * fixed, Real * space,
669 Moment shortest)
671 *fixed = 0.0;
672 Direction d = LEFT;
673 Drul_array<Item*> cols (l,r);
677 if (!Paper_column::is_musical (cols[d]))
680 Tied accidentals over barlines cause problems, so lets see
681 what happens if we do this for non musical columns only.
683 Interval lext = cols[d]->extent (cols [d], X_AXIS);
684 if (!lext.is_empty ())
685 *fixed += -d * lext[-d];
688 while (flip (&d) != LEFT);
691 if (l->is_breakable (l) && r->is_breakable (r))
693 Moment *dt = unsmob_moment (l->get_property ("measure-length"));
694 Moment mlen (1);
695 if (dt)
696 mlen = *dt;
698 Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
700 *space = *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
702 else
704 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
706 if (dt == Moment (0,0))
709 In this case, Staff_spacing should handle the job,
710 using dt when it is 0 is silly.
712 *space = *fixed + 0.5;
714 else
716 bool dummy;
717 *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
724 Read hints from L and generate springs.
726 void
727 Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
729 Real compound_fixed = 0.0;
730 Real compound_space = 0.0;
731 int wish_count = 0;
733 Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
735 if (dt == Moment (0,0))
737 for (SCM s = l->get_property ("spacing-wishes");
738 gh_pair_p (s); s = gh_cdr (s))
740 Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
742 if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
743 continue;
745 Real space;
746 Real fixed_space;
749 column for the left one settings should be ok due automatic
750 pointer munging.
753 assert (spacing_grob-> get_column () == l);
755 Staff_spacing::get_spacing_params (spacing_grob,
756 &space, &fixed_space);
758 if (Paper_column::when_mom (r).grace_part_)
761 Correct for grace notes.
763 Ugh. The 0.8 is arbitrary.
765 space *= 0.8;
769 compound_space += space;
770 compound_fixed += fixed_space;
771 wish_count ++ ;
775 if (compound_space <= 0.0 || !wish_count)
777 standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space ,
778 shortest);
779 wish_count = 1;
781 else
783 compound_space /= wish_count;
784 compound_fixed /= wish_count;
787 assert (!isinf (compound_space));
788 compound_space = compound_space >? compound_fixed;
792 Hmm. we do 1/0 in the next thing. Perhaps we should check if this
793 works on all architectures.
797 There used to be code that changed spacing depending on
798 raggedright setting. Ugh.
800 Do it more cleanly, or rename the property.
803 Real strength = 1 / (compound_space - compound_fixed);
804 Real distance = compound_space;
805 Spaceable_grob::add_spring (l, r, distance, strength, false);
810 Get the measure wide ant for arithmetic spacing.
812 Real
813 Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only)
815 Real k = robust_scm2double (me->get_property ("shortest-duration-space"), 1);
816 Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
818 if (d < shortest)
821 We don't space really short notes using the log of the
822 duration, since it would disproportionally stretches the long
823 notes in a piece. In stead, we use geometric spacing with constant 0.5
824 (i.e. linear.)
826 This should probably be tunable, to use other base numbers.
828 In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
829 3.6 mm (total). head-width = 2.4, so we 1.2mm for 16th, 1.5
830 mm for 8th. (white space), suggesting that we use
832 (1.2 / 1.5)^{-log2(duration ratio)}
836 Rational ratio = d.main_part_ / shortest;
838 return ((k-1) + double (ratio)) * incr;
840 else
843 John S. Gourlay. ``Spacing a Line of Music,'' Technical
844 Report OSU-CISRC-10/87-TR35, Department of Computer and
845 Information Science, The Ohio State University, 1987.
847 Real log = log_2 (shortest);
848 k -= log;
849 Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
850 *expand_only = false;
852 return (log_2 (compdur) + k) * incr;
856 Real
857 Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
858 Moment shortest, bool * expand_only)
860 Moment shortest_playing_len = 0;
861 SCM s = lc->get_property ("shortest-playing-duration");
863 if (unsmob_moment (s))
864 shortest_playing_len = *unsmob_moment (s);
866 if (! shortest_playing_len.to_bool ())
868 programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
869 shortest_playing_len = 1;
872 Moment lwhen = Paper_column::when_mom (lc);
873 Moment rwhen = Paper_column::when_mom (rc);
875 Moment delta_t = rwhen - lwhen;
876 if (!Paper_column::is_musical (rc))
879 when toying with mmrests, it is possible to have musical
880 column on the left and non-musical on the right, spanning
881 several measures.
884 Moment *dt = unsmob_moment (rc->get_property ("measure-length"));
885 if (dt)
887 delta_t = delta_t <? *dt;
890 The following is an extra safety measure, such that
891 the length of a mmrest event doesn't cause havoc.
893 shortest_playing_len = shortest_playing_len <? *dt;
896 Real dist = 0.0;
899 In normal situations, the next column is at most
900 SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
901 with durations, invalidating this assumption. Here we kludge
902 around to get chord tremolos to behave properly.
905 shortest_playing_len = shortest_playing_len >? delta_t;
906 if (delta_t.main_part_ && !lwhen.grace_part_)
908 dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
909 dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
911 else if (delta_t.grace_part_)
914 TODO: figure out how to space grace notes.
916 dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
918 Real grace_fact
919 = robust_scm2double (me->get_property ("grace-space-factor"), 1);
921 dist *= grace_fact;
925 return dist;
930 ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
931 "The space taken by a note is dependent on its duration. Doubling a\n"
932 "duration adds spacing-increment to the space. The most common shortest\n"
933 "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
934 "spaced proportonial to their duration.\n"
935 "\n"
936 "Typically, the increment is the width of a black note head. In a\n"
937 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
938 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
939 "head width) A 16th note is followed by 0.5 note head width. The\n"
940 "quarter note is followed by 3 NHW, the half by 4 NHW, etc.\n",
941 "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space common-shortest-duration");
945 ADD_INTERFACE (Spacing_interface,"spacing-interface",
946 "Something to do with line breaking and spacing. Kill this one after determining line breaks.",
947 "");