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);
94 if (hint != SCM_BOOL_F)
96 hint = SCM_CDDR (hint);
98 s.distance_f_ = gh_scm2double (hint);
99 if (!lc->musical_b ())
102 else if (!lc->musical_b() && i+1 < col_count())
104 s.distance_f_ = default_bar_spacing (lc,rc,shortest);
105 s.strength_f_ = non_musical_space_strength; // fixed after complaints by michael krause
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)
135 \bar "". We give it 0 space, with high strength.
137 s.distance_f_ = 0.0 PT;
138 s.strength_f_ = 20.0;
140 meas_springs.push (s);
148 Do something if breakable column has no spacing hints set.
151 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
153 Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
154 Real durational_distance = 0;
155 Moment delta_t = rc->when_mom () - lc->when_mom () ;
158 ugh should use shortest_playing distance
162 Real k= paper_l()->arithmetic_constant (shortest);
163 durational_distance = paper_l()->length_mom_to_dist (delta_t,k);
166 return symbol_distance >? durational_distance;
171 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
173 Moment shortest_playing_len = lc->shortest_playing_mom_;
174 if (! shortest_playing_len)
176 warning (_f ("can't find a ruling note at %s",
177 lc->when_mom ().str ()));
178 shortest_playing_len = 1;
182 warning (_f ("no minimum in measure at %s",
183 lc->when_mom ().str ()));
186 Moment delta_t = rc->when_mom () - lc->when_mom ();
187 Real k= paper_l()->arithmetic_constant(shortest);
188 Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
189 dist *= (double)(delta_t / shortest_playing_len);
191 dist += stem_dir_correction (lc,rc);
197 Correct for optical illusions. See [Wanske] p. 138. The combination
198 up-stem + down-stem should get extra space, the combination
199 down-stem + up-stem less.
201 This should be more advanced, since relative heights of the note
202 heads also influence required correction.
204 Also might not work correctly ico. multi voices or staff changing voices
206 TODO: lookup correction distances? More advanced correction?
207 Possibly turn this off?
209 This routine reads the DIR_LIST property of both its L and R arguments.
212 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
214 SCM dl = l->get_elt_property (dir_list_scm_sym);
215 SCM dr = r->get_elt_property (dir_list_scm_sym);
216 if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
222 if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
228 assert (gh_number_p (dl) && gh_number_p(dr));
229 int d1 = gh_scm2int (dl);
230 int d2 = gh_scm2int (dr);
236 Real correction = 0.0;
237 Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
242 if (d1 == 1 && d2 == -1)
244 else if (d1 == -1 && d2 == 1)
254 programming_error ("Stem directions not set correctly for optical correction");
260 Spacing_spanner::get_springs () const
262 Array<Spring> springs;
264 for (int i=1; i < col_count (); i++)
266 if (scol (i)->breakable_b ())
268 springs.concat (do_measure (last_break, i));