]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
release: 1.1.52
[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 "p-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   for (int i= col1; i < col2; i++)
71     {
72       Item * l = scol(i);
73       Item * r = scol(i+1);
74       Item * lb = l->find_prebroken_piece (RIGHT);
75       Item * rb = r->find_prebroken_piece (LEFT);      
76
77       Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
78
79       for (int i=0; i < 4; i++)
80         {
81           Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
82           Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
83           if (!lc || !rc)
84             continue;
85
86           Spring s;
87           s.item_l_drul_[LEFT] = lc;
88           s.item_l_drul_[RIGHT] = rc;
89           
90           SCM hint = lc->get_elt_property (extra_space_scm_sym);
91           SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
92         
93           if (hint != SCM_BOOL_F)
94             {
95               hint = SCM_CDDR (hint);
96               
97               s.distance_f_ = gh_scm2double (hint); 
98               if (!lc->musical_b ())
99                 s.strength_f_ = 2.0;
100             }
101           else if (!lc->musical_b() && i+1 < col_count())
102             {
103               s.distance_f_ = default_bar_spacing (lc,rc,shortest);
104               s.strength_f_ = 2.0;
105             }
106           else if (lc->musical_b())
107             {
108               s.distance_f_ = note_spacing (lc, rc, shortest);
109               
110             }
111           
112           if (next_hint != SCM_BOOL_F)
113             {
114              next_hint = SCM_CADR(next_hint);
115              s.distance_f_ += gh_scm2double (next_hint);
116             }
117           else
118             {
119               Interval ext (rc->extent (X_AXIS));
120               Real correction =  ext.empty_b() ? 0.0 : - ext [LEFT];
121
122               /*
123                 don't want to create too much extra space for accidentals
124                */
125               if (lc->musical_b () && rc->musical_b ())
126                 correction /= 2.0;
127
128               s.distance_f_ += correction;
129             }
130           
131           meas_springs.push (s);        
132         }
133     }
134
135   return meas_springs;
136 }
137
138 /**
139    Do something if breakable column has no spacing hints set.
140  */
141 Real
142 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
143 {
144   Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
145   Real durational_distance = 0;
146   Moment delta_t =  rc->when_mom () - lc->when_mom () ;
147
148   /*
149                 ugh should use shortest_playing distance
150   */
151   if (delta_t)
152     {
153       Real k=  paper_l()->arithmetic_constant (shortest);
154       durational_distance =  paper_l()->length_mom_to_dist (delta_t,k);
155     }
156
157   return  symbol_distance >? durational_distance;
158 }
159
160
161 Real
162 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
163 {
164   Moment shortest_playing_len = lc->shortest_playing_mom_;
165   if (! shortest_playing_len)
166     {
167       warning (_f ("can't find a ruling note at %s", 
168                    lc->when_mom ().str ()));
169       shortest_playing_len = 1;
170     }
171   if (! shortest)
172     {
173       warning (_f ("no minimum in measure at %s", 
174                    lc->when_mom ().str ()));
175       shortest = 1;
176     }
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);
181
182   dist += stem_dir_correction (lc,rc);
183   return dist;
184 }
185
186
187 /**
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.
191
192    This should be more advanced, since relative heights of the note
193    heads also influence required correction.
194
195    Also might not work correctly ico. multi voices or staff changing voices
196
197    TODO: lookup correction distances?  More advanced correction?
198    Possibly turn this off?
199
200    This routine reads the DIR_LIST property of both its L and R arguments.
201 */
202 Real
203 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
204 {
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)
208     return 0.0;
209
210   dl = SCM_CDR (dl);
211   dr = SCM_CDR (dr);
212
213   if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
214     return 0.;
215
216   dl = SCM_CAR(dl);
217   dr = SCM_CAR(dr);
218
219   assert (gh_number_p (dl) && gh_number_p(dr));
220   int d1 = gh_scm2int (dl);
221   int d2 = gh_scm2int (dr);
222
223   if (d1 == d2)
224     return 0.0;
225
226   bool err = false;
227   Real correction = 0.0;
228   Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
229
230
231   if (d1 && d2)
232     {
233       if (d1 == 1 && d2 == -1)
234         correction = ssc;
235       else if (d1 == -1 && d2 == 1)
236         correction = -ssc;
237       else
238         err = true;
239     }
240   
241   else
242     err = true;
243
244   if (err)
245     programming_error ("Stem directions not set correctly for optical correction");
246   return correction;
247 }
248   
249
250 Array<Spring>
251 Spacing_spanner::get_springs () const
252 {
253   Array<Spring> springs;
254   int last_break =0;
255   for (int i=1; i < col_count (); i++)
256     {
257       if (scol (i)->breakable_b ())
258         {
259           springs.concat (do_measure (last_break, i));
260           last_break  = i;
261         }
262     }
263   return springs;
264 }
265
266
267
268