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