]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
659216be561657e57604de0631f527cf2f980243
[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--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include <math.h>
11 #include <stdio.h>
12
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"
30
31
32 /*
33   TODO: this file/class is too complex. Should figure out how to chop
34   this up even more.
35     
36  */
37
38 class Spacing_spanner
39 {
40 public:
41   static void standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
42                                                  Real * fixed, Real * space, Moment);
43   
44
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*);
59 };
60
61 /*
62   Return whether COL is fixed to its neighbors by some kind of spacing
63   constraint.
64
65   
66   If in doubt, then we're not loose; the spacing engine should space
67   for it, risking suboptimal spacing.
68   
69   (Otherwise, we might risk core dumps, and other weird stuff.)
70
71 */
72 static bool
73 loose_column (Grob *l, Grob *c, Grob *r) 
74 {
75   SCM rns = c->get_grob_property ("right-neighbors");
76   SCM lns = c->get_grob_property ("left-neighbors");
77
78  /*
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.
82
83     (this happens in the following situation:
84
85        |
86        |    clef G 
87       *
88
89        |               |      ||
90        |               |      || 
91       O               O       ||
92
93
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.)
97     
98   */  
99   if (!gh_pair_p (lns) || !gh_pair_p (rns))
100     return false;
101
102   Item * l_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (lns)));
103   Item * r_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (rns)));
104
105   if (!l_neighbor || !r_neighbor)
106     return false;
107
108   l_neighbor = l_neighbor->get_column ();
109   r_neighbor = dynamic_cast<Item*> (Note_spacing::right_column  (r_neighbor));
110
111   if (l == l_neighbor && r == r_neighbor)
112     return false;
113
114   if (!l_neighbor || !r_neighbor)
115     return false;
116
117
118   
119   /*
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.
123   */
124   if(!  ((Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
125          && (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_neighbor))) )
126     {
127       return false;
128     }
129
130
131   /*
132     A rather hairy check, but we really only want to move around clefs. (anything else?)
133
134     in any case, we don't want to move bar lines.
135    */
136   for (SCM e = c->get_grob_property ("elements"); gh_pair_p (e); e = gh_cdr (e))
137     {
138       Grob * g = unsmob_grob (gh_car (e));
139       if (g && Break_align_interface::has_interface (g))
140         {
141           for (SCM s = g->get_grob_property ("elements"); gh_pair_p (s);
142                s = gh_cdr (s))
143             {
144               Grob *h = unsmob_grob (gh_car (s));
145
146               /*
147                 ugh. -- fix staff-bar name? 
148                */
149               if (h  && h->get_grob_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
150                 return false;
151             }
152         }
153     }
154   
155   return true;
156 }
157
158 /*
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.
162 */
163 void
164 Spacing_spanner::prune_loose_columns (Grob*me,Link_array<Grob> *cols, Rational shortest)
165 {
166   Link_array<Grob> newcols;
167   Real increment = robust_scm2double (me->get_grob_property ("spacing-increment"), 1.2);
168   for (int i=0; i < cols->size ();  i++)
169     {
170       if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
171         {
172           newcols.push (cols->elem(i));
173           continue;
174         }
175
176       Grob *c = cols->elem(i);
177       if (loose_column (cols->elem (i-1), c, cols->elem (i+1)))
178         {
179           SCM lns = c->get_grob_property ("left-neighbors");
180           lns = gh_pair_p (lns) ? gh_car (lns) : SCM_BOOL_F;
181
182           SCM rns = c->get_grob_property ("right-neighbors");
183           rns = gh_pair_p (rns) ? gh_car (rns) : SCM_BOOL_F;
184
185           /*
186             Either object can be non existent, if the score ends
187             prematurely.
188            */
189           rns = gh_car (unsmob_grob (rns)->get_grob_property ("right-items"));
190           c->set_grob_property ("between-cols", gh_cons (lns,
191                                                          rns));
192
193           /*
194             Set distance constraints for loose columns
195           */
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);
201
202           do
203             {
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]);
207
208               for (SCM s = lc->get_grob_property ("spacing-wishes");
209                    gh_pair_p (s); s = gh_cdr (s))
210                 {
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;
215
216                   Real space, fixed;
217                   fixed = 0.0;
218                   bool dummy;
219
220                   if (d == LEFT)
221                     {
222                       /*
223                         The note spacing should be taken from the musical
224                         columns.
225                     
226                       */
227                       Real base = note_spacing (me, lc, rc, shortest, &dummy);
228                       Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
229
230                       space -= increment; 
231                   
232                       dists[d] = dists[d] >? space;
233                     }
234                   else
235                     {
236                       Real space, fixed_space;
237                       Staff_spacing::get_spacing_params (sp,
238                                                          &space, &fixed_space);
239
240                       dists[d] = dists[d] >? fixed_space;
241                     }
242                   
243                 }
244             }
245           while (flip (&d) != LEFT);
246
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));
251
252           r.add_to_cols ();
253         }
254       else
255         {
256           newcols.push (c);
257         }
258     }
259
260   *cols = newcols;
261 }
262
263 /*
264   Set neighboring columns determined by the spacing-wishes grob property.  
265 */
266 void
267 Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
268 {
269   for (int i=0; i < cols.size(); i++)
270     {
271       SCM right_neighbors = SCM_EOL;
272       int min_rank = 100000;    // inf.
273
274
275       SCM wishes=  cols[i]->get_grob_property ("spacing-wishes");
276       for (SCM s =wishes; gh_pair_p (s); s = gh_cdr (s))
277         {
278           Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
279
280           Item * lc = wish->get_column ();
281           Grob * right = Note_spacing::right_column (wish);
282
283           if (!right)
284             continue;
285
286           Item * rc = dynamic_cast<Item*> (right);
287
288           int right_rank = Paper_column::get_rank (rc);
289           int left_rank = Paper_column::get_rank (lc);    
290
291           /*
292             update the left column.
293            */
294           if (right_rank <= min_rank)
295             {
296               if (right_rank < min_rank)
297                 right_neighbors  =SCM_EOL;
298               
299               min_rank = right_rank;
300               right_neighbors = gh_cons (wish->self_scm (), right_neighbors);
301             }
302
303           /*
304             update the right column of the wish.
305            */
306           int maxrank = 0;
307           SCM left_neighs = rc->get_grob_property ("left-neighbors");
308           if (gh_pair_p (left_neighs)
309               && unsmob_grob (gh_car (left_neighs)))
310             {
311               Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
312               maxrank = Paper_column::get_rank (it->get_column ());
313             }
314
315           if (left_rank >= maxrank)
316             {
317               if (left_rank > maxrank)
318                 left_neighs = SCM_EOL;
319
320               left_neighs = gh_cons (wish->self_scm (), left_neighs);
321               rc->set_grob_property ("left-neighbors", right_neighbors);
322             }
323         }
324
325       if (gh_pair_p (right_neighbors))
326         {
327           cols[i]->set_grob_property ("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> cols)
338 {
339   for (int i = 0; i < cols.size (); i++)
340     {
341       Item * it = dynamic_cast<Item*>(cols[i]);
342       if (!Item::breakable_b (it) && !Paper_column::musical_b (it))
343         continue;
344
345       // it->breakable || it->musical
346
347       /*
348         sloppy with typnig left/right-neighbors should take list, but paper-column found instead.
349        */
350       SCM ln = cols[i] ->get_grob_property ("left-neighbors");
351       if (!gh_pair_p (ln) && i ) 
352         {
353           cols[i]->set_grob_property ("left-neighbors", gh_cons (cols[i-1]->self_scm(), SCM_EOL));
354         }
355
356       SCM rn = cols[i] ->get_grob_property ("right-neighbors");
357       if (!gh_pair_p (rn) && i < cols.size () - 1) 
358         {
359           cols[i]->set_grob_property ("right-neighbors", gh_cons (cols[i + 1]->self_scm(), SCM_EOL));
360         }
361     }
362 }
363
364
365 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs,1);
366 SCM
367 Spacing_spanner::set_springs (SCM smob)
368 {
369   Grob *me = unsmob_grob (smob);
370
371   Link_array<Grob> all (me->pscore_->system_->columns ());
372
373   set_explicit_neighbor_columns (all);
374
375   SCM preset_shortest = me->get_grob_property ("common-shortest-duration");
376   Rational global_shortest;
377   if (unsmob_moment (preset_shortest))
378     {
379       global_shortest = unsmob_moment (preset_shortest)->main_part_;
380     }
381   else
382     {
383       global_shortest = find_shortest (me, all);
384       if (verbose_global_b)
385         {
386           progress_indication (_f("Global shortest duration is %s\n", global_shortest.to_string ())); 
387         }
388     }
389   prune_loose_columns (me, &all, global_shortest);
390   set_implicit_neighbor_columns (all);
391
392   
393   int j = 0;
394   for (int i = 1; i < all.size (); i++)
395     {
396       Grob *sc = all[i];
397       if (Item::breakable_b (sc))
398         {
399           Link_array<Grob> measure (all.slice (j, i+1));          
400           do_measure (global_shortest, me, &measure);
401           j = i;
402         }
403     }
404
405   return SCM_UNSPECIFIED;
406 }
407
408
409 /*
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.
413
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.
417
418 */
419 Rational
420 Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
421 {
422   /*
423     ascending in duration
424    */
425   Array<Rational> durations; 
426   Array<int> counts;
427   
428   Rational shortest_in_measure;
429   shortest_in_measure.set_infinite (1);
430   
431   for (int i =0 ; i < cols.size (); i++)  
432     {
433       if (Paper_column::musical_b (cols[i]))
434         {
435           Moment *when = unsmob_moment (cols[i]->get_grob_property  ("when"));
436
437           /*
438             ignore grace notes for shortest notes.
439           */
440           if (when && when->grace_part_)
441             continue;
442           
443           SCM  st = cols[i]->get_grob_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_;
447         }
448       else if (!shortest_in_measure.is_infinity ()
449                && Item::breakable_b (cols[i]))
450         {
451           int j = 0;
452           for (; j < durations.size(); j++)
453             {
454               if (durations[j] > shortest_in_measure)
455                 {
456                   counts.insert (1, j);
457                   durations.insert (shortest_in_measure, j);
458                   break;
459                 }
460               else if (durations[j] == shortest_in_measure)
461                 {
462                   counts[j]++;
463                   break;
464                 }
465             }
466
467           if (durations.size() == j)
468             {
469               durations.push (shortest_in_measure);
470               counts.push (1);
471             }
472
473           shortest_in_measure.set_infinite(1); 
474         }
475     }
476
477   int max_idx = -1;
478   int max_count = 0;
479   for (int i =durations.size(); i--;)
480     {
481       if (counts[i] >= max_count)
482         {
483           max_idx = i;
484           max_count = counts[i];
485         }
486
487       //      printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
488     }
489
490   SCM  bsd = me->get_grob_property ("base-shortest-duration");
491   Rational d = Rational (1,8);
492   if (Moment *m = unsmob_moment (bsd))
493     d = m->main_part_;
494   
495   if (max_idx >= 0)
496     d = d <? durations[max_idx] ;
497
498   return d;
499 }
500
501 /*
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.
506  */
507 void
508 Spacing_spanner::do_measure (Rational shortest, Grob*me, Link_array<Grob> *cols) 
509 {
510
511   Real headwid = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
512   for (int i= 0; i < cols->size () - 1; i++)
513     {
514       Item * l = dynamic_cast<Item*> (cols->elem (i));
515       Item * r =  dynamic_cast<Item*> (cols->elem (i+1));
516
517       Paper_column * lc = dynamic_cast<Paper_column*> (l);
518       Paper_column * rc = dynamic_cast<Paper_column*> (r);
519
520       if (!Paper_column::musical_b (l))
521         {
522           breakable_column_spacing (me, l, r, shortest);
523
524           /*
525             
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.
529             
530            */
531           Item *lb = l->find_prebroken_piece (RIGHT);
532           Item *rb = r->find_prebroken_piece (LEFT);
533           
534           if (lb)
535             breakable_column_spacing (me, lb,r, shortest);
536
537           if (rb)
538             breakable_column_spacing (me, l, rb, shortest);
539           if (lb && rb)
540             breakable_column_spacing (me, lb, rb, shortest);
541           
542           continue ; 
543         }
544
545
546       musical_column_spacing (me, lc, rc, headwid, shortest);
547       if (Item *rb = r->find_prebroken_piece (LEFT))
548         musical_column_spacing (me, lc, rb, headwid, shortest);
549     }    
550 }
551
552
553 /*
554   Generate the space between two musical columns LC and RC, given
555   spacing parameters INCR and SHORTEST.
556  */
557 void
558 Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real increment, Rational shortest)
559 {
560   bool expand_only = false;
561   Real base_note_space = note_spacing (me, lc, rc, shortest, &expand_only);
562
563   Real compound_note_space = 0.0;
564   Real compound_fixed_note_space = 0.0;
565   int wish_count = 0;
566   
567   SCM seq  = lc->get_grob_property ("right-neighbors");
568
569   /*
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.
573   */
574   for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
575     {
576       Grob * wish = unsmob_grob (gh_car (s));
577
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;
582
583       /*
584         This is probably a waste of time in the case of polyphonic
585         music.  */
586       if (Note_spacing::has_interface (wish))
587         {
588           Real space =0.0;
589           Real fixed =0.0;
590           
591           Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
592
593           
594           compound_note_space = compound_note_space + space;
595           compound_fixed_note_space = compound_fixed_note_space + fixed;
596           wish_count ++;
597           
598         }
599     }
600
601   if (Paper_column::when_mom (rc).grace_part_ &&
602       !Paper_column::when_mom (lc).grace_part_)
603     {
604       /*
605         Ugh. 0.8 is arbitrary.
606        */
607       compound_note_space *= 0.8; 
608     }
609   
610   if (compound_note_space < 0 || wish_count == 0)
611     {
612       compound_note_space = base_note_space;
613       compound_fixed_note_space =  increment;
614     }
615   else
616     {
617       compound_note_space /= wish_count;
618       compound_fixed_note_space /= wish_count;
619     }
620
621   /*
622     Whatever we do, the fixed space is smaller than the real
623     space.
624
625     TODO: this criterion is discontinuous in the derivative.
626     Maybe it should be continuous?
627   */
628   compound_fixed_note_space = compound_fixed_note_space <? compound_note_space;
629
630   bool packed = to_boolean (me->get_paper ()->get_scmvar ("packed"));
631   Real strength, distance;
632
633   /*
634     TODO: make sure that the space doesn't exceed the right margin.
635    */
636   if (packed)
637     {
638       /*
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.
646       */
647       strength = 1.0;
648       distance = compound_fixed_note_space;
649     }
650   else
651     {
652       strength = 1 / (compound_note_space - compound_fixed_note_space);
653       distance = compound_note_space;
654     }
655
656   //  Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only);
657
658   Spaceable_grob::add_spring (lc, rc, distance, strength, false);  
659 }
660
661
662 /*
663   The one-size-fits all spacing. It doesn't take into account
664   different spacing wishes from one to the next column.
665  */
666 void
667 Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
668                                    Real * fixed, Real * space,
669                                    Moment shortest)
670 {
671   *fixed = 0.0;
672   Direction d = LEFT;
673   Drul_array<Item*> cols(l,r);
674   
675   do
676     {
677       if (!Paper_column::musical_b (cols[d]))
678         {
679           /*
680             Tied accidentals over barlines cause problems, so lets see
681             what happens if we do this for non musical columns only.
682            */
683           Interval lext = cols[d]->extent (cols [d], X_AXIS);
684           if (!lext.is_empty ())
685             *fixed += -d * lext[-d];
686         }
687     }
688   while (flip (&d) != LEFT);
689   
690
691   if (l->breakable_b (l) && r->breakable_b(r))
692     {
693       Moment *dt = unsmob_moment (l->get_grob_property ("measure-length"));
694       Moment mlen (1);
695       if (dt)
696         mlen = *dt;
697       
698       Real incr = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
699
700       *space =  *fixed + incr * double (mlen.main_part_ / shortest.main_part_) * 0.8;
701     }
702   else
703     {
704       Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
705
706       if (dt == Moment (0,0))
707         {
708           /*
709             In this case, Staff_spacing should handle the job,
710             using dt when it is 0 is silly.
711            */
712           *space = *fixed + 0.5; 
713         }
714       else
715         {
716           bool dummy;
717           *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
718         }
719     }
720 }
721
722
723 /*
724   Read hints from L and generate springs.
725 */
726 void
727 Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
728 {
729   Real compound_fixed = 0.0;
730   Real compound_space = 0.0;
731   int wish_count = 0;
732
733   Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
734
735   if (dt == Moment (0,0))
736     {
737       for (SCM s = l->get_grob_property ("spacing-wishes");
738            gh_pair_p (s); s = gh_cdr (s))
739         {
740           Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
741
742           if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
743             continue;
744
745           Real space;
746           Real fixed_space;
747
748           /*
749             column for the left one settings should be ok due automatic
750             pointer munging.
751
752           */
753           assert (spacing_grob-> get_column () == l);
754
755           Staff_spacing::get_spacing_params (spacing_grob,
756                                              &space, &fixed_space);
757
758           if (Paper_column::when_mom (r).grace_part_)
759             {
760               /*
761                 Correct for grace notes.
762
763                 Ugh. The 0.8 is arbitrary.
764               */
765               space *= 0.8;
766             }
767
768
769           compound_space += space;
770           compound_fixed += fixed_space;
771           wish_count ++ ;
772         }
773     }
774
775   if (compound_space <= 0.0 || !wish_count)
776     {
777       standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space ,
778                                          shortest);
779       wish_count = 1;
780     }
781   else
782     {
783       compound_space /= wish_count;
784       compound_fixed /= wish_count;
785     }
786
787   assert (!isinf (compound_space));
788   compound_space = compound_space >? compound_fixed;
789
790   
791   /*
792     Hmm.  we do 1/0 in the next thing. Perhaps we should check if this
793     works on all architectures.
794    */
795
796   /*
797     There used to be code that changed spacing depending on
798     raggedright setting.  Ugh.
799
800     Do it more cleanly, or rename the property. 
801     
802    */
803   Real strength = 1 / (compound_space - compound_fixed);
804   Real distance = compound_space;
805   Spaceable_grob::add_spring (l, r, distance, strength, false);
806 }
807
808
809 /**
810   Get the measure wide ant for arithmetic spacing.
811   */
812 Real
813 Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only) 
814 {
815   Real k = robust_scm2double (me->get_grob_property ("shortest-duration-space"), 1);
816   Real incr = robust_scm2double (me->get_grob_property ("spacing-increment"), 1);
817   
818   if (d < shortest)
819     {
820       /*
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.)
825
826         This should probably be tunable, to use other base numbers.
827
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
831
832         (1.2 / 1.5)^{-log2(duration ratio)}
833         
834
835        */
836       Rational ratio = d.main_part_ / shortest;
837
838       return ((k-1) + double (ratio)) * incr;
839     }
840   else
841     {
842       /*
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.
846        */
847       Real log =  log_2 (shortest);
848       k -= log;
849       Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
850       *expand_only = false;      
851    
852       return (log_2 (compdur) + k) * incr;
853     }
854 }
855
856 Real
857 Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
858                                Moment shortest, bool * expand_only) 
859 {
860   Moment shortest_playing_len = 0;
861   SCM s = lc->get_grob_property ("shortest-playing-duration");
862
863   if (unsmob_moment (s))
864     shortest_playing_len = *unsmob_moment (s);
865   
866   if (! shortest_playing_len.to_bool ())
867     {
868       programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
869       shortest_playing_len = 1;
870     }
871
872   Moment lwhen = Paper_column::when_mom (lc);
873   Moment rwhen =  Paper_column::when_mom (rc);
874
875   Moment delta_t = rwhen - lwhen;
876   if (!Paper_column::musical_b (rc ))
877     {
878       /*
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.
882
883         In 2.0.1, this still fucks up in an interesting way:
884
885         
886 \score {
887 {       \property Score.skipBars = ##t
888         \context Staff = clarinet
889             { 
890                 \notes {
891                 \time 3/4 \mark "72"
892 << s1*0^"all"           R4*3*11 >>
893                 \mark "73"
894                 R4*3*11 \mark "74"
895         d2 r4
896
897
898                 }}}
899     \paper { raggedright = ##t }
900 }
901
902         
903        */
904       
905       Moment *dt = unsmob_moment (rc->get_grob_property ("measure-length"));
906       if (dt)
907         delta_t = delta_t <? *dt; 
908     }
909   Real dist = 0.0;
910
911   /*
912     In normal situations, the next column is at most
913     SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
914     with durations, invalidating this assumption. Here we kludge
915     around to get chord tremolos to behave properly.
916     
917    */
918   shortest_playing_len = shortest_playing_len >? delta_t;
919   if (delta_t.main_part_ && !lwhen.grace_part_)
920     {
921       dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
922       dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
923     }
924   else if (delta_t.grace_part_)
925     {
926       /*
927         TODO: figure out how to space grace notes.
928       */
929       dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
930
931       Real grace_fact
932         = robust_scm2double (me->get_grob_property ("grace-space-factor"), 1);
933
934       dist *= grace_fact;
935     }
936
937   
938   return dist;
939 }
940
941
942
943 ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
944 "The space taken by a note is dependent on its duration. Doubling a\n"
945 "duration adds spacing-increment to the space. The most common shortest\n"
946 "note gets shortest-duration-space. Notes that are even shorter are\n"
947 "spaced proportonial to their duration.\n"
948 "\n"
949 "Typically, the increment is the width of a black note head.  In a\n"
950 "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
951 "gets 2 note heads width (i.e. the space following a note is 1 note\n"
952 "head width) A 16th note is followed by 0.5 note head width. The\n"
953 "quarter note is followed by  3 NHW, the half by 4 NHW, etc.\n",
954   "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space common-shortest-duration");
955
956
957
958 ADD_INTERFACE (Spacing_interface,"spacing-interface",
959   "Something to do with line breaking and spacing. Kill this one after determining line breaks.",
960   "");
961