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>
10 #include "spacing-spanner.hh"
11 #include "score-column.hh"
12 #include "dimensions.hh"
13 #include "paper-def.hh"
15 #include "paper-score.hh"
16 #include "line-of-score.hh"
18 Spacing_spanner::Spacing_spanner ()
20 set_elt_property ("transparent", SCM_BOOL_T);
24 Spacing_spanner::col_count () const
26 return pscore_l_->line_l_->cols_.size ();
30 Spacing_spanner::scol (int i)const
32 return dynamic_cast<Score_column*> (pscore_l_->line_l_->cols_[i]);
36 cut 'n paste from spring-spacer.cc
38 generate springs between columns.
41 The algorithm is partly taken from :
43 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
44 OSU-CISRC-10/87-TR35, Department of Computer and Information
45 Science, The Ohio State University, 1987.
51 Spacing_spanner::do_measure (int col1, int col2) const
53 for (int i =col1; i < col2; i++)
55 scol (i)->preprocess ();
60 shortest.set_infinite (1);
61 for (int i =col1; i < col2; i++)
63 if (scol(i)->musical_b ())
65 shortest = shortest <? scol(i)->shortest_starter_mom_;
69 Array<Spring> meas_springs;
71 Real non_musical_space_strength = paper_l ()->get_var ("breakable_column_space_strength");
72 for (int i= col1; i < col2; i++)
76 Item * lb = l->find_broken_piece (RIGHT);
77 Item * rb = r->find_broken_piece (LEFT);
79 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
81 for (int j=0; j < 4; j++)
83 Score_column * lc = dynamic_cast<Score_column*> (combinations[j][0]);
84 Score_column *rc = dynamic_cast<Score_column*> (combinations[j][1]);
89 s.item_l_drul_[LEFT] = lc;
90 s.item_l_drul_[RIGHT] = rc;
92 SCM hint = lc->get_elt_property ("extra-space");
93 SCM next_hint = rc->get_elt_property ("extra-space");
94 SCM stretch_hint = lc->get_elt_property ("stretch-distance");
95 SCM next_stretch_hint = rc->get_elt_property ("stretch-distance");
98 if (hint != SCM_UNDEFINED)
100 left_distance = gh_scm2double (gh_cdr (hint));
102 else if (!lc->musical_b() && i+1 < col_count())
104 left_distance= default_bar_spacing (lc,rc,shortest);
106 else if (lc->musical_b())
108 left_distance = note_spacing (lc, rc, shortest);
111 s.distance_f_ = left_distance;
114 Only do tight spaces *after* barlines (breakable columns),
117 We want the space before barline to be like the note
118 spacing in the measure.
120 if (lc->breakable_b () || lc->original_l_)
121 s.strength_f_ = non_musical_space_strength;
122 else if (!lc->musical_b ())
123 left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
126 Real right_dist = 0.0;
127 if (next_hint != SCM_UNDEFINED)
129 right_dist += - gh_scm2double (gh_car (next_hint));
133 Interval ext (rc->extent (X_AXIS));
134 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
138 don't want to create too much extra space for accidentals
140 if (lc->musical_b () && rc->musical_b ())
142 if (rc->get_elt_property ("contains-grace") == SCM_UNDEFINED)
143 right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
146 if (rc->musical_b () && rc->get_elt_property ("contains-grace") != SCM_UNDEFINED)
147 right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
150 s.distance_f_ = left_distance + right_dist;
152 Real stretch_dist = 0.;
153 if (gh_number_p (stretch_hint))
154 stretch_dist += gh_scm2double (stretch_hint);
156 stretch_dist += left_distance;
158 if (next_stretch_hint != SCM_UNDEFINED)
159 // see regtest spacing-tight
160 stretch_dist += - gh_scm2double (SCM_CAR (next_stretch_hint));
162 stretch_dist += right_dist;
164 if (s.distance_f_ <0)
165 programming_error("negative dist");
167 if (stretch_dist == 0.0)
170 \bar "". We give it 0 space, with high strength.
172 s.strength_f_ = 20.0;
175 s.strength_f_ /= stretch_dist;
177 meas_springs.push (s);
185 Do something if breakable column has no spacing hints set.
188 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc,
189 Moment shortest) const
191 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
192 Real durational_distance = 0;
193 Moment delta_t = rc->when_mom () - lc->when_mom () ;
196 ugh should use shortest_playing distance
200 Real k= paper_l()->arithmetic_constant (shortest);
201 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
204 return symbol_distance >? durational_distance;
209 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
211 Moment shortest_playing_len = lc->shortest_playing_mom_;
212 if (! shortest_playing_len)
214 programming_error ("Can't find a ruling note at " + lc->when_mom ().str ());
215 shortest_playing_len = 1;
220 programming_error ("no minimum in measure at " + lc->when_mom ().str ());
223 Moment delta_t = rc->when_mom () - lc->when_mom ();
224 Real k= paper_l()->arithmetic_constant(shortest);
225 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
226 dist *= (double)(delta_t / shortest_playing_len);
228 dist += stem_dir_correction (lc,rc);
234 Correct for optical illusions. See [Wanske] p. 138. The combination
235 up-stem + down-stem should get extra space, the combination
236 down-stem + up-stem less.
238 This should be more advanced, since relative heights of the note
239 heads also influence required correction.
241 Also might not work correctly ico. multi voices or staff changing voices
243 TODO: lookup correction distances? More advanced correction?
244 Possibly turn this off?
246 This routine reads the DIR_LIST property of both its L and R arguments.
249 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
251 SCM dl = l->get_elt_property ("dir-list");
252 SCM dr = r->get_elt_property ("dir-list");
253 if (dl == SCM_UNDEFINED || dr == SCM_UNDEFINED)
257 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
263 assert (gh_number_p (dl) && gh_number_p(dr));
264 int d1 = gh_scm2int (dl);
265 int d2 = gh_scm2int (dr);
271 Real correction = 0.0;
272 Real ssc = paper_l ()->get_var("stemSpacingCorrection");
277 if (d1 == 1 && d2 == -1)
279 else if (d1 == -1 && d2 == 1)
289 programming_error ("Stem directions not set correctly for optical correction");
295 Spacing_spanner::get_springs () const
297 Array<Spring> springs;
299 for (int i=1; i < col_count (); i++)
301 if (scol (i)->breakable_b ())
303 springs.concat (do_measure (last_break, i));