2 beam.cc -- implement Beam
4 source file of the GNU LilyPond music typesetter
6 (c) 1997 Han-Wen Nienhuys <hanwen@stack.nl>
10 Less hairy code. knee: ([\stem 1; c8 \stem -1; c8]
24 #include "molecule.hh"
25 #include "leastsquares.hh"
27 #include "paper-def.hh"
29 #include "grouping.hh"
41 Stem_info (Stem const *);
44 Stem_info::Stem_info (Stem const *s)
48 beams_i_ = intlog2(s->flag_i_) - 2;
56 miny_f_ = interline + #beams * interbeam
57 ideal8 = 2 * interline + interbeam
58 ideal16,32,64,128 = 1.5 * interline + #beams * interbeam
61 miny_f_ = interline + #beams * interbeam
62 ideal8,16 = 2 interline + #beams * interbeam
63 ideal32,64,128 = 1.5 interline + #beams * interbeam
67 Real notehead_y = s->paper()->interline_f ();
68 // huh? why do i need the / 2
69 // Real interbeam_f = s->paper()->interbeam_f ();
70 Real interbeam_f = s->paper()->interbeam_f () / 2;
73 idealy_f_ = dir_ * s->stem_start_f() + beams_i_ * interbeam_f;
75 idealy_f_ += 2 * interline_f;
77 idealy_f_ += 1.5 * interline_f;
80 idealy_f_ = dir_ * s->stem_end_f();
82 miny_f_ = dir_ * s->stem_start_f() + notehead_y + beams_i_ * interbeam_f;
84 idealy_f_ = miny_f_ >? idealy_f_;
85 // assert (miny_f_ <= idealy_f_);
95 Real w=(paper()->note_width () + width ().length ())/2.0;
96 return Offset (w, (left_pos + w* slope)*paper()->internote_f ());
110 s->add_dependency (this);
111 s->print_flag_b_ = false;
113 if (!spanned_drul_[LEFT])
119 Beam::set_default_dir()
121 int up = 0, down = 0;
122 int up_count = 0, down_count = 0;
124 for (int i=0; i <stems.size(); i++)
127 int cur_down = sl->get_center_distance_from_top();
128 int cur_up = sl->get_center_distance_from_bottom();
145 // the following relation is equal to
146 // up / up_count > down / down_count
147 dir_ = (up * down_count > down * up_count) ? UP : DOWN;
149 for (int i=0; i <stems.size(); i++)
157 should use minimum energy formulation (cf linespacing)
160 the y of the (start) of the beam should be quantisized,
161 so that no stafflines appear just in between two beam-flags
167 Array<Stem_info> sinfo;
168 for (int j=0; j <stems.size(); j++)
172 i->set_default_extents();
173 if (i->invisible_b())
180 slope = left_pos = 0;
181 else if (sinfo.size() == 1)
184 left_pos = sinfo[0].idealy_f_;
189 Real leftx = sinfo[0].x;
191 for (int i=0; i < sinfo.size(); i++)
194 l.input.push (Offset (sinfo[i].x, sinfo[i].idealy_f_));
197 l.minimise (slope, left_pos);
201 for (int i=0; i < sinfo.size(); i++)
203 Real y = sinfo[i].x * slope + left_pos;
204 Real my = sinfo[i].miny_f_;
215 This neat trick is by Werner Lemberg, damped = tanh (slope) corresponds
216 with some tables in [Wanske]
218 slope = 0.6 * tanh (slope);
221 Real sl = slope*paper()->internote_f ();
222 paper()->lookup_l ()->beam (sl, 20 PT);
223 slope = sl /paper()->internote_f ();
229 Real x0 = stems[0]->hpos_f();
230 for (int j=0; j <stems.size(); j++)
234 Real x = s->hpos_f()-x0;
235 s->set_stemend (left_pos + slope * x);
241 Beam::do_post_processing()
243 if (stems.size() < 2)
245 warning ("Beam with less than 2 stems");
246 transparent_b_ = true;
254 Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur)
258 assert (cur.children.size() == stems.size ());
265 for (int j=0; j <stems.size(); j++)
269 int f = intlog2(abs (s->flag_i_))-2;
274 b= cur.generate_beams (flags, fi);
277 assert (stems.size() == b.size ()/2);
280 for (int j=0, i=0; i < b.size() && j <stems.size (); i+= 2, j++)
283 s->beams_left_i_ = b[i];
284 s->beams_right_i_ = b[i+1];
289 Beam::do_pre_processing()
298 Beam::do_width() const
300 return Interval (stems[0]->hpos_f(),
301 stems.top()->hpos_f ());
305 beams to go with one stem.
308 Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const
310 assert (!next || next->hpos_f() > here->hpos_f ());
311 assert (!prev || prev->hpos_f() < here->hpos_f ());
312 // Real dy=paper()->internote_f ()*2;
313 Real dy = paper()->interbeam_f ();
314 Real stemdx = paper()->rule_thickness ();
315 Real sl = slope*paper()->internote_f ();
316 paper()->lookup_l ()->beam (sl, 20 PT);
321 /* half beams extending to the left. */
324 int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
325 int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
326 Real w = (here->hpos_f() - prev->hpos_f ())/4;
329 if (lhalfs) // generates warnings if not
330 a = paper()->lookup_l ()->beam (sl, w);
331 a.translate (Offset (-w, -w * sl));
332 for (int j = 0; j < lhalfs; j++)
335 b.translate (-dir_ * dy * (lwholebeams+j), Y_AXIS);
342 int rhalfs = here->beams_right_i_ - next->beams_left_i_;
343 int rwholebeams = here->beams_right_i_ <? next->beams_left_i_;
345 Real w = next->hpos_f() - here->hpos_f ();
346 Atom a = paper()->lookup_l ()->beam (sl, w + stemdx);
349 for (; j < rwholebeams; j++)
352 b.translate (-dir_ * dy * j, Y_AXIS);
358 a = paper()->lookup_l ()->beam (sl, w);
360 for (; j < rwholebeams + rhalfs; j++)
363 b.translate (-dir_ * dy * j, Y_AXIS);
368 leftbeams.add (rightbeams);
374 Beam::brew_molecule_p() const
377 Molecule *mol_p = new Molecule;
379 // Real inter_f = paper()->interbeam_f ();
380 Real inter_f = paper()->internote_f ();
381 Real x0 = stems[0]->hpos_f();
382 for (int j=0; j <stems.size(); j++)
385 Stem * prev = (j > 0)? stems[j-1] : 0;
386 Stem * next = (j < stems.size()-1) ? stems[j+1] :0;
388 Molecule sb = stem_beams (i, next, prev);
389 Real x = i->hpos_f()-x0;
390 sb.translate (Offset (x, (x * slope + left_pos)* inter_f));
393 mol_p->translate (x0 - spanned_drul_[LEFT]->absolute_coordinate(X_AXIS), X_AXIS);
398 IMPLEMENT_IS_TYPE_B1(Beam, Spanner);
401 Beam::do_print() const
404 DOUT << "slope " <<slope << "left ypos " << left_pos;
410 Beam::do_substitute_dependent (Score_elem*o,Score_elem*n)
412 if (o->is_type_b (Stem::static_name()))
414 stems.substitute ((Stem*)o->item(), n?(Stem*) n->item ():0);