lilypond-1.3.28
[lilypond.git] / lily / spacing-spanner.cc
blobe912cf5d3c9900cf0ae8a9f27461471c4205eb84
1 /*
2 spacing-spanner.cc -- implement Spacing_spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 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 ()
21 set_empty (X_AXIS);
22 set_empty (Y_AXIS);
23 set_elt_property ("transparent", SCM_BOOL_T);
27 cut 'n paste from spring-spacer.cc
29 generate springs between columns.
32 The algorithm is partly taken from :
34 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
35 OSU-CISRC-10/87-TR35, Department of Computer and Information
36 Science, The Ohio State University, 1987.
38 TOO HAIRY.
41 Array<Spring>
42 Spacing_spanner::do_measure (Link_array<Paper_column> cols) const
44 Moment shortest;
45 Moment mean_shortest;
46 shortest.set_infinite (1);
48 int n = 0;
49 for (int i =0 ; i < cols.size (); i++)
51 if (cols[i]->musical_b ())
53 SCM st = cols[i]->get_elt_property ("shortest-starter-duration");
54 Moment this_shortest = (*SMOB_TO_TYPE(Moment, st));
55 shortest = shortest <? this_shortest;
56 if (!mean_shortest.infty_b ())
58 n++;
59 mean_shortest += this_shortest;
63 mean_shortest /= n;
65 Array<Spring> meas_springs;
67 Real non_musical_space_strength = paper_l ()->get_var ("breakable_column_space_strength");
68 for (int i= 0; i < cols.size () - 1; i++)
70 Item * l = cols[i];
71 Item * r = cols[i+1];
72 Item * lb = l->find_broken_piece (RIGHT);
73 Item * rb = r->find_broken_piece (LEFT);
75 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
77 for (int j=0; j < 4; j++)
79 Paper_column * lc = dynamic_cast<Paper_column*> (combinations[j][0]);
80 Paper_column *rc = dynamic_cast<Paper_column*> (combinations[j][1]);
81 if (!lc || !rc)
82 continue;
84 Spring s;
85 s.item_l_drul_[LEFT] = lc;
86 s.item_l_drul_[RIGHT] = rc;
88 SCM hint = lc->get_elt_property ("extra-space");
89 SCM next_hint = rc->get_elt_property ("extra-space");
90 SCM stretch_hint = lc->get_elt_property ("stretch-distance");
91 SCM next_stretch_hint = rc->get_elt_property ("stretch-distance");
93 Real left_distance;
94 if (gh_pair_p (hint))
96 left_distance = gh_scm2double (gh_cdr (hint));
98 // 2nd condition should be (i+1 < col_count()), ie. not the last column in score. FIXME
99 else if (!lc->musical_b() && i+1 < cols.size ())
101 left_distance= default_bar_spacing (lc,rc,shortest);
103 else if (lc->musical_b())
105 left_distance = note_spacing (lc, rc, shortest);
108 s.distance_f_ = left_distance;
111 Only do tight spaces *after* barlines (breakable columns),
112 not before.
114 We want the space before barline to be like the note
115 spacing in the measure.
117 if (lc->breakable_b () || lc->original_l_)
118 s.strength_f_ = non_musical_space_strength;
119 else if (!lc->musical_b ())
120 left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
123 Real right_dist = 0.0;
124 if (gh_pair_p (next_hint))
126 right_dist += - gh_scm2double (gh_car (next_hint));
128 else
130 Interval ext (rc->extent (X_AXIS));
131 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
135 don't want to create too much extra space for accidentals
137 if (lc->musical_b () && rc->musical_b ())
139 if (!to_boolean (rc->get_elt_property ("contains-grace")))
140 right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
143 if (rc->musical_b () && to_boolean (rc->get_elt_property ("contains-grace")))
144 right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
147 s.distance_f_ = left_distance + right_dist;
149 Real stretch_dist = 0.;
150 if (gh_number_p (stretch_hint))
151 stretch_dist += gh_scm2double (stretch_hint);
152 else
153 stretch_dist += left_distance;
155 if (gh_pair_p (next_stretch_hint))
156 // see regtest spacing-tight
157 stretch_dist += - gh_scm2double (gh_car (next_stretch_hint));
158 else
159 stretch_dist += right_dist;
161 if (s.distance_f_ <0)
162 programming_error("negative dist");
164 if (stretch_dist == 0.0)
167 \bar "". We give it 0 space, with high strength.
169 s.strength_f_ = 20.0;
171 else
172 s.strength_f_ /= stretch_dist;
174 meas_springs.push (s);
178 return meas_springs;
182 Do something if breakable column has no spacing hints set.
184 Real
185 Spacing_spanner::default_bar_spacing (Paper_column *lc, Paper_column *rc,
186 Moment shortest) const
188 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
189 Real durational_distance = 0;
190 Moment delta_t = rc->when_mom () - lc->when_mom () ;
193 ugh should use shortest_playing distance
195 if (delta_t)
197 durational_distance = get_duration_space (delta_t, shortest);
200 return symbol_distance >? durational_distance;
205 Get the measure wide constant for arithmetic spacing.
207 @see
208 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
209 OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
210 The Ohio State University, 1987.
213 Real
214 Spacing_spanner::get_duration_space (Moment d, Moment shortest) const
216 Real log = log_2 (Moment (1,8) <? shortest);
217 Real k= paper_l ()->get_var ("arithmetic_basicspace")
218 - log;
220 return (log_2 (d) + k) * paper_l ()->get_var ("arithmetic_multiplier");
224 Real
225 Spacing_spanner::note_spacing (Paper_column *lc, Paper_column *rc, Moment shortest) const
227 Moment shortest_playing_len = 0;
228 SCM s = lc->get_elt_property ("shortest-playing-duration");
229 // SCM s = lc->get_elt_property ("mean-playing-duration");
230 if (SMOB_IS_TYPE_B(Moment, s))
231 shortest_playing_len = *SMOB_TO_TYPE (Moment, s);
234 if (! shortest_playing_len)
236 programming_error ("Can't find a ruling note at " + lc->when_mom ().str ());
237 shortest_playing_len = 1;
240 if (! shortest)
242 programming_error ("no minimum in measure at " + lc->when_mom ().str ());
243 shortest = 1;
245 Moment delta_t = rc->when_mom () - lc->when_mom ();
246 Real dist = get_duration_space (shortest_playing_len, shortest);
247 dist *= (double)(delta_t / shortest_playing_len);
249 dist += stem_dir_correction (lc,rc);
250 return dist;
255 Correct for optical illusions. See [Wanske] p. 138. The combination
256 up-stem + down-stem should get extra space, the combination
257 down-stem + up-stem less.
259 This should be more advanced, since relative heights of the note
260 heads also influence required correction.
262 Also might not work correctly ico. multi voices or staff 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.
269 Real
270 Spacing_spanner::stem_dir_correction (Paper_column*l, Paper_column*r) const
272 SCM dl = l->get_elt_property ("dir-list");
273 SCM dr = r->get_elt_property ("dir-list");
274 if (dl == SCM_UNDEFINED || dr == SCM_UNDEFINED)
275 return 0.0;
278 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
279 return 0.;
281 dl = gh_car (dl);
282 dr = gh_car (dr);
284 assert (gh_number_p (dl) && gh_number_p(dr));
285 int d1 = gh_scm2int (dl);
286 int d2 = gh_scm2int (dr);
288 if (d1 == d2)
289 return 0.0;
291 bool err = false;
292 Real correction = 0.0;
293 Real ssc = paper_l ()->get_var("stemSpacingCorrection");
296 if (d1 && d2)
298 if (d1 == 1 && d2 == -1)
299 correction = ssc;
300 else if (d1 == -1 && d2 == 1)
301 correction = -ssc;
302 else
303 err = true;
306 else
307 err = true;
309 if (err)
310 programming_error ("Stem directions not set correctly for optical correction");
311 return correction;
315 Array<Spring>
316 Spacing_spanner::get_springs () const
318 Array<Spring> springs;
320 SCM last_col = pscore_l_->line_l_->get_elt_property ("columns");
321 Link_array<Paper_column> measure;
322 for (SCM s = last_col; gh_pair_p (s); s = gh_cdr (s))
324 Score_element * elt = unsmob_element (gh_car (s));
325 Paper_column* sc = dynamic_cast<Paper_column*> (elt);
326 measure.push (sc);
327 if (sc->breakable_b ())
329 measure.reverse ();
330 springs.concat (do_measure (measure));
331 measure.clear ();
332 measure.push (sc);
335 return springs;