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 (s.distance_f_ <0)
169 programming_error("negative dist");
171 if (stretch_dist == 0.0)
174 \bar "". We give it 0 space, with high strength.
176 s.strength_f_ = 20.0;
179 s.strength_f_ /= stretch_dist;
181 meas_springs.push (s);
189 Do something if breakable column has no spacing hints set.
192 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc,
193 Moment shortest) const
195 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
196 Real durational_distance = 0;
197 Moment delta_t = rc->when_mom () - lc->when_mom () ;
200 ugh should use shortest_playing distance
204 Real k= paper_l()->arithmetic_constant (shortest);
205 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
208 return symbol_distance >? durational_distance;
213 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
215 Moment shortest_playing_len = lc->shortest_playing_mom_;
216 if (! shortest_playing_len)
218 programming_error ("can't find a ruling note at " + lc->when_mom ().str ());
219 shortest_playing_len = 1;
224 programming_error ("no minimum in measure at " + lc->when_mom ().str ());
227 Moment delta_t = rc->when_mom () - lc->when_mom ();
228 Real k= paper_l()->arithmetic_constant(shortest);
229 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
230 dist *= (double)(delta_t / shortest_playing_len);
232 dist += stem_dir_correction (lc,rc);
238 Correct for optical illusions. See [Wanske] p. 138. The combination
239 up-stem + down-stem should get extra space, the combination
240 down-stem + up-stem less.
242 This should be more advanced, since relative heights of the note
243 heads also influence required correction.
245 Also might not work correctly ico. multi voices or staff changing voices
247 TODO: lookup correction distances? More advanced correction?
248 Possibly turn this off?
250 This routine reads the DIR_LIST property of both its L and R arguments.
253 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
255 SCM dl = l->get_elt_property (dir_list_scm_sym);
256 SCM dr = r->get_elt_property (dir_list_scm_sym);
257 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
263 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
269 assert (gh_number_p (dl) && gh_number_p(dr));
270 int d1 = gh_scm2int (dl);
271 int d2 = gh_scm2int (dr);
277 Real correction = 0.0;
278 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
283 if (d1 == 1 && d2 == -1)
285 else if (d1 == -1 && d2 == 1)
295 programming_error ("Stem directions not set correctly for optical correction");
301 Spacing_spanner::get_springs () const
303 Array<Spring> springs;
305 for (int i=1; i < col_count (); i++)
307 if (scol (i)->breakable_b ())
309 springs.concat (do_measure (last_break, i));