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_sym, 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_scm_sym);
93 SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
94 SCM stretch_hint = lc->get_elt_property (stretch_distance_scm_sym);
95 SCM next_stretch_hint = rc->get_elt_property (stretch_distance_scm_sym);
98 if (hint != SCM_BOOL_F)
100 hint = SCM_CDDR (hint);
102 left_distance = gh_scm2double (hint);
104 else if (!lc->musical_b() && i+1 < col_count())
106 left_distance= default_bar_spacing (lc,rc,shortest);
108 else if (lc->musical_b())
110 left_distance = note_spacing (lc, rc, shortest);
113 s.distance_f_ = left_distance;
116 Only do tight spaces *after* barlines (breakable columns),
119 We want the space before barline to be like the note
120 spacing in the measure.
122 if (lc->breakable_b () || lc->original_l_)
123 s.strength_f_ = non_musical_space_strength;
124 else if (!lc->musical_b ())
125 left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
128 Real right_dist = 0.0;
129 if (next_hint != SCM_BOOL_F)
131 next_hint = SCM_CADR(next_hint);
132 right_dist += - gh_scm2double (next_hint);
136 Interval ext (rc->extent (X_AXIS));
137 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
141 don't want to create too much extra space for accidentals
143 if (lc->musical_b () && rc->musical_b ())
145 if (rc->get_elt_property (contains_grace_scm_sym) == SCM_BOOL_F)
146 right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
149 if (rc->musical_b () && rc->get_elt_property (contains_grace_scm_sym) != SCM_BOOL_F)
150 right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
153 s.distance_f_ = left_distance + right_dist;
155 Real stretch_dist = 0.;
156 if (stretch_hint != SCM_BOOL_F)
157 stretch_dist += gh_scm2double (SCM_CDDR (stretch_hint));
159 stretch_dist += left_distance;
161 if (next_stretch_hint != SCM_BOOL_F)
162 // see regtest spacing-tight
163 stretch_dist += - gh_scm2double (SCM_CADR (next_stretch_hint));
165 stretch_dist += right_dist;
167 if (s.distance_f_ <0)
168 programming_error("negative dist");
170 if (stretch_dist == 0.0)
173 \bar "". We give it 0 space, with high strength.
175 s.strength_f_ = 20.0;
178 s.strength_f_ /= stretch_dist;
180 meas_springs.push (s);
188 Do something if breakable column has no spacing hints set.
191 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc,
192 Moment shortest) const
194 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
195 Real durational_distance = 0;
196 Moment delta_t = rc->when_mom () - lc->when_mom () ;
199 ugh should use shortest_playing distance
203 Real k= paper_l()->arithmetic_constant (shortest);
204 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
207 return symbol_distance >? durational_distance;
212 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
214 Moment shortest_playing_len = lc->shortest_playing_mom_;
215 if (! shortest_playing_len)
217 programming_error ("Can't find a ruling note at " + lc->when_mom ().str ());
218 shortest_playing_len = 1;
223 programming_error ("no minimum in measure at " + lc->when_mom ().str ());
226 Moment delta_t = rc->when_mom () - lc->when_mom ();
227 Real k= paper_l()->arithmetic_constant(shortest);
228 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
229 dist *= (double)(delta_t / shortest_playing_len);
231 dist += stem_dir_correction (lc,rc);
237 Correct for optical illusions. See [Wanske] p. 138. The combination
238 up-stem + down-stem should get extra space, the combination
239 down-stem + up-stem less.
241 This should be more advanced, since relative heights of the note
242 heads also influence required correction.
244 Also might not work correctly ico. multi voices or staff changing voices
246 TODO: lookup correction distances? More advanced correction?
247 Possibly turn this off?
249 This routine reads the DIR_LIST property of both its L and R arguments.
252 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
254 SCM dl = l->get_elt_property (dir_list_scm_sym);
255 SCM dr = r->get_elt_property (dir_list_scm_sym);
256 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
262 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
268 assert (gh_number_p (dl) && gh_number_p(dr));
269 int d1 = gh_scm2int (dl);
270 int d2 = gh_scm2int (dr);
276 Real correction = 0.0;
277 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
282 if (d1 == 1 && d2 == -1)
284 else if (d1 == -1 && d2 == 1)
294 programming_error ("Stem directions not set correctly for optical correction");
300 Spacing_spanner::get_springs () const
302 Array<Spring> springs;
304 for (int i=1; i < col_count (); i++)
306 if (scol (i)->breakable_b ())
308 springs.concat (do_measure (last_break, i));