]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
(LY_DEFINE): new file.
[lilypond.git] / lily / spacing-spanner.cc
1 /*
2   spacing-spanner.cc -- implement Spacing_spanner
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1999--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include <math.h>
10 #include <cstdio>
11
12 #include "main.hh"
13 #include "system.hh"
14 #include "warn.hh"
15 #include "output-def.hh"
16 #include "paper-score.hh"
17 #include "paper-column.hh"
18 #include "moment.hh"
19 #include "note-spacing.hh"
20 #include "misc.hh"
21 #include "warn.hh"
22 #include "staff-spacing.hh"
23 #include "spring.hh"
24 #include "paper-column.hh"
25 #include "spaceable-grob.hh"
26 #include "break-align-interface.hh"
27 #include "spacing-interface.hh"
28 #include "pointer-group-interface.hh"
29 #include "grob-array.hh"
30
31 /*
32   TODO: this file/class is too complex. Should figure out how to chop
33   this up even more.
34 */
35
36 class Spacing_spanner
37 {
38 public:
39   static void standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
40                                                  Real *fixed, Real *space, Moment);
41
42   static Real default_bar_spacing (Grob *, Grob *, Grob *, Moment);
43   static Real note_spacing (Grob *, Grob *, Grob *, Moment, bool *);
44   static Real get_duration_space (Grob *, Moment dur, Rational shortest, bool *);
45   static Rational find_shortest (Grob *, Link_array<Grob> const &);
46   static void breakable_column_spacing (Grob *, Item *l, Item *r, Moment);
47   static void find_loose_columns () {}
48   static void prune_loose_columns (Grob *, Link_array<Grob> *cols, Rational);
49   static void find_loose_columns (Link_array<Grob> cols);
50   static void set_explicit_neighbor_columns (Link_array<Grob> const &cols);
51   static void set_implicit_neighbor_columns (Link_array<Grob> const &cols);
52   static void do_measure (Rational, Grob *me, Link_array<Grob> *cols);
53   static void musical_column_spacing (Grob *, Item *, Item *, Real, Rational);
54   DECLARE_SCHEME_CALLBACK (set_springs, (SCM));
55   static bool has_interface (Grob *);
56 };
57
58 /*
59   Return whether COL is fixed to its neighbors by some kind of spacing
60   constraint.
61
62
63   If in doubt, then we're not loose; the spacing engine should space
64   for it, risking suboptimal spacing.
65
66   (Otherwise, we might risk core dumps, and other weird stuff.)
67 */
68 static bool
69 loose_column (Grob *l, Grob *c, Grob *r)
70 {
71   extract_grob_set (c, "right-neighbors", rns);
72   extract_grob_set (c, "left-neighbors", lns);
73   
74   /*
75     If this column doesn't have a proper neighbor, we should really
76     make it loose, but spacing it correctly is more than we can
77     currently can handle.
78
79     (this happens in the following situation:
80
81     |
82     |    clef G
83     *
84
85     |               |      ||
86     |               |      ||
87     O               O       ||
88
89
90     the column containing the clef is really loose, and should be
91     attached right to the first column, but that is a lot of work for
92     such a borderline case.)
93
94   */
95   if (lns.is_empty () || rns.is_empty ())
96     return false;
97
98   Item *l_neighbor = dynamic_cast<Item *> (lns[0]);
99   Item *r_neighbor = dynamic_cast<Item *> (rns[0]);
100
101   if (!l_neighbor || !r_neighbor)
102     return false;
103
104   l_neighbor = l_neighbor->get_column ();
105   r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
106
107   if (l == l_neighbor && r == r_neighbor)
108     return false;
109
110   if (!l_neighbor || !r_neighbor)
111     return false;
112
113   /*
114     Only declare loose if the bounds make a little sense.  This means
115     some cases (two isolated, consecutive clef changes) won't be
116     nicely folded, but hey, then don't do that.
117   */
118   if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
119          && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))))
120     {
121       return false;
122     }
123
124   /*
125     A rather hairy check, but we really only want to move around
126     clefs. (anything else?)
127
128     in any case, we don't want to move bar lines.
129   */
130   extract_grob_set (c, "elements", elts);
131   for (int i = elts.size (); i--; )
132     {
133       Grob *g = elts[i];
134       if (g && Break_align_interface::has_interface (g))
135         {
136           extract_grob_set (g, "elements", gelts);
137           for (int j = gelts.size (); j--; )
138             {
139               Grob *h = gelts[j];
140
141               /*
142                 ugh. -- fix staff-bar name?
143               */
144               if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
145                 return false;
146             }
147         }
148     }
149
150   return true;
151 }
152
153 /*
154   Remove columns that are not tightly fitting from COLS. In the
155   removed columns, set 'between-cols to the columns where it is in
156   between.
157 */
158 void
159 Spacing_spanner::prune_loose_columns (Grob *me, Link_array<Grob> *cols, Rational shortest)
160 {
161   Link_array<Grob> newcols;
162   Real increment = robust_scm2double (me->get_property ("spacing-increment"), 1.2);
163   for (int i = 0; i < cols->size (); i++)
164     {
165       if (Item::is_breakable (cols->elem (i)) || Paper_column::is_musical (cols->elem (i)))
166         {
167           newcols.push (cols->elem (i));
168           continue;
169         }
170
171       Grob *c = cols->elem (i);
172       if (loose_column (cols->elem (i - 1), c, cols->elem (i + 1)))
173         {
174           extract_grob_set (c, "right-neighbors", rns_arr);
175           extract_grob_set (c, "left-neighbors", lns_arr);
176           
177           SCM lns = lns_arr.size () ? lns_arr.top()->self_scm () : SCM_BOOL_F;
178           SCM rns = rns_arr.size () ? rns_arr.top()->self_scm () : SCM_BOOL_F;
179           
180           /*
181             Either object can be non existent, if the score ends
182             prematurely.
183           */
184
185           extract_grob_set (unsmob_grob (rns), "right-items", right_items);
186           c->set_object ("between-cols", scm_cons (lns,
187                                                    right_items[0]->self_scm ()));
188
189           /*
190             Set distance constraints for loose columns
191           */
192           Drul_array<Grob *> next_door;
193           next_door[LEFT] = cols->elem (i - 1);
194           next_door[RIGHT] = cols->elem (i + 1);
195           Direction d = LEFT;
196           Drul_array<Real> dists (0, 0);
197
198           do
199             {
200               dists[d] = 0.0;
201               Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
202               Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
203
204
205               extract_grob_set (lc, "spacing-wishes", wishes);
206               for (int k = wishes.size(); k--;)
207                 {
208                   Grob *sp = wishes[k];
209                   if (Note_spacing::left_column (sp) != lc
210                       || Note_spacing::right_column (sp) != rc)
211                     continue;
212
213                   Real space, fixed;
214                   fixed = 0.0;
215                   bool dummy;
216
217                   if (d == LEFT)
218                     {
219                       /*
220                         The note spacing should be taken from the musical
221                         columns.
222
223                       */
224                       Real base = note_spacing (me, lc, rc, shortest, &dummy);
225                       Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
226
227                       space -= increment;
228
229                       dists[d] = max (dists[d], space);
230                     }
231                   else
232                     {
233                       Real space, fixed_space;
234                       Staff_spacing::get_spacing_params (sp,
235                                                          &space, &fixed_space);
236
237                       dists[d] = max (dists[d], fixed_space);
238                     }
239                 }
240             }
241           while (flip (&d) != LEFT);
242
243           Rod r;
244           r.distance_ = dists[LEFT] + dists[RIGHT];
245           r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->elem (i - 1));
246           r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->elem (i + 1));
247
248           r.add_to_cols ();
249         }
250       else
251         {
252           newcols.push (c);
253         }
254     }
255
256   *cols = newcols;
257 }
258
259 /*
260   Set neighboring columns determined by the spacing-wishes grob property.
261 */
262 void
263 Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> const &cols)
264 {
265   for (int i = 0; i < cols.size (); i++)
266     {
267       SCM right_neighbors = Grob_array::make_array ();
268       Grob_array *rn_arr = unsmob_grob_array (right_neighbors);
269       int min_rank = 100000;    // inf.
270
271       extract_grob_set (cols[i], "spacing-wishes", wishes);
272       for (int k = wishes.size(); k--;)
273         {
274           Item *wish = dynamic_cast<Item *> ( wishes[k]);
275
276           Item *lc = wish->get_column ();
277           Grob *right = Note_spacing::right_column (wish);
278
279           if (!right)
280             continue;
281
282           Item *rc = dynamic_cast<Item *> (right);
283
284           int right_rank = Paper_column::get_rank (rc);
285           int left_rank = Paper_column::get_rank (lc);
286
287           /*
288             update the left column.
289           */
290           if (right_rank <= min_rank)
291             {
292               if (right_rank < min_rank)
293                 rn_arr->clear ();
294
295               min_rank = right_rank;
296               rn_arr->add (wish);
297             }
298
299           /*
300             update the right column of the wish.
301           */
302           int maxrank = 0;
303
304           extract_grob_set (rc, "left-neighbors", lns_arr);
305           if (lns_arr.size ())
306             {
307               Item *it = dynamic_cast<Item *> (lns_arr.top());
308               maxrank = Paper_column::get_rank (it->get_column ());
309             }
310
311           if (left_rank >= maxrank)
312             {
313               
314               if (left_rank > maxrank)
315                 {
316                   Grob_array *ga = unsmob_grob_array (rc->get_object ("left-neighbors"));
317                   if (ga)
318                     ga->clear ();
319                 }
320
321               Pointer_group_interface::add_grob (rc, ly_symbol2scm ("left-neighbors"), wish);
322             }
323         }
324
325       if (rn_arr->size ())
326         {
327           cols[i]->set_object ("right-neighbors", right_neighbors);
328         }
329     }
330 }
331
332 /*
333   Set neighboring columns that have no left/right-neighbor set
334   yet. Only do breakable non-musical columns, and musical columns.
335 */
336 void
337 Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> const &cols)
338 {
339   for (int i = 0; i < cols.size (); i++)
340     {
341       Item *it = dynamic_cast<Item *> (cols[i]);
342       if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
343         continue;
344
345       // it->breakable || it->musical
346
347       /*
348         sloppy with typing left/right-neighbors should take list, but paper-column found instead.
349       */
350       extract_grob_set (cols[i], "left-neighbors", lns);
351       if (lns.is_empty () && i )
352         {
353           SCM ga_scm = Grob_array::make_array();
354           Grob_array *ga = unsmob_grob_array (ga_scm);
355           ga->add (cols[i-1]);
356           cols[i]->set_object ("left-neighbors", ga_scm);
357         }
358       extract_grob_set (cols[i], "right-neighbors", rns);
359       if (rns.is_empty () && i < cols.size () - 1)
360         {
361           SCM ga_scm = Grob_array::make_array();
362           Grob_array *ga = unsmob_grob_array (ga_scm);
363           ga->add (cols[i+1]);
364           cols[i]->set_object ("right-neighbors", ga_scm);
365         }
366     }
367 }
368
369 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
370 SCM
371 Spacing_spanner::set_springs (SCM smob)
372 {
373   Grob *me = unsmob_grob (smob);
374
375   /*
376     can't use get_system() ? --hwn.
377   */
378   Link_array<Grob> all (me->pscore_->root_system ()->columns ());
379
380   set_explicit_neighbor_columns (all);
381
382   SCM preset_shortest = me->get_property ("common-shortest-duration");
383   Rational global_shortest;
384   if (unsmob_moment (preset_shortest))
385     {
386       global_shortest = unsmob_moment (preset_shortest)->main_part_;
387     }
388   else
389     {
390       global_shortest = find_shortest (me, all);
391       if (be_verbose_global)
392         message (_f ("Global shortest duration is %s", global_shortest.to_string ()) + "\n");
393     }
394   prune_loose_columns (me, &all, global_shortest);
395   set_implicit_neighbor_columns (all);
396
397   int j = 0;
398   for (int i = 1; i < all.size (); i++)
399     {
400       Grob *sc = all[i];
401       if (Item::is_breakable (sc))
402         {
403           Link_array<Grob> measure (all.slice (j, i + 1));
404           do_measure (global_shortest, me, &measure);
405           j = i;
406         }
407     }
408
409   return SCM_UNSPECIFIED;
410 }
411
412 /*
413   We want the shortest note that is also "common" in the piece, so we
414   find the shortest in each measure, and take the most frequently
415   found duration.
416
417   This probably gives weird effects with modern music, where every
418   note has a different duration, but hey, don't write that kind of
419   stuff, then.
420 */
421 Rational
422 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
423 {
424   /*
425     ascending in duration
426   */
427   Array<Rational> durations;
428   Array<int> counts;
429
430   Rational shortest_in_measure;
431   shortest_in_measure.set_infinite (1);
432
433   for (int i = 0; i < cols.size (); i++)
434     {
435       if (Paper_column::is_musical (cols[i]))
436         {
437           Moment *when = unsmob_moment (cols[i]->get_property ("when"));
438
439           /*
440             ignore grace notes for shortest notes.
441           */
442           if (when && when->grace_part_)
443             continue;
444
445           SCM st = cols[i]->get_property ("shortest-starter-duration");
446           Moment this_shortest = *unsmob_moment (st);
447           assert (this_shortest.to_bool ());
448           shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
449         }
450       else if (!shortest_in_measure.is_infinity ()
451                && Item::is_breakable (cols[i]))
452         {
453           int j = 0;
454           for (; j < durations.size (); j++)
455             {
456               if (durations[j] > shortest_in_measure)
457                 {
458                   counts.insert (1, j);
459                   durations.insert (shortest_in_measure, j);
460                   break;
461                 }
462               else if (durations[j] == shortest_in_measure)
463                 {
464                   counts[j]++;
465                   break;
466                 }
467             }
468
469           if (durations.size () == j)
470             {
471               durations.push (shortest_in_measure);
472               counts.push (1);
473             }
474
475           shortest_in_measure.set_infinite (1);
476         }
477     }
478
479   int max_idx = -1;
480   int max_count = 0;
481   for (int i = durations.size (); i--;)
482     {
483       if (counts[i] >= max_count)
484         {
485           max_idx = i;
486           max_count = counts[i];
487         }
488
489       //      printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
490     }
491
492   SCM bsd = me->get_property ("base-shortest-duration");
493   Rational d = Rational (1, 8);
494   if (Moment *m = unsmob_moment (bsd))
495     d = m->main_part_;
496
497   if (max_idx >= 0)
498     d = min (d, durations[max_idx]);
499
500   return d;
501 }
502
503 /*
504   Generate spacing for a single measure. We used to have code that did
505   per-measure spacing. Now we have piecewise spacing. We should fix
506   this to support "spacing-regions": some regions have different notes
507   (different time sigs) than others, and should be spaced differently.
508 */
509 void
510 Spacing_spanner::do_measure (Rational global_shortest, Grob *me,
511                              Link_array<Grob> *cols)
512 {
513   Real headwid = robust_scm2double (me->get_property ("spacing-increment"), 1);
514   for (int i = 0; i < cols->size () - 1; i++)
515     {
516       Item *l = dynamic_cast<Item *> (cols->elem (i));
517       Item *r = dynamic_cast<Item *> (cols->elem (i + 1));
518
519       Paper_column *lc = dynamic_cast<Paper_column *> (l);
520       Paper_column *rc = dynamic_cast<Paper_column *> (r);
521
522       if (Paper_column::is_musical (l))
523         {
524           musical_column_spacing (me, lc, rc, headwid, global_shortest);
525           if (Item *rb = r->find_prebroken_piece (LEFT))
526             musical_column_spacing (me, lc, rb, headwid, global_shortest);
527         }
528       else
529         {
530           /*
531             The case that the right part is broken as well is rather
532             rare, but it is possible, eg. with a single empty measure,
533             or if one staff finishes a tad earlier than the rest.
534           */
535           Item *lb = l->find_prebroken_piece (RIGHT);
536           Item *rb = r->find_prebroken_piece (LEFT);
537
538           if (i == 0 && Paper_column::get_rank (l) == 0)
539             l = 0;
540
541           if (l && r)
542             breakable_column_spacing (me, l, r, global_shortest);
543           
544           if (lb && r)
545             breakable_column_spacing (me, lb, r, global_shortest);
546
547           if (l && rb)
548             breakable_column_spacing (me, l, rb, global_shortest);
549
550           if (lb && rb)
551             breakable_column_spacing (me, lb, rb, global_shortest);
552         }
553     }
554 }
555
556 /*
557   Generate the space between two musical columns LC and RC, given
558   spacing parameters INCR and SHORTEST.
559 */
560 void
561 Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc, Real increment, Rational global_shortest)
562 {
563   bool expand_only = false;
564   Real base_note_space = note_spacing (me, lc, rc, global_shortest, &expand_only);
565
566   Real compound_note_space = 0.0;
567   Real compound_fixed_note_space = 0.0;
568   int wish_count = 0;
569
570   extract_grob_set (lc, "right-neighbors", neighbors);
571
572   /*
573     We adjust the space following a note only if the next note
574     happens after the current note (this is set in the grob
575     property SPACING-SEQUENCE.
576   */
577   for (int i = 0; i < neighbors.size (); i++)
578     {
579       Grob *wish = neighbors[i];
580
581       Item *wish_rcol = Note_spacing::right_column (wish);
582       if (Note_spacing::left_column (wish) != lc
583           || (wish_rcol != rc && wish_rcol != rc->original_))
584         continue;
585
586       /*
587         This is probably a waste of time in the case of polyphonic
588         music.  */
589       if (Note_spacing::has_interface (wish))
590         {
591           Real space = 0.0;
592           Real fixed = 0.0;
593
594           Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
595
596           compound_note_space = compound_note_space + space;
597           compound_fixed_note_space = compound_fixed_note_space + fixed;
598           wish_count++;
599         }
600     }
601
602   if (Paper_column::when_mom (rc).grace_part_
603       && !Paper_column::when_mom (lc).grace_part_)
604     {
605       /*
606         Ugh. 0.8 is arbitrary.
607       */
608       compound_note_space *= 0.8;
609     }
610
611   if (compound_note_space < 0 || wish_count == 0)
612     {
613       compound_note_space = base_note_space;
614       compound_fixed_note_space = increment;
615     }
616   else
617     {
618       compound_note_space /= wish_count;
619       compound_fixed_note_space /= wish_count;
620     }
621
622   /*
623     Whatever we do, the fixed space is smaller than the real
624     space.
625
626     TODO: this criterion is discontinuous in the derivative.
627     Maybe it should be continuous?
628   */
629   compound_fixed_note_space = min (compound_fixed_note_space, compound_note_space);
630
631   bool packed = to_boolean (me->get_layout ()->c_variable ("packed"));
632   Real inverse_strength = 1.0;
633   Real distance = 1.0;
634
635   /*
636     TODO: make sure that the space doesn't exceed the right margin.
637   */
638   if (packed)
639     {
640       /*
641         In packed mode, pack notes as tight as possible.  This makes
642         sense mostly in combination with raggedright mode: the notes
643         are then printed at minimum distance.  This is mostly useful
644         for ancient notation, but may also be useful for some flavours
645         of contemporary music.  If not in raggedright mode, lily will
646         pack as much bars of music as possible into a line, but the
647         line will then be stretched to fill the whole linewidth.
648       */
649       inverse_strength = 1.0;
650       distance = compound_fixed_note_space;
651     }
652   else
653     {
654       inverse_strength = (compound_note_space - compound_fixed_note_space);
655       distance = compound_note_space;
656     }
657
658   Spaceable_grob::add_spring (lc, rc, distance, inverse_strength);
659 }
660
661 /*
662   The one-size-fits all spacing. It doesn't take into account
663   different spacing wishes from one to the next column.
664 */
665 void
666 Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
667                                                     Real *fixed, Real *space,
668                                                     Moment shortest)
669 {
670   *fixed = 0.0;
671   Direction d = LEFT;
672   Drul_array<Item *> cols (l, r);
673
674   do
675     {
676       if (!Paper_column::is_musical (cols[d]))
677         {
678           /*
679             Tied accidentals over barlines cause problems, so lets see
680             what happens if we do this for non musical columns only.
681           */
682           Interval lext = cols[d]->extent (cols [d], X_AXIS);
683           if (!lext.is_empty ())
684             *fixed += -d * lext[-d];
685         }
686     }
687   while (flip (&d) != LEFT);
688
689   if (l->is_breakable (l) && r->is_breakable (r))
690     {
691       Moment *dt = unsmob_moment (l->get_property ("measure-length"));
692       Moment mlen (1);
693       if (dt)
694         mlen = *dt;
695
696       Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
697
698       *space = *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
699     }
700   else
701     {
702       Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
703
704       if (dt == Moment (0, 0))
705         {
706           /*
707             In this case, Staff_spacing should handle the job,
708             using dt when it is 0 is silly.
709           */
710           *space = *fixed + 0.5;
711         }
712       else
713         {
714           bool dummy;
715           *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
716         }
717     }
718 }
719
720 /*
721   Read hints from L and generate springs.
722 */
723 void
724 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r, Moment shortest)
725 {
726   Real compound_fixed = 0.0;
727   Real compound_space = 0.0;
728   int wish_count = 0;
729
730   Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
731
732   if (dt == Moment (0, 0))
733     {
734       extract_grob_set (l, "spacing-wishes", wishes);
735
736       for (int i = 0; i < wishes.size (); i++)
737         {
738           Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
739
740           if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
741             continue;
742
743           Real space;
744           Real fixed_space;
745
746           /*
747             column for the left one settings should be ok due automatic
748             pointer munging.
749
750           */
751           assert (spacing_grob->get_column () == l);
752
753           Staff_spacing::get_spacing_params (spacing_grob,
754                                              &space, &fixed_space);
755
756           if (Paper_column::when_mom (r).grace_part_)
757             {
758               /*
759                 Correct for grace notes.
760
761                 Ugh. The 0.8 is arbitrary.
762               */
763               space *= 0.8;
764             }
765
766           compound_space += space;
767           compound_fixed += fixed_space;
768           wish_count++;
769         }
770     }
771
772   if (compound_space <= 0.0 || !wish_count)
773     {
774       standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space,
775                                          shortest);
776       wish_count = 1;
777     }
778   else
779     {
780       compound_space /= wish_count;
781       compound_fixed /= wish_count;
782     }
783
784   assert (!isinf (compound_space));
785   compound_space = max (compound_space, compound_fixed);
786
787   /*
788     There used to be code that changed spacing depending on
789     raggedright setting.  Ugh.
790
791     Do it more cleanly, or rename the property.
792
793   */
794   Real inverse_strength = (compound_space - compound_fixed);
795   Real distance = compound_space;
796   Spaceable_grob::add_spring (l, r, distance, inverse_strength);
797 }
798
799 /**
800    Get the measure wide ant for arithmetic spacing.
801 */
802 Real
803 Spacing_spanner::get_duration_space (Grob *me, Moment d, Rational shortest, bool *expand_only)
804 {
805   Real k = robust_scm2double (me->get_property ("shortest-duration-space"), 1);
806   Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
807
808   if (d < shortest)
809     {
810       /*
811         We don't space really short notes using the log of the
812         duration, since it would disproportionally stretches the long
813         notes in a piece. In stead, we use geometric spacing with constant 0.5
814         (i.e. linear.)
815
816         This should probably be tunable, to use other base numbers.
817
818         In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
819         3.6 mm (total).  head-width = 2.4, so we 1.2mm for 16th, 1.5
820         mm for 8th. (white space), suggesting that we use
821
822         (1.2 / 1.5)^{-log2(duration ratio)}
823
824
825       */
826       Rational ratio = d.main_part_ / shortest;
827
828       return ((k - 1) + double (ratio)) * incr;
829     }
830   else
831     {
832       /*
833         John S. Gourlay. ``Spacing a Line of Music, '' Technical
834         Report OSU-CISRC-10/87-TR35, Department of Computer and
835         Information Science, The Ohio State University, 1987.
836       */
837       Real log = log_2 (shortest);
838       k -= log;
839       Rational compdur = d.main_part_ + d.grace_part_ / Rational (3);
840       *expand_only = false;
841
842       return (log_2 (compdur) + k) * incr;
843     }
844 }
845
846 Real
847 Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc,
848                                Moment shortest, bool *expand_only)
849 {
850   Moment shortest_playing_len = 0;
851   SCM s = lc->get_property ("shortest-playing-duration");
852
853   if (unsmob_moment (s))
854     shortest_playing_len = *unsmob_moment (s);
855
856   if (! shortest_playing_len.to_bool ())
857     {
858       programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
859       shortest_playing_len = 1;
860     }
861
862   Moment lwhen = Paper_column::when_mom (lc);
863   Moment rwhen = Paper_column::when_mom (rc);
864
865   Moment delta_t = rwhen - lwhen;
866   if (!Paper_column::is_musical (rc))
867     {
868       /*
869         when toying with mmrests, it is possible to have musical
870         column on the left and non-musical on the right, spanning
871         several measures.
872       */
873
874       Moment *dt = unsmob_moment (rc->get_property ("measure-length"));
875       if (dt)
876         {
877           delta_t = min (delta_t, *dt);
878
879           /*
880             The following is an extra safety measure, such that
881             the length of a mmrest event doesn't cause havoc.
882           */
883           shortest_playing_len = min (shortest_playing_len, *dt);
884         }
885     }
886   Real dist = 0.0;
887
888   /*
889     In normal situations, the next column is at most
890     SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
891     with durations, invalidating this assumption. Here we kludge
892     around to get chord tremolos to behave properly.
893
894   */
895   shortest_playing_len = max (shortest_playing_len, delta_t);
896   if (delta_t.main_part_ && !lwhen.grace_part_)
897     {
898       dist = get_duration_space (me, shortest_playing_len,
899                                  shortest.main_part_, expand_only);
900       dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_);
901     }
902   else if (delta_t.grace_part_)
903     {
904       /*
905         TODO: figure out how to space grace notes.
906       */
907       dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
908
909       Real grace_fact
910         = robust_scm2double (me->get_property ("grace-space-factor"), 1);
911
912       dist *= grace_fact;
913     }
914
915   return dist;
916 }
917
918 ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
919                "The space taken by a note is dependent on its duration. Doubling a\n"
920                "duration adds spacing-increment to the space. The most common shortest\n"
921                "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
922                "spaced proportonial to their duration.\n"
923                "\n"
924                "Typically, the increment is the width of a black note head.  In a\n"
925                "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
926                "gets 2 note heads width (i.e. the space following a note is 1 note\n"
927                "head width) A 16th note is followed by 0.5 note head width. The\n"
928                "quarter note is followed by  3 NHW, the half by 4 NHW, etc.\n",
929                
930                "grace-space-factor spacing-increment base-shortest-duration "
931                "shortest-duration-space common-shortest-duration"
932
933                );
934
935 ADD_INTERFACE (Spacing_interface, "spacing-interface",
936                "Something to do with line breaking and spacing. "
937                "Kill this one after determining line breaks.",
938                "");
939