]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
update outdated comments
[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--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "spacing-spanner.hh"
10
11 #include <math.h>
12 #include <cstdio>
13
14 #include "spacing-options.hh"
15 #include "international.hh"
16 #include "main.hh"
17 #include "moment.hh"
18 #include "note-spacing.hh"
19 #include "output-def.hh"
20 #include "paper-column.hh"
21 #include "paper-score.hh"
22 #include "pointer-group-interface.hh"
23 #include "spaceable-grob.hh"
24 #include "spacing-interface.hh"
25 #include "staff-spacing.hh"
26 #include "system.hh"
27 #include "warn.hh"
28
29 vector<Grob*>
30 Spacing_spanner::get_columns (Grob *me_grob)
31 {
32   Spanner *me = dynamic_cast<Spanner*> (me_grob);
33   vector<Grob*> all (get_root_system (me)->used_columns ());
34   vsize start = binary_search (all, (Grob*)me->get_bound (LEFT),
35                                &Paper_column::less_than);
36   vsize end = binary_search (all, (Grob*) me->get_bound (RIGHT),
37                              &Paper_column::less_than);  
38   
39   all = vector<Grob*>::vector<Grob*> (all.begin () + start,
40                                       all.begin () + end + 1);
41   return all;
42 }
43
44 MAKE_SCHEME_CALLBACK (Spacing_spanner, set_springs, 1);
45 SCM
46 Spacing_spanner::set_springs (SCM smob)
47 {
48   Spanner *me = unsmob_spanner (smob);
49
50   /*
51     can't use get_system () ? --hwn.
52   */
53   Spacing_options options;
54   options.init_from_grob (me);
55   vector<Grob*> cols = Spacing_spanner::get_columns (me);
56   set_explicit_neighbor_columns (cols);
57
58   prune_loose_columns (me, &cols, &options);
59   set_implicit_neighbor_columns (cols);
60   generate_springs (me, cols, &options);
61
62   return SCM_UNSPECIFIED;
63 }
64
65 /*
66   We want the shortest note that is also "common" in the piece, so we
67   find the shortest in each measure, and take the most frequently
68   found duration.
69
70   This probably gives weird effects with modern music, where every
71   note has a different duration, but hey, don't write that kind of
72   stuff, then.
73 */
74
75 MAKE_SCHEME_CALLBACK (Spacing_spanner, calc_common_shortest_duration, 1);
76 SCM 
77 Spacing_spanner::calc_common_shortest_duration (SCM grob)
78 {
79   Spanner *me = unsmob_spanner (grob);
80
81   vector<Grob*> cols (get_columns (me));
82   
83   /*
84     ascending in duration
85   */
86   vector<Rational> durations;
87   vector<int> counts;
88
89   Rational shortest_in_measure;
90   shortest_in_measure.set_infinite (1);
91
92   for (vsize i = 0; i < cols.size (); i++)
93     {
94       if (Paper_column::is_musical (cols[i]))
95         {
96           Moment *when = unsmob_moment (cols[i]->get_property ("when"));
97
98           /*
99             ignore grace notes for shortest notes.
100           */
101           if (when && when->grace_part_)
102             continue;
103
104           SCM st = cols[i]->get_property ("shortest-starter-duration");
105           Moment this_shortest = *unsmob_moment (st);
106           assert (this_shortest.to_bool ());
107           shortest_in_measure = min (shortest_in_measure, this_shortest.main_part_);
108         }
109       else if (!shortest_in_measure.is_infinity ()
110                && Paper_column::is_breakable (cols[i]))
111         {
112           vsize j = 0;
113           for (; j < durations.size (); j++)
114             {
115               if (durations[j] > shortest_in_measure)
116                 {
117                   counts.insert (counts.begin () + j, 1);
118                   durations.insert (durations.begin () + j, shortest_in_measure);
119                   break;
120                 }
121               else if (durations[j] == shortest_in_measure)
122                 {
123                   counts[j]++;
124                   break;
125                 }
126             }
127
128           if (durations.size () == j)
129             {
130               durations.push_back (shortest_in_measure);
131               counts.push_back (1);
132             }
133
134           shortest_in_measure.set_infinite (1);
135         }
136     }
137
138   int max_idx = -1;
139   int max_count = 0;
140   for (vsize i = durations.size (); i--;)
141     {
142       if (counts[i] >= max_count)
143         {
144           max_idx = i;
145           max_count = counts[i];
146         }
147     }
148
149   SCM bsd = me->get_property ("base-shortest-duration");
150   Rational d = Rational (1, 8);
151   if (Moment *m = unsmob_moment (bsd))
152     d = m->main_part_;
153
154   if (max_idx >= 0)
155     d = min (d, durations[max_idx]);
156
157   return Moment (d).smobbed_copy ();
158 }
159
160 void
161 Spacing_spanner::generate_pair_spacing (Grob *me,
162                                         Paper_column *left_col, Paper_column *right_col,
163                                         Paper_column *after_right_col,
164                                         Spacing_options const *options)
165 {
166   if (Paper_column::is_musical (left_col))
167     {
168       if (!Paper_column::is_musical (right_col)
169           && options->float_nonmusical_columns_
170           && after_right_col
171           && Paper_column::is_musical (after_right_col))
172         {
173           /*
174             TODO: should generate rods to prevent collisions.
175           */
176           musical_column_spacing (me, left_col, after_right_col, options);
177           right_col->set_object ("between-cols", scm_cons (left_col->self_scm (),
178                                                            after_right_col->self_scm ()));
179         }
180       else
181         musical_column_spacing (me, left_col, right_col, options);
182
183       if (Item *rb = right_col->find_prebroken_piece (LEFT))
184         musical_column_spacing (me, left_col, rb, options);
185     }
186   else
187     {
188       /*
189         The case that the right part is broken as well is rather
190         rare, but it is possible, eg. with a single empty measure,
191         or if one staff finishes a tad earlier than the rest.
192       */
193       Item *lb = left_col->find_prebroken_piece (RIGHT);
194       Item *rb = right_col->find_prebroken_piece (LEFT);
195
196       if (left_col && right_col)
197         breakable_column_spacing (me, left_col, right_col, options);
198
199       if (lb && right_col)
200         breakable_column_spacing (me, lb, right_col, options);
201
202       if (left_col && rb)
203         breakable_column_spacing (me, left_col, rb, options);
204
205       if (lb && rb)
206         breakable_column_spacing (me, lb, rb, options);
207     }
208 }
209
210 void
211 Spacing_spanner::generate_springs (Grob *me,
212                                    vector<Grob*> const &cols,
213                                    Spacing_options const *options)
214 {
215   Paper_column *prev = 0;
216   for (vsize i = 0; i < cols.size (); i++)
217     {
218       Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
219       Paper_column *next = (i + 1 < cols.size ()) ? dynamic_cast<Paper_column *> (cols[i+1]) : 0;
220       
221       if (i > 0)
222         generate_pair_spacing (me, prev, col, next, options);
223
224       prev = col;
225     }
226 }
227
228 /*
229   Generate the space between two musical columns LEFT_COL and RIGHT_COL.
230 */
231 void
232 Spacing_spanner::musical_column_spacing (Grob *me,
233                                          Item *left_col,
234                                          Item *right_col,
235                                          Spacing_options const *options)
236 {
237   Real base_note_space = note_spacing (me, left_col, right_col, options);
238   Spring spring;
239
240   if (options->stretch_uniformly_)
241     spring = Spring (base_note_space, 0.0);
242   else
243     {
244       vector<Spring> springs;
245       extract_grob_set (left_col, "right-neighbors", neighbors);
246
247       for (vsize i = 0; i < neighbors.size (); i++)
248         {
249           Grob *wish = neighbors[i];
250
251           Item *wish_rcol = Spacing_interface::right_column (wish);
252           if (Spacing_interface::left_column (wish) != left_col
253               || (wish_rcol != right_col && wish_rcol != right_col->original ()))
254             continue;
255
256           /*
257             This is probably a waste of time in the case of polyphonic
258             music.  */
259           if (Note_spacing::has_interface (wish))
260             springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_));
261         }
262
263       if (springs.empty ())
264         {
265
266           if (!Paper_column::is_musical (right_col))
267             {
268               /*
269                 There used to be code that examined left_col->extent
270                 (X_AXIS), but this is resulted in unexpected wide
271                 spacing, because the width of s^"text" output is also
272                 taken into account here.
273                */
274               spring = Spring (max (base_note_space, options->increment_),
275                                options->increment_);
276             }
277           else
278             {
279               /*
280                 Fixed should be 0.0. If there are no spacing wishes, we're
281                 likely dealing with polyphonic spacing of hemiolas.
282             
283                 We used to have min_distance_ = options->increment_
284
285                 but this can lead to numeric instability problems when we
286                 do
287             
288                 inverse_strength = (distance_ - min_distance_)
289       
290               */
291               spring = Spring (base_note_space, 0.0);
292             }
293         }
294       else
295         spring = merge_springs (springs);
296     }
297
298   if (Paper_column::when_mom (right_col).grace_part_
299       && !Paper_column::when_mom (left_col).grace_part_)
300     {
301       /*
302         Ugh. 0.8 is arbitrary.
303       */
304       spring *= 0.8;
305     }
306
307   /*
308     TODO: make sure that the space doesn't exceed the right margin.
309   */
310   if (options->packed_)
311     {
312       /*
313         In packed mode, pack notes as tight as possible.  This makes
314         sense mostly in combination with raggedright mode: the notes
315         are then printed at minimum distance.  This is mostly useful
316         for ancient notation, but may also be useful for some flavours
317         of contemporary music.  If not in raggedright mode, lily will
318         pack as much bars of music as possible into a line, but the
319         line will then be stretched to fill the whole linewidth.
320       */
321       spring.set_distance (spring.min_distance ());
322       spring.set_inverse_stretch_strength (1.0);
323     }
324
325   Spaceable_grob::add_spring (left_col, right_col, spring);
326 }
327
328 /*
329   Check if COL fills the whole measure.
330  */
331 bool
332 Spacing_spanner::fills_measure (Grob *me, Item *left, Item *col)
333 {
334   System *sys = get_root_system (me);
335   Item *next = sys->column (col->get_column ()->get_rank () + 1);
336   if (!next)
337     return false;
338
339   if (Paper_column::is_musical (next)
340       || Paper_column::is_musical (left)
341       || !Paper_column::is_musical (col)
342       || !Paper_column::is_used (next))
343     return false;
344   
345   Moment dt =
346     Paper_column::when_mom (next) - Paper_column::when_mom (col);
347   
348   Moment *len = unsmob_moment (left->get_property ("measure-length"));
349   if (!len)
350     return false;
351   
352   /*
353     Don't check for exact measure length, since ending measures are
354     often shortened due to pickups.
355    */
356   if (dt.main_part_ > len->main_part_ / Rational (2)
357       && (next->is_broken ()
358           || next->break_status_dir ()))
359     return true;
360
361   return false;
362 }
363
364 /*
365   Read hints from L and generate springs.
366 */
367 void
368 Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
369                                            Spacing_options const *options)
370 {
371   vector<Spring> springs;
372   Spring spring;
373
374   Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
375
376   if (dt == Moment (0, 0))
377     {
378       extract_grob_set (l, "spacing-wishes", wishes);
379
380       for (vsize i = 0; i < wishes.size (); i++)
381         {
382           Item *spacing_grob = dynamic_cast<Item *> (wishes[i]);
383
384           if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
385             continue;
386
387           /*
388             column for the left one settings should be ok due automatic
389             pointer munging.
390           */
391           assert (spacing_grob->get_column () == l);
392
393           springs.push_back (Staff_spacing::get_spacing (spacing_grob, r));
394         }
395     }
396
397   if (springs.empty ())
398     spring = standard_breakable_column_spacing (me, l, r, options);
399   else
400     spring = merge_springs (springs);
401
402   if (Paper_column::when_mom (r).grace_part_)
403     {
404       /*
405         Correct for grace notes.
406         
407         Ugh. The 0.8 is arbitrary.
408       */
409       spring *= 0.8;
410     }
411
412   if (Paper_column::is_musical (r)
413       && l->break_status_dir () == CENTER
414       && fills_measure (me, l, r))
415     {
416       spring.set_distance (spring.distance () + 1.0);
417       spring.set_default_strength ();
418     }
419   
420   if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
421     {
422       spring.set_min_distance (0.0);
423       spring.set_default_strength ();
424     }
425
426   Spaceable_grob::add_spring (l, r, spring);
427 }
428
429 ADD_INTERFACE (Spacing_spanner,
430                "The space taken by a note is dependent on its duration. Doubling a\n"
431                "duration adds spacing-increment to the space. The most common shortest\n"
432                "note gets @code{shortest-duration-space}. Notes that are even shorter are\n"
433                "spaced proportonial to their duration.\n"
434                "\n"
435                "Typically, the increment is the width of a black note head.  In a\n"
436                "piece with lots of 8th notes, and some 16th notes, the eighth note\n"
437                "gets 2 note heads width (i.e. the space following a note is 1 note\n"
438                "head width) A 16th note is followed by 0.5 note head width. The\n"
439                "quarter note is followed by  3 NHW, the half by 4 NHW, etc.\n",
440
441                
442                "average-spacing-wishes "
443                "base-shortest-duration "
444                "common-shortest-duration "
445                "packed-spacing "
446                "shortest-duration-space "
447                "spacing-increment "
448                "strict-grace-spacing "
449                "strict-note-spacing "
450                "uniform-stretching "
451                
452                );
453