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"
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 for (int i= col1; i < col2; i++)
74 Item * lb = l->find_prebroken_piece (RIGHT);
75 Item * rb = r->find_prebroken_piece (LEFT);
77 Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
79 for (int i=0; i < 4; i++)
81 Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
82 Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
87 s.item_l_drul_[LEFT] = lc;
88 s.item_l_drul_[RIGHT] = rc;
90 SCM hint = lc->get_elt_property (extra_space_scm_sym);
91 SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
93 if (hint != SCM_BOOL_F)
95 hint = SCM_CDDR (hint);
97 s.distance_f_ = gh_scm2double (hint);
98 if (!lc->musical_b ())
101 else if (!lc->musical_b() && i+1 < col_count())
103 s.distance_f_ = default_bar_spacing (lc,rc,shortest);
106 else if (lc->musical_b())
108 s.distance_f_ = note_spacing (lc, rc, shortest);
112 if (next_hint != SCM_BOOL_F)
114 next_hint = SCM_CADR(next_hint);
115 s.distance_f_ += gh_scm2double (next_hint);
119 Interval ext (rc->extent (X_AXIS));
120 Real correction = ext.empty_b() ? 0.0 : - ext [LEFT];
123 don't want to create too much extra space for accidentals
125 if (lc->musical_b () && rc->musical_b ())
128 s.distance_f_ += correction;
131 meas_springs.push (s);
139 Do something if breakable column has no spacing hints set.
142 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
144 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
145 Real durational_distance = 0;
146 Moment delta_t = rc->when_mom () - lc->when_mom () ;
149 ugh should use shortest_playing distance
153 Real k= paper_l()->arithmetic_constant (shortest);
154 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
157 return symbol_distance >? durational_distance;
162 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
164 Moment shortest_playing_len = lc->shortest_playing_mom_;
165 if (! shortest_playing_len)
167 warning (_f ("can't find a ruling note at %s",
168 lc->when_mom ().str ()));
169 shortest_playing_len = 1;
173 warning (_f ("no minimum in measure at %s",
174 lc->when_mom ().str ()));
177 Moment delta_t = rc->when_mom () - lc->when_mom ();
178 Real k= paper_l()->arithmetic_constant(shortest);
179 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
180 dist *= (double)(delta_t / shortest_playing_len);
182 dist += stem_dir_correction (lc,rc);
188 Correct for optical illusions. See [Wanske] p. 138. The combination
189 up-stem + down-stem should get extra space, the combination
190 down-stem + up-stem less.
192 This should be more advanced, since relative heights of the note
193 heads also influence required correction.
195 Also might not work correctly ico. multi voices or staff changing voices
197 TODO: lookup correction distances? More advanced correction?
198 Possibly turn this off?
200 This routine reads the DIR_LIST property of both its L and R arguments.
203 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
205 SCM dl = l->get_elt_property (dir_list_scm_sym);
206 SCM dr = r->get_elt_property (dir_list_scm_sym);
207 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
213 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
219 assert (gh_number_p (dl) && gh_number_p(dr));
220 int d1 = gh_scm2int (dl);
221 int d2 = gh_scm2int (dr);
227 Real correction = 0.0;
228 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
233 if (d1 == 1 && d2 == -1)
235 else if (d1 == -1 && d2 == 1)
245 programming_error ("Stem directions not set correctly for optical correction");
251 Spacing_spanner::get_springs () const
253 Array<Spring> springs;
255 for (int i=1; i < col_count (); i++)
257 if (scol (i)->breakable_b ())
259 springs.concat (do_measure (last_break, i));