]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam.cc
release: 0.1.13
[lilypond.git] / lily / beam.cc
1 /*
2   beam.cc -- implement Beam
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
7
8   TODO
9
10   Less hairy code.  knee: ([\stem 1; c8 \stem -1; c8]
11   
12 */
13
14 #include <math.h>
15
16 #include "p-col.hh"
17 #include "varray.hh"
18 #include "proto.hh"
19 #include "dimen.hh"
20 #include "beam.hh"
21 #include "misc.hh"
22 #include "debug.hh"
23 #include "symbol.hh"
24 #include "molecule.hh"
25 #include "leastsquares.hh"
26 #include "stem.hh"
27 #include "paper-def.hh"
28 #include "lookup.hh"
29 #include "grouping.hh"
30 #include "stem-info.hh"
31
32
33 IMPLEMENT_IS_TYPE_B1(Beam, Spanner);
34
35 Beam::Beam()
36 {
37   slope = 0;
38   left_pos = 0.0;
39 }
40
41 void
42 Beam::add (Stem*s)
43 {
44   stems.push (s);
45   s->add_dependency (this);
46   s->beam_l_ = this;
47
48   if (!spanned_drul_[LEFT])
49     set_bounds(LEFT,s);
50   else
51     set_bounds(RIGHT,s);
52 }
53
54 Molecule*
55 Beam::brew_molecule_p() const 
56 {
57   Molecule *mol_p = new Molecule;
58   // huh? inter-what
59   //    Real inter_f = paper()->interbeam_f ();
60   Real inter_f = paper()->internote_f ();
61   Real x0 = stems[0]->hpos_f();
62   for (int j=0; j <stems.size(); j++) 
63     {
64       Stem *i = stems[j];
65       Stem * prev = (j > 0)? stems[j-1] : 0;
66       Stem * next = (j < stems.size()-1) ? stems[j+1] :0;
67
68       Molecule sb = stem_beams (i, next, prev);
69       Real  x = i->hpos_f()-x0;
70       sb.translate (Offset (x, (x * slope  + left_pos)* inter_f));
71       mol_p->add (sb);
72     }
73   mol_p->translate (x0 - spanned_drul_[LEFT]->absolute_coordinate(X_AXIS), X_AXIS);
74   return mol_p;
75 }
76
77 Offset
78 Beam::center() const
79 {
80   Real w=(paper()->note_width () + width ().length ())/2.0;
81   return Offset (w, (left_pos + w* slope)*paper()->internote_f ());
82 }
83
84 void
85 Beam::do_pre_processing()
86 {
87   if (!dir_)
88     set_default_dir();
89 }
90
91 void
92 Beam::do_print() const
93 {
94 #ifndef NPRINT
95   DOUT << "slope " <<slope << "left ypos " << left_pos;
96   Spanner::do_print();
97 #endif
98 }
99
100 void
101 Beam::do_post_processing()
102 {
103   if (stems.size() < 2) 
104     {
105       warning ("Beam with less than 2 stems");
106       transparent_b_ = true;
107       return ;
108     }
109   solve_slope();    
110   set_stemlens();
111 }
112
113 void
114 Beam::do_substitute_dependent (Score_elem*o,Score_elem*n)
115 {
116   if (o->is_type_b (Stem::static_name())) 
117       stems.substitute ((Stem*)o->item(),  n?(Stem*) n->item ():0);
118 }
119
120 Interval
121 Beam::do_width() const
122 {
123   return Interval (stems[0]->hpos_f(),
124                    stems.top()->hpos_f ());
125 }
126
127 void
128 Beam::set_default_dir()
129 {
130   int up = 0, down = 0;
131   int up_count = 0, down_count = 0;
132
133   for (int i=0; i <stems.size(); i++) 
134     {
135       Stem *sl = stems[i];
136       int cur_down = sl->get_center_distance_from_top();
137       int cur_up = sl->get_center_distance_from_bottom();
138       if (cur_down) 
139         {
140           down += cur_down;
141           down_count++;
142         }
143       if (cur_up) 
144         {
145           up += cur_up;
146           up_count++;
147         }
148     }
149   if (!down)
150     down_count = 1;
151   if (!up)
152     up_count = 1;
153
154   // the following relation is equal to
155   //        up / up_count > down / down_count
156   dir_ = (up * down_count > down * up_count) ? UP : DOWN;
157
158   for (int i=0; i <stems.size(); i++) 
159     {
160       Stem *sl = stems[i];
161       sl->dir_ = dir_;
162     }
163 }
164
165 /*
166   should use minimum energy formulation (cf linespacing)
167
168   [todo]
169   the y of the (start) of the beam should be quantisized,
170   so that no stafflines appear just in between two beam-flags
171
172 */
173 void
174 Beam::solve_slope()
175 {
176   Array<Stem_info> sinfo;
177   for (int j=0; j <stems.size(); j++) 
178     {
179       Stem *i = stems[j];
180
181       i->set_default_extents();
182       if (i->invisible_b())
183         continue;
184         
185       Stem_info info (i);
186       sinfo.push (info);
187     }
188   if (! sinfo.size())
189     slope = left_pos = 0;
190   else if (sinfo.size() == 1) 
191     {
192       slope = 0;
193       left_pos = sinfo[0].idealy_f_;
194     }
195   else 
196     {
197         
198       Real leftx = sinfo[0].x;
199       Least_squares l;
200       for (int i=0; i < sinfo.size(); i++) 
201         {
202           sinfo[i].x -= leftx;
203           l.input.push (Offset (sinfo[i].x, sinfo[i].idealy_f_));
204         }
205
206       l.minimise (slope, left_pos);
207     }
208   
209   Real dy = 0.0;
210   for (int i=0; i < sinfo.size(); i++) 
211     {
212       Real y = sinfo[i].x * slope + left_pos;
213       Real my = sinfo[i].miny_f_;
214
215       if (my - y > dy)
216         dy = my -y;     
217     }
218   left_pos += dy;
219   left_pos *= dir_;    
220
221   slope *= dir_;
222
223   /*
224     This neat trick is by Werner Lemberg, damped = tanh (slope) corresponds
225     with some tables in [Wanske]
226     */
227   slope = 0.6 * tanh (slope);  
228
229   // ugh
230   Real sl = slope*paper()->internote_f ();
231   paper()->lookup_l ()->beam (sl, 20 PT);
232   slope = sl /paper()->internote_f ();
233 }
234
235 void
236 Beam::set_stemlens()
237 {
238   Real x0 = stems[0]->hpos_f();    
239   for (int j=0; j <stems.size(); j++) 
240     {
241       Stem *s = stems[j];
242
243       Real x =  s->hpos_f()-x0;
244       s->set_stemend (left_pos + slope * x);    
245     }
246 }
247
248 void
249 Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur)
250 {
251   def.OK();
252   cur.OK();
253   assert (cur.children.size() == stems.size ());
254   
255   cur.split (def);
256
257   Array<int> b;
258   {
259     Array<int> flags;
260     for (int j=0; j <stems.size(); j++) 
261       {
262         Stem *s = stems[j];
263
264         int f = intlog2(abs (s->flag_i_))-2;
265         assert (f>0);
266         flags.push (f);
267       }
268     int fi =0;
269     b= cur.generate_beams (flags, fi);
270     b.insert (0,0);
271     b.push (0);
272     assert (stems.size() == b.size ()/2);
273   }
274
275   for (int j=0, i=0; i < b.size() && j <stems.size (); i+= 2, j++) 
276     {
277       Stem *s = stems[j];
278       s->beams_left_i_ = b[i];
279       s->beams_right_i_ = b[i+1];
280     }
281 }
282
283 /*
284   beams to go with one stem.
285   */
286 Molecule
287 Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const
288 {
289   assert (!next || next->hpos_f() > here->hpos_f ());
290   assert (!prev || prev->hpos_f() < here->hpos_f ());
291   //    Real dy=paper()->internote_f ()*2;
292   Real dy = paper()->interbeam_f ();
293   Real stemdx = paper()->rule_thickness ();
294   Real sl = slope*paper()->internote_f ();
295   paper()->lookup_l ()->beam (sl, 20 PT);
296
297   Molecule leftbeams;
298   Molecule rightbeams;
299
300   /* half beams extending to the left. */
301   if (prev) 
302     {
303       int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
304       int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
305       Real w = (here->hpos_f() - prev->hpos_f ())/4;
306       Symbol dummy;
307       Atom a (dummy);
308       if (lhalfs)               // generates warnings if not
309         a =  paper()->lookup_l ()->beam (sl, w);
310       a.translate (Offset (-w, -w * sl));
311       for (int j = 0; j  < lhalfs; j++) 
312         {
313           Atom b (a);
314           b.translate (-dir_ * dy * (lwholebeams+j), Y_AXIS);
315           leftbeams.add (b);
316         }
317     }
318         
319   if (next)
320     {
321       int rhalfs = here->beams_right_i_ - next->beams_left_i_;
322       int rwholebeams = here->beams_right_i_ <? next->beams_left_i_; 
323
324       Real w = next->hpos_f() - here->hpos_f ();
325       Atom a = paper()->lookup_l ()->beam (sl, w + stemdx);
326         
327       int j = 0;
328       for (; j  < rwholebeams; j++) 
329         {
330           Atom b (a);
331           b.translate (-dir_ * dy * j, Y_AXIS);
332           rightbeams.add (b); 
333         }
334
335       w /= 4;
336       if (rhalfs)
337         a = paper()->lookup_l ()->beam (sl, w);
338         
339       for (; j  < rwholebeams + rhalfs; j++) 
340         {
341           Atom b (a);
342           b.translate (-dir_ * dy * j, Y_AXIS);
343           rightbeams.add (b); 
344         }
345         
346     }
347   leftbeams.add (rightbeams);
348   return leftbeams;
349 }