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_i_ * 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_i_ * s->stem_end_f();
82 miny_f_ = dir_i_ * 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;
115 Beam::set_default_dir()
117 int up = 0, down = 0;
118 int up_count = 0, down_count = 0;
120 for (int i=0; i <stems.size(); i++)
123 int cur_down = sl->get_center_distance_from_top();
124 int cur_up = sl->get_center_distance_from_bottom();
141 // the following relation is equal to
142 // up / up_count > down / down_count
143 dir_i_ = (up * down_count > down * up_count) ? 1 : -1;
145 for (int i=0; i <stems.size(); i++)
153 should use minimum energy formulation (cf linespacing)
156 the y of the (start) of the beam should be quantisized,
157 so that no stafflines appear just in between two beam-flags
163 Array<Stem_info> sinfo;
164 for (int j=0; j <stems.size(); j++)
168 i->set_default_extents();
169 if (i->invisible_b())
176 slope = left_pos = 0;
177 else if (sinfo.size() == 1)
180 left_pos = sinfo[0].idealy_f_;
185 Real leftx = sinfo[0].x;
187 for (int i=0; i < sinfo.size(); i++)
190 l.input.push (Offset (sinfo[i].x, sinfo[i].idealy_f_));
193 l.minimise (slope, left_pos);
197 for (int i=0; i < sinfo.size(); i++)
199 Real y = sinfo[i].x * slope + left_pos;
200 Real my = sinfo[i].miny_f_;
211 This neat trick is by Werner Lemberg, damped = tanh (slope) corresponds
212 with some tables in [Wanske]
214 slope = 0.6 * tanh (slope);
217 Real sl = slope*paper()->internote_f ();
218 paper()->lookup_l ()->beam (sl, 20 PT);
219 slope = sl /paper()->internote_f ();
225 Real x0 = stems[0]->hpos_f();
226 for (int j=0; j <stems.size(); j++)
230 Real x = s->hpos_f()-x0;
231 s->set_stemend (left_pos + slope * x);
237 Beam::do_post_processing()
239 if ( stems.size() < 2)
241 warning ("Beam with less than 2 stems");
242 transparent_b_ = true;
250 Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur)
254 assert (cur.children.size() == stems.size ());
261 for (int j=0; j <stems.size(); j++)
265 int f = intlog2(abs (s->flag_i_))-2;
270 b= cur.generate_beams (flags, fi);
273 assert (stems.size() == b.size ()/2);
276 for (int j=0, i=0; i < b.size() && j <stems.size (); i+= 2, j++)
279 s->beams_left_i_ = b[i];
280 s->beams_right_i_ = b[i+1];
285 Beam::do_pre_processing()
294 Beam::do_width() const
296 return Interval (stems[0]->hpos_f(),
297 stems.top()->hpos_f ());
301 beams to go with one stem.
304 Beam::stem_beams (Stem *here, Stem *next, Stem *prev)const
306 assert (!next || next->hpos_f() > here->hpos_f () );
307 assert (!prev || prev->hpos_f() < here->hpos_f () );
308 // Real dy=paper()->internote_f ()*2;
309 Real dy = paper()->interbeam_f ();
310 Real stemdx = paper()->rule_thickness ();
311 Real sl = slope*paper()->internote_f ();
312 paper()->lookup_l ()->beam (sl, 20 PT);
317 /* half beams extending to the left. */
320 int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
321 int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
322 Real w = (here->hpos_f() - prev->hpos_f ())/4;
325 if (lhalfs) // generates warnings if not
326 a = paper()->lookup_l ()->beam (sl, w);
327 a.translate (Offset (-w, -w * sl));
328 for (int j = 0; j < lhalfs; j++)
331 b.translate (-dir_i_ * dy * (lwholebeams+j), Y_AXIS);
338 int rhalfs = here->beams_right_i_ - next->beams_left_i_;
339 int rwholebeams = here->beams_right_i_ <? next->beams_left_i_;
341 Real w = next->hpos_f() - here->hpos_f ();
342 Atom a = paper()->lookup_l ()->beam (sl, w + stemdx);
345 for (; j < rwholebeams; j++)
348 b.translate (-dir_i_ * dy * j, Y_AXIS);
354 a = paper()->lookup_l ()->beam (sl, w);
356 for (; j < rwholebeams + rhalfs; j++)
359 b.translate (-dir_i_ * dy * j, Y_AXIS);
364 leftbeams.add (rightbeams);
370 Beam::brew_molecule_p() const
373 Molecule *mol_p = new Molecule;
375 // Real inter_f = paper()->interbeam_f ();
376 Real inter_f = paper()->internote_f ();
377 Real x0 = stems[0]->hpos_f();
378 for (int j=0; j <stems.size(); j++)
381 Stem * prev = (j > 0)? stems[j-1] : 0;
382 Stem * next = (j < stems.size()-1) ? stems[j+1] :0;
384 Molecule sb = stem_beams (i, next, prev);
385 Real x = i->hpos_f()-x0;
386 sb.translate (Offset (x, (x * slope + left_pos)* inter_f));
389 mol_p->translate (x0 - left_col_l_->hpos_f_, X_AXIS);
394 IMPLEMENT_IS_TYPE_B1(Beam, Spanner);
397 Beam::do_print()const
400 DOUT << "slope " <<slope << "left ypos " << left_pos;
406 Beam::do_substitute_dependent (Score_elem*o,Score_elem*n)
408 if (o->is_type_b (Stem::static_name()))
410 stems.substitute ((Stem*)o->item(), n?(Stem*) n->item ():0);