]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
a307e1b1044b5d1d57cda128c23e98d97496db75
[lilypond.git] / lily / spacing-spanner.cc
1 /*   
2   spacing-spanner.cc --  implement Spacing_spanner
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "spacing-spanner.hh"
11 #include "score-column.hh"
12 #include "dimensions.hh"
13 #include "paper-def.hh"
14 #include "warn.hh"
15 #include "paper-score.hh"
16 #include "line-of-score.hh"
17
18 Spacing_spanner::Spacing_spanner ()
19 {
20   set_elt_property (break_helper_only_scm_sym, SCM_BOOL_T);
21   set_elt_property (transparent_scm_sym, SCM_BOOL_T);
22 }
23
24 int
25 Spacing_spanner::col_count () const
26 {
27   return pscore_l_->line_l_->cols_.size ();
28 }
29
30 Score_column *
31 Spacing_spanner::scol (int i)const
32 {
33   return dynamic_cast<Score_column*> (pscore_l_->line_l_->cols_[i]);
34 }
35
36 /*
37   cut 'n paste from spring-spacer.cc
38
39   generate springs between columns.
40
41
42   The algorithm is partly taken from :
43
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.
47   
48  */
49 Array<Spring>
50 Spacing_spanner::do_measure (int col1, int col2) const
51 {
52   for (int i =col1; i < col2; i++)
53     {
54       scol (i)->preprocess ();
55       scol (i)->print ();
56     }
57
58   Moment shortest;
59   shortest.set_infinite (1);
60   for (int i =col1; i < col2; i++)
61     {
62       if (scol(i)->musical_b ())
63         {
64           shortest = shortest <? scol(i)->shortest_starter_mom_;
65         }
66     }
67
68   Array<Spring> meas_springs;
69
70   Real non_musical_space_strength = paper_l ()->get_var ("non_musical_space_strength");
71   for (int i= col1; i < col2; i++)
72     {
73       Item * l = scol(i);
74       Item * r = scol(i+1);
75       Item * lb = l->find_prebroken_piece (RIGHT);
76       Item * rb = r->find_prebroken_piece (LEFT);      
77
78       Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
79
80       for (int i=0; i < 4; i++)
81         {
82           Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
83           Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
84           if (!lc || !rc)
85             continue;
86
87           Spring s;
88           s.item_l_drul_[LEFT] = lc;
89           s.item_l_drul_[RIGHT] = rc;
90           
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);
94             
95           if (hint != SCM_BOOL_F)
96             {
97               hint = SCM_CDDR (hint);
98               
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;
102             }
103           else if (!lc->musical_b() && i+1 < col_count())
104             {
105               s.distance_f_ = default_bar_spacing (lc,rc,shortest);
106             }
107           else if (lc->musical_b())
108             {
109               s.distance_f_ = note_spacing (lc, rc, shortest);
110               
111             }
112           
113           if (next_hint != SCM_BOOL_F)
114             {
115              next_hint = SCM_CADR(next_hint);
116              s.distance_f_ += gh_scm2double (next_hint);
117             }
118           else
119             {
120               Interval ext (rc->extent (X_AXIS));
121               Real correction =  ext.empty_b() ? 0.0 : - ext [LEFT];
122
123               /*
124                 don't want to create too much extra space for accidentals
125                */
126               if (lc->musical_b () && rc->musical_b ())
127                 correction /= 2.0;
128
129               s.distance_f_ += correction;
130             }
131
132           if (s.distance_f_ == 0.0)
133             {
134               /*
135                 \bar "".  We give it 0 space, with high strength. 
136                */
137               s.distance_f_ = 0.0 PT;
138               s.strength_f_ = 20.0; 
139             }
140           else if (stretch_hint != SCM_BOOL_F)
141             {
142               Real hint_sp = gh_scm2double (SCM_CDR (stretch_hint));
143               s.strength_f_ /= hint_sp;
144             }
145           else
146             {
147               s.strength_f_ /= s.distance_f_; 
148             }
149
150           meas_springs.push (s);        
151         }
152     }
153
154   return meas_springs;
155 }
156
157 /**
158    Do something if breakable column has no spacing hints set.
159  */
160 Real
161 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
162 {
163   Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
164   Real durational_distance = 0;
165   Moment delta_t =  rc->when_mom () - lc->when_mom () ;
166
167   /*
168                 ugh should use shortest_playing distance
169   */
170   if (delta_t)
171     {
172       Real k=  paper_l()->arithmetic_constant (shortest);
173       durational_distance =  paper_l()->length_mom_to_dist (delta_t,k);
174     }
175
176   return  symbol_distance >? durational_distance;
177 }
178
179
180 Real
181 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
182 {
183   Moment shortest_playing_len = lc->shortest_playing_mom_;
184   if (! shortest_playing_len)
185     {
186       warning (_f ("can't find a ruling note at %s", 
187                    lc->when_mom ().str ()));
188       shortest_playing_len = 1;
189     }
190   if (! shortest)
191     {
192       warning (_f ("no minimum in measure at %s", 
193                    lc->when_mom ().str ()));
194       shortest = 1;
195     }
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);
200
201   dist += stem_dir_correction (lc,rc);
202   return dist;
203 }
204
205
206 /**
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.
210
211    This should be more advanced, since relative heights of the note
212    heads also influence required correction.
213
214    Also might not work correctly ico. multi voices or staff changing voices
215
216    TODO: lookup correction distances?  More advanced correction?
217    Possibly turn this off?
218
219    This routine reads the DIR_LIST property of both its L and R arguments.
220 */
221 Real
222 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
223 {
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)
227     return 0.0;
228
229   dl = SCM_CDR (dl);
230   dr = SCM_CDR (dr);
231
232   if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
233     return 0.;
234
235   dl = SCM_CAR(dl);
236   dr = SCM_CAR(dr);
237
238   assert (gh_number_p (dl) && gh_number_p(dr));
239   int d1 = gh_scm2int (dl);
240   int d2 = gh_scm2int (dr);
241
242   if (d1 == d2)
243     return 0.0;
244
245   bool err = false;
246   Real correction = 0.0;
247   Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
248
249
250   if (d1 && d2)
251     {
252       if (d1 == 1 && d2 == -1)
253         correction = ssc;
254       else if (d1 == -1 && d2 == 1)
255         correction = -ssc;
256       else
257         err = true;
258     }
259   
260   else
261     err = true;
262
263   if (err)
264     programming_error ("Stem directions not set correctly for optical correction");
265   return correction;
266 }
267   
268
269 Array<Spring>
270 Spacing_spanner::get_springs () const
271 {
272   Array<Spring> springs;
273   int last_break =0;
274   for (int i=1; i < col_count (); i++)
275     {
276       if (scol (i)->breakable_b ())
277         {
278           springs.concat (do_measure (last_break, i));
279           last_break  = i;
280         }
281     }
282   return springs;
283 }
284
285
286
287