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 ("non_musical_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;
116 Only do tight spaces *after* barlines, not before.
118 We want the space before barline to be like the note
119 spacing in the measure.
121 if (!lc->musical_b ())
122 s.strength_f_ = non_musical_space_strength;
124 Real right_dist = 0.0;
125 if (next_hint != SCM_BOOL_F)
127 next_hint = SCM_CADR(next_hint);
128 right_dist += - gh_scm2double (next_hint);
132 Interval ext (rc->extent (X_AXIS));
133 right_dist = ext.empty_b() ? 0.0 : - ext [LEFT];
137 don't want to create too much extra space for accidentals
139 if (lc->musical_b () && rc->musical_b ())
142 s.distance_f_ = left_distance + right_dist;
144 Real stretch_dist = 0.;
145 if (stretch_hint != SCM_BOOL_F)
146 stretch_dist += gh_scm2double (SCM_CDDR (stretch_hint));
148 stretch_dist += left_distance;
150 if (next_stretch_hint != SCM_BOOL_F)
151 // see regtest spacing-tight
152 stretch_dist += - gh_scm2double (SCM_CADR (next_stretch_hint));
154 stretch_dist += right_dist;
156 if (stretch_dist == 0.0)
159 \bar "". We give it 0 space, with high strength.
161 s.strength_f_ = 20.0;
164 s.strength_f_ /= stretch_dist;
166 meas_springs.push (s);
174 Do something if breakable column has no spacing hints set.
177 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc,
178 Moment shortest) const
180 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
181 Real durational_distance = 0;
182 Moment delta_t = rc->when_mom () - lc->when_mom () ;
185 ugh should use shortest_playing distance
189 Real k= paper_l()->arithmetic_constant (shortest);
190 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
193 return symbol_distance >? durational_distance;
198 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
200 Moment shortest_playing_len = lc->shortest_playing_mom_;
201 if (! shortest_playing_len)
203 warning (_f ("can't find a ruling note at %s",
204 lc->when_mom ().str ()));
205 shortest_playing_len = 1;
209 warning (_f ("no minimum in measure at %s",
210 lc->when_mom ().str ()));
213 Moment delta_t = rc->when_mom () - lc->when_mom ();
214 Real k= paper_l()->arithmetic_constant(shortest);
215 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
216 dist *= (double)(delta_t / shortest_playing_len);
218 dist += stem_dir_correction (lc,rc);
224 Correct for optical illusions. See [Wanske] p. 138. The combination
225 up-stem + down-stem should get extra space, the combination
226 down-stem + up-stem less.
228 This should be more advanced, since relative heights of the note
229 heads also influence required correction.
231 Also might not work correctly ico. multi voices or staff changing voices
233 TODO: lookup correction distances? More advanced correction?
234 Possibly turn this off?
236 This routine reads the DIR_LIST property of both its L and R arguments.
239 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
241 SCM dl = l->get_elt_property (dir_list_scm_sym);
242 SCM dr = r->get_elt_property (dir_list_scm_sym);
243 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
249 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
255 assert (gh_number_p (dl) && gh_number_p(dr));
256 int d1 = gh_scm2int (dl);
257 int d2 = gh_scm2int (dr);
263 Real correction = 0.0;
264 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
269 if (d1 == 1 && d2 == -1)
271 else if (d1 == -1 && d2 == 1)
281 programming_error ("Stem directions not set correctly for optical correction");
287 Spacing_spanner::get_springs () const
289 Array<Spring> springs;
291 for (int i=1; i < col_count (); i++)
293 if (scol (i)->breakable_b ())
295 springs.concat (do_measure (last_break, i));