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 (break_helper_only_scm_sym, SCM_BOOL_T);
21 set_elt_property (transparent_scm_sym, SCM_BOOL_T);
25 Spacing_spanner::col_count () const
27 return pscore_l_->line_l_->cols_.size ();
31 Spacing_spanner::scol (int i)const
33 return dynamic_cast<Score_column*> (pscore_l_->line_l_->cols_[i]);
37 cut 'n paste from spring-spacer.cc
39 generate springs between columns.
42 The algorithm is partly taken from :
44 John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
45 OSU-CISRC-10/87-TR35, Department of Computer and Information
46 Science, The Ohio State University, 1987.
52 Spacing_spanner::do_measure (int col1, int col2) const
54 for (int i =col1; i < col2; i++)
56 scol (i)->preprocess ();
61 shortest.set_infinite (1);
62 for (int i =col1; i < col2; i++)
64 if (scol(i)->musical_b ())
66 shortest = shortest <? scol(i)->shortest_starter_mom_;
70 Array<Spring> meas_springs;
72 Real non_musical_space_strength = paper_l ()->get_var ("breakable_column_space_strength");
73 for (int i= col1; i < col2; i++)
77 Item * lb = l->find_prebroken_piece (RIGHT);
78 Item * rb = r->find_prebroken_piece (LEFT);
80 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
82 for (int j=0; j < 4; j++)
84 Score_column * lc = dynamic_cast<Score_column*> (combinations[j][0]);
85 Score_column *rc = dynamic_cast<Score_column*> (combinations[j][1]);
90 s.item_l_drul_[LEFT] = lc;
91 s.item_l_drul_[RIGHT] = rc;
93 SCM hint = lc->get_elt_property (extra_space_scm_sym);
94 SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
95 SCM stretch_hint = lc->get_elt_property (stretch_distance_scm_sym);
96 SCM next_stretch_hint = rc->get_elt_property (stretch_distance_scm_sym);
99 if (hint != SCM_BOOL_F)
101 hint = SCM_CDDR (hint);
103 left_distance = gh_scm2double (hint);
105 else if (!lc->musical_b() && i+1 < col_count())
107 left_distance= default_bar_spacing (lc,rc,shortest);
109 else if (lc->musical_b())
111 left_distance = note_spacing (lc, rc, shortest);
114 s.distance_f_ = left_distance;
117 Only do tight spaces *after* barlines (breakable columns),
120 We want the space before barline to be like the note
121 spacing in the measure.
123 if (lc->breakable_b () || lc->original_l_)
124 s.strength_f_ = non_musical_space_strength;
125 else if (!lc->musical_b ())
126 left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
129 Real right_dist = 0.0;
130 if (next_hint != SCM_BOOL_F)
132 next_hint = SCM_CADR(next_hint);
133 right_dist += - gh_scm2double (next_hint);
137 Interval ext (rc->extent (X_AXIS));
138 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
142 don't want to create too much extra space for accidentals
144 if (lc->musical_b () && rc->musical_b ())
146 if (rc->get_elt_property (contains_grace_scm_sym) == SCM_BOOL_F)
147 right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
150 if (rc->musical_b () && rc->get_elt_property (contains_grace_scm_sym) != SCM_BOOL_F)
151 right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
154 s.distance_f_ = left_distance + right_dist;
156 Real stretch_dist = 0.;
157 if (stretch_hint != SCM_BOOL_F)
158 stretch_dist += gh_scm2double (SCM_CDDR (stretch_hint));
160 stretch_dist += left_distance;
162 if (next_stretch_hint != SCM_BOOL_F)
163 // see regtest spacing-tight
164 stretch_dist += - gh_scm2double (SCM_CADR (next_stretch_hint));
166 stretch_dist += right_dist;
168 if (stretch_dist == 0.0)
171 \bar "". We give it 0 space, with high strength.
173 s.strength_f_ = 20.0;
176 s.strength_f_ /= stretch_dist;
178 meas_springs.push (s);
186 Do something if breakable column has no spacing hints set.
189 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc,
190 Moment shortest) const
192 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
193 Real durational_distance = 0;
194 Moment delta_t = rc->when_mom () - lc->when_mom () ;
197 ugh should use shortest_playing distance
201 Real k= paper_l()->arithmetic_constant (shortest);
202 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
205 return symbol_distance >? durational_distance;
210 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
212 Moment shortest_playing_len = lc->shortest_playing_mom_;
213 if (! shortest_playing_len)
215 warning (_f ("can't find a ruling note at %s",
216 lc->when_mom ().str ()));
217 shortest_playing_len = 1;
221 warning (_f ("no minimum in measure at %s",
222 lc->when_mom ().str ()));
225 Moment delta_t = rc->when_mom () - lc->when_mom ();
226 Real k= paper_l()->arithmetic_constant(shortest);
227 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
228 dist *= (double)(delta_t / shortest_playing_len);
230 dist += stem_dir_correction (lc,rc);
236 Correct for optical illusions. See [Wanske] p. 138. The combination
237 up-stem + down-stem should get extra space, the combination
238 down-stem + up-stem less.
240 This should be more advanced, since relative heights of the note
241 heads also influence required correction.
243 Also might not work correctly ico. multi voices or staff changing voices
245 TODO: lookup correction distances? More advanced correction?
246 Possibly turn this off?
248 This routine reads the DIR_LIST property of both its L and R arguments.
251 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
253 SCM dl = l->get_elt_property (dir_list_scm_sym);
254 SCM dr = r->get_elt_property (dir_list_scm_sym);
255 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
261 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
267 assert (gh_number_p (dl) && gh_number_p(dr));
268 int d1 = gh_scm2int (dl);
269 int d2 = gh_scm2int (dr);
275 Real correction = 0.0;
276 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
281 if (d1 == 1 && d2 == -1)
283 else if (d1 == -1 && d2 == 1)
293 programming_error ("Stem directions not set correctly for optical correction");
299 Spacing_spanner::get_springs () const
301 Array<Spring> springs;
303 for (int i=1; i < col_count (); i++)
305 if (scol (i)->breakable_b ())
307 springs.concat (do_measure (last_break, i));