lilypond-1.3.65
[lilypond.git] / lily / spacing-spanner.cc
blob827213d9fd089b1046a4a5d2f614c6576a89fa6a
1 /*
2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
10 #include "spacing-spanner.hh"
11 #include "paper-column.hh"
12 #include "dimensions.hh"
13 #include "paper-def.hh"
14 #include "warn.hh"
15 #include "paper-score.hh"
16 #include "line-of-score.hh"
17 #include "misc.hh"
19 Spacing_spanner::Spacing_spanner (SCM s)
20 : Spanner (s)
22 set_extent_callback (0, X_AXIS);
23 set_extent_callback (0, Y_AXIS);
28 The algorithm is partly taken from :
30 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
31 OSU-CISRC-10/87-TR35, Department of Computer and Information
32 Science, The Ohio State University, 1987.
34 TOO HAIRY.
36 TODO: write comments
39 Array<Spring>
40 Spacing_spanner::do_measure (Link_array<Paper_column> cols) const
42 Moment shortest;
43 Moment mean_shortest;
44 shortest.set_infinite (1);
46 int n = 0;
47 for (int i =0 ; i < cols.size (); i++)
49 if (cols[i]->musical_b ())
51 SCM st = cols[i]->get_elt_property ("shortest-starter-duration");
52 Moment this_shortest = (*SMOB_TO_TYPE(Moment, st));
53 shortest = shortest <? this_shortest;
54 if (!mean_shortest.infty_b ())
56 n++;
57 mean_shortest += this_shortest;
61 mean_shortest /= n;
63 Array<Spring> meas_springs;
65 Real non_musical_space_strength = paper_l ()->get_var ("breakable_column_space_strength");
66 for (int i= 0; i < cols.size () - 1; i++)
68 Item * l = cols[i];
69 Item * r = cols[i+1];
70 Item * lb = l->find_prebroken_piece (RIGHT);
71 Item * rb = r->find_prebroken_piece (LEFT);
73 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
75 for (int j=0; j < 4; j++)
77 Paper_column * lc = dynamic_cast<Paper_column*> (combinations[j][0]);
78 Paper_column *rc = dynamic_cast<Paper_column*> (combinations[j][1]);
79 if (!lc || !rc)
80 continue;
82 Spring s;
83 s.item_l_drul_[LEFT] = lc;
84 s.item_l_drul_[RIGHT] = rc;
86 SCM hint = lc->get_elt_property ("extra-space");
87 SCM next_hint = rc->get_elt_property ("extra-space");
88 SCM stretch_hint = lc->get_elt_property ("stretch-distance");
89 SCM next_stretch_hint = rc->get_elt_property ("stretch-distance");
91 Real left_distance;
92 if (gh_pair_p (hint))
94 left_distance = gh_scm2double (gh_cdr (hint));
96 // 2nd condition should be (i+1 < col_count()), ie. not the last column in score. FIXME
97 else if (!lc->musical_b() && i+1 < cols.size ())
99 left_distance= default_bar_spacing (lc,rc,shortest);
101 else if (lc->musical_b())
103 left_distance = note_spacing (lc, rc, shortest);
106 s.distance_f_ = left_distance;
109 Only do tight spaces *after* barlines (breakable columns),
110 not before.
112 We want the space before barline to be like the note
113 spacing in the measure.
115 if (lc->breakable_b () || lc->original_l_)
116 s.strength_f_ = non_musical_space_strength;
117 else if (!lc->musical_b ())
118 left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
121 Real right_dist = 0.0;
122 if (gh_pair_p (next_hint))
124 right_dist += - gh_scm2double (gh_car (next_hint));
126 else
128 Interval ext (rc->extent (X_AXIS));
129 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
133 don't want to create too much extra space for accidentals
135 if (lc->musical_b () && rc->musical_b ())
137 if (!to_boolean (rc->get_elt_property ("contains-grace")))
138 right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
141 if (rc->musical_b () && to_boolean (rc->get_elt_property ("contains-grace")))
142 right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
144 s.distance_f_ = left_distance + right_dist;
146 Real stretch_dist = 0.;
147 if (gh_number_p (stretch_hint))
148 stretch_dist += gh_scm2double (stretch_hint);
149 else
150 stretch_dist += left_distance;
152 if (gh_pair_p (next_stretch_hint))
153 // see regtest spacing-tight
154 stretch_dist += - gh_scm2double (gh_car (next_stretch_hint));
155 else
156 stretch_dist += right_dist;
158 if (s.distance_f_ <0)
160 programming_error("Negative dist, setting to 1.0 PT");
161 s.distance_f_ = 1.0;
163 if (stretch_dist == 0.0)
166 \bar "". We give it 0 space, with high strength.
168 s.strength_f_ = 20.0;
170 else
171 s.strength_f_ /= stretch_dist;
173 meas_springs.push (s);
177 return meas_springs;
181 Do something if breakable column has no spacing hints set.
183 Real
184 Spacing_spanner::default_bar_spacing (Paper_column *lc, Paper_column *rc,
185 Moment shortest) const
187 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
188 Real durational_distance = 0;
189 Moment delta_t = rc->when_mom () - lc->when_mom () ;
192 ugh should use shortest_playing distance
194 if (delta_t)
196 durational_distance = get_duration_space (delta_t, shortest);
199 return symbol_distance >? durational_distance;
204 Get the measure wide constant for arithmetic spacing.
206 @see
207 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
208 OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
209 The Ohio State University, 1987.
212 Real
213 Spacing_spanner::get_duration_space (Moment d, Moment shortest) const
215 Real log = log_2 (Moment (1,8) <? shortest);
216 Real k= paper_l ()->get_var ("arithmetic_basicspace")
217 - log;
219 return (log_2 (d) + k) * paper_l ()->get_var ("arithmetic_multiplier");
223 Real
224 Spacing_spanner::note_spacing (Paper_column *lc, Paper_column *rc, Moment shortest) const
226 Moment shortest_playing_len = 0;
227 SCM s = lc->get_elt_property ("shortest-playing-duration");
228 // SCM s = lc->get_elt_property ("mean-playing-duration");
229 if (SMOB_IS_TYPE_B(Moment, s))
230 shortest_playing_len = *SMOB_TO_TYPE (Moment, s);
233 if (! shortest_playing_len)
235 programming_error ("can't find a ruling note at " + lc->when_mom ().str ());
236 shortest_playing_len = 1;
239 if (! shortest)
241 programming_error ("no minimum in measure at " + lc->when_mom ().str ());
242 shortest = 1;
244 Moment delta_t = rc->when_mom () - lc->when_mom ();
245 Real dist = get_duration_space (shortest_playing_len, shortest);
246 dist *= (double)(delta_t / shortest_playing_len);
248 dist += stem_dir_correction (lc,rc);
249 return dist;
254 Correct for optical illusions. See [Wanske] p. 138. The combination
255 up-stem + down-stem should get extra space, the combination
256 down-stem + up-stem less.
258 This should be more advanced, since relative heights of the note
259 heads also influence required correction.
261 Also might not work correctly in case of multi voices or staff
262 changing voices
264 TODO: lookup correction distances? More advanced correction?
265 Possibly turn this off?
267 This routine reads the DIR-LIST property of both its L and R arguments. */
268 Real
269 Spacing_spanner::stem_dir_correction (Paper_column*l, Paper_column*r) const
271 SCM dl = l->get_elt_property ("dir-list");
272 SCM dr = r->get_elt_property ("dir-list");
273 if (dl == SCM_UNDEFINED || dr == SCM_UNDEFINED)
274 return 0.0;
277 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
278 return 0.;
280 dl = gh_car (dl);
281 dr = gh_car (dr);
283 assert (gh_number_p (dl) && gh_number_p(dr));
284 int d1 = gh_scm2int (dl);
285 int d2 = gh_scm2int (dr);
287 if (d1 == d2)
288 return 0.0;
290 bool err = false;
291 Real correction = 0.0;
292 Real ssc = paper_l ()->get_var("stemSpacingCorrection");
295 if (d1 && d2)
297 if (d1 == 1 && d2 == -1)
298 correction = ssc;
299 else if (d1 == -1 && d2 == 1)
300 correction = -ssc;
301 else
302 err = true;
305 else
306 err = true;
308 if (err)
309 programming_error ("Stem directions not set correctly for optical correction");
310 return correction;
314 Array<Spring>
315 Spacing_spanner::get_springs () const
317 Array<Spring> springs;
319 Link_array<Paper_column> all (pscore_l_->line_l_->column_l_arr ()) ;
321 int j = 0;
323 for (int i = 1; i < all.size (); i++)
325 Paper_column* sc = dynamic_cast<Paper_column*> (all[i]);
326 if (sc->breakable_b ())
328 Link_array<Paper_column> measure (all.slice (j, i+1));
329 springs.concat (do_measure (measure));
330 j = i;
335 farewell, cruel world
337 ((Spacing_spanner*)this)->suicide ();
339 return springs;