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.
50 Spacing_spanner::do_measure (int col1, int col2) const
52 for (int i =col1; i < col2; i++)
54 scol (i)->preprocess ();
59 shortest.set_infinite (1);
60 for (int i =col1; i < col2; i++)
62 if (scol(i)->musical_b ())
64 shortest = shortest <? scol(i)->shortest_starter_mom_;
68 Array<Spring> meas_springs;
70 Real non_musical_space_strength = paper_l ()->get_var ("non_musical_space_strength");
71 for (int i= col1; i < col2; i++)
75 Item * lb = l->find_prebroken_piece (RIGHT);
76 Item * rb = r->find_prebroken_piece (LEFT);
78 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
80 for (int i=0; i < 4; i++)
82 Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
83 Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
88 s.item_l_drul_[LEFT] = lc;
89 s.item_l_drul_[RIGHT] = rc;
91 SCM hint = lc->get_elt_property (extra_space_scm_sym);
92 SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
93 SCM stretch_hint = rc->get_elt_property (stretch_distance_scm_sym);
95 if (hint != SCM_BOOL_F)
97 hint = SCM_CDDR (hint);
99 s.distance_f_ = gh_scm2double (hint);
100 if (!lc->musical_b ())
101 s.strength_f_ = non_musical_space_strength; // fixed after complaints by michael krause 2.0;
103 else if (!lc->musical_b() && i+1 < col_count())
105 s.distance_f_ = default_bar_spacing (lc,rc,shortest);
107 else if (lc->musical_b())
109 s.distance_f_ = note_spacing (lc, rc, shortest);
113 if (next_hint != SCM_BOOL_F)
115 next_hint = SCM_CADR(next_hint);
116 s.distance_f_ += gh_scm2double (next_hint);
120 Interval ext (rc->extent (X_AXIS));
121 Real correction = ext.empty_b() ? 0.0 : - ext [LEFT];
124 don't want to create too much extra space for accidentals
126 if (lc->musical_b () && rc->musical_b ())
129 s.distance_f_ += correction;
132 if (s.distance_f_ == 0.0)
135 \bar "". We give it 0 space, with high strength.
137 s.distance_f_ = 0.0 PT;
138 s.strength_f_ = 20.0;
140 else if (stretch_hint != SCM_BOOL_F)
142 Real hint_sp = gh_scm2double (SCM_CDR (stretch_hint));
143 s.strength_f_ /= hint_sp;
147 s.strength_f_ /= s.distance_f_;
150 meas_springs.push (s);
158 Do something if breakable column has no spacing hints set.
161 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
163 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
164 Real durational_distance = 0;
165 Moment delta_t = rc->when_mom () - lc->when_mom () ;
168 ugh should use shortest_playing distance
172 Real k= paper_l()->arithmetic_constant (shortest);
173 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
176 return symbol_distance >? durational_distance;
181 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
183 Moment shortest_playing_len = lc->shortest_playing_mom_;
184 if (! shortest_playing_len)
186 warning (_f ("can't find a ruling note at %s",
187 lc->when_mom ().str ()));
188 shortest_playing_len = 1;
192 warning (_f ("no minimum in measure at %s",
193 lc->when_mom ().str ()));
196 Moment delta_t = rc->when_mom () - lc->when_mom ();
197 Real k= paper_l()->arithmetic_constant(shortest);
198 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
199 dist *= (double)(delta_t / shortest_playing_len);
201 dist += stem_dir_correction (lc,rc);
207 Correct for optical illusions. See [Wanske] p. 138. The combination
208 up-stem + down-stem should get extra space, the combination
209 down-stem + up-stem less.
211 This should be more advanced, since relative heights of the note
212 heads also influence required correction.
214 Also might not work correctly ico. multi voices or staff changing voices
216 TODO: lookup correction distances? More advanced correction?
217 Possibly turn this off?
219 This routine reads the DIR_LIST property of both its L and R arguments.
222 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
224 SCM dl = l->get_elt_property (dir_list_scm_sym);
225 SCM dr = r->get_elt_property (dir_list_scm_sym);
226 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
232 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
238 assert (gh_number_p (dl) && gh_number_p(dr));
239 int d1 = gh_scm2int (dl);
240 int d2 = gh_scm2int (dr);
246 Real correction = 0.0;
247 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
252 if (d1 == 1 && d2 == -1)
254 else if (d1 == -1 && d2 == 1)
264 programming_error ("Stem directions not set correctly for optical correction");
270 Spacing_spanner::get_springs () const
272 Array<Spring> springs;
274 for (int i=1; i < col_count (); i++)
276 if (scol (i)->breakable_b ())
278 springs.concat (do_measure (last_break, i));