2 beam.cc -- implement Beam
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--1998, 1998 Han-Wen Nienhuys <hanwen@stack.nl>
7 Jan Nieuwenhuizen <jan@digicash.com>
17 * (future) knee: ([\stem 1; c8 \stem -1; c8]
27 #include "abbreviation-beam.hh"
31 #include "molecule.hh"
32 #include "leastsquares.hh"
34 #include "paper-def.hh"
36 #include "grouping.hh"
37 #include "stem-info.hh"
38 #include "main.hh" // experimental features
41 IMPLEMENT_IS_TYPE_B1 (Beam, Spanner);
48 quantisation_ = NORMAL;
56 s->add_dependency (this);
59 if (!spanned_drul_[LEFT])
66 Beam::brew_molecule_p () const
68 Molecule *mol_p = new Molecule;
70 Real internote_f = paper ()->internote_f ();
72 Real x0 = stems_[0]->hpos_f ();
73 for (int j=0; j <stems_.size (); j++)
76 Stem * prev = (j > 0)? stems_[j-1] : 0;
77 Stem * next = (j < stems_.size ()-1) ? stems_[j+1] :0;
79 Molecule sb = stem_beams (i, next, prev);
80 Real x = i->hpos_f ()-x0;
81 sb.translate (Offset (x, (x * slope_f_ + left_y_) * internote_f));
84 mol_p->translate_axis (x0
85 - spanned_drul_[LEFT]->absolute_coordinate (X_AXIS), X_AXIS);
93 Real w= (paper ()->note_width () + width ().length ())/2.0;
94 return Offset (w, (left_y_ + w* slope_f_)*paper ()->internote_f ());
98 Beam::do_pre_processing ()
105 Beam::do_print () const
108 DOUT << "slope_f_ " <<slope_f_ << "left ypos " << left_y_;
109 Spanner::do_print ();
114 Beam::do_post_processing ()
116 if (stems_.size () < 2)
118 warning (_ ("Beam with less than 2 stems"));
119 transparent_b_ = true;
127 Beam::do_substitute_dependent (Score_elem*o,Score_elem*n)
129 if (o->is_type_b (Stem::static_name ()))
130 stems_.substitute ((Stem*)o->item (), n? (Stem*) n->item ():0);
134 Beam::do_width () const
136 return Interval (stems_[0]->hpos_f (),
137 stems_.top ()->hpos_f ());
141 Beam::set_default_dir ()
143 Drul_array<int> total;
144 total[UP] = total[DOWN] = 0;
145 Drul_array<int> count;
146 count[UP] = count[DOWN] = 0;
149 for (int i=0; i <stems_.size (); i++)
152 int current = s->dir_
153 ? (1 + d * s->dir_)/2
154 : s->get_center_distance ((Direction)-d);
162 } while (flip(&d) != DOWN);
167 } while (flip(&d) != DOWN);
171 [Ross] states that the majority of the notes dictates the
172 direction (and not the mean of "center distance")
174 dir_ = (total[UP] > total[DOWN]) ? UP : DOWN;
176 for (int i=0; i <stems_.size (); i++)
178 Stem *sl = stems_[i];
184 See Documentation/tex/fonts.doc
190 should use minimum energy formulation (cf linespacing)
193 assert (multiple_i_);
194 Array<Stem_info> sinfo;
195 for (int j=0; j <stems_.size (); j++)
199 i->mult_i_ = multiple_i_;
200 i->set_default_extents ();
201 if (i->invisible_b ())
208 slope_f_ = left_y_ = 0;
209 else if (sinfo.size () == 1)
212 left_y_ = sinfo[0].idealy_f_;
217 Real leftx = sinfo[0].x_;
219 for (int i=0; i < sinfo.size (); i++)
221 sinfo[i].x_ -= leftx;
222 l.input.push (Offset (sinfo[i].x_, sinfo[i].idealy_f_));
225 l.minimise (slope_f_, left_y_);
229 for (int i=0; i < sinfo.size (); i++)
231 Real y = sinfo[i].x_ * slope_f_ + left_y_;
232 Real my = sinfo[i].miny_f_;
243 This neat trick is by Werner Lemberg, damped = tanh (slope_f_) corresponds
244 with some tables in [Wanske]
247 slope_f_ = 0.6 * tanh (slope_f_) / damping_i_;
251 Real sl = slope_f_ * paper ()->internote_f ();
252 paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT);
253 slope_f_ = sl / paper ()->internote_f ();
260 [Ross] (simplification of)
261 Try to set slope_f_ complying with y-span of:
263 - beam_f / 2 + staffline_f / 2
264 - beam_f + staffline_f
268 if (quantisation_ <= NONE)
271 Real interline_f = paper ()->interline_f ();
272 Real internote_f = interline_f / 2;
273 Real staffline_f = paper ()->rule_thickness ();
274 Real beam_f = paper ()->beam_thickness_f ();
276 Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
278 // dim(y) = internote; so slope = (y/internote)/x
279 Real dy_f = dx_f * abs (slope_f_ * internote_f);
283 /* UGR. ICE in 2.8.1; bugreport filed. */
284 Array<Real> allowed_fraction (3);
285 allowed_fraction[0] = 0;
286 allowed_fraction[1] = (beam_f / 2 + staffline_f / 2);
287 allowed_fraction[2] = (beam_f + staffline_f);
290 Interval iv = quantise_iv (allowed_fraction, interline_f, dy_f);
291 quanty_f = (dy_f - iv.min () <= iv.max () - dy_f)
296 slope_f_ = (quanty_f / dx_f) / internote_f * sign (slope_f_);
299 static int test_pos = 0;
304 Prevent interference from stafflines and beams. See Documentation/tex/fonts.doc
308 Beam::quantise_left_y (bool extend_b)
311 we only need to quantise the start of the beam as dy is quantised too
312 if extend_b then stems must *not* get shorter
315 if (quantisation_ <= NONE)
319 ----------------------------------------------------------
323 --------------########------------------------------------
326 hang straddle sit inter hang
329 Real interline_f = paper ()->interline_f ();
330 Real internote_f = paper ()->internote_f ();
331 Real staffline_f = paper ()->rule_thickness ();
332 Real beam_f = paper ()->beam_thickness_f ();
336 it would be nice to have all allowed positions in a runtime matrix:
337 (multiplicity, minimum_beam_dy, maximum_beam_dy)
341 Real sit = beam_f / 2 - staffline_f / 2;
342 Real inter = interline_f / 2;
343 Real hang = interline_f - beam_f / 2 + staffline_f / 2;
346 Put all allowed positions into an array.
347 Whether a position is allowed or not depends on
348 strictness of quantisation, multiplicity and direction.
350 For simplicity, we'll assume dir = UP and correct if
351 dir = DOWN afterwards.
354 // dim(left_y_) = internote
355 Real dy_f = dir_ * left_y_ * internote_f;
357 Real beamdx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
358 Real beamdy_f = beamdx_f * slope_f_ * internote_f;
360 Array<Real> allowed_position;
361 if (quantisation_ != TEST)
363 if (quantisation_ <= NORMAL)
365 if ((multiple_i_ <= 2) || (abs (beamdy_f) >= staffline_f / 2))
366 allowed_position.push (straddle);
367 if ((multiple_i_ <= 1) || (abs (beamdy_f) >= staffline_f / 2))
368 allowed_position.push (sit);
369 allowed_position.push (hang);
372 // TODO: check and fix TRADITIONAL
374 if ((multiple_i_ <= 2) || (abs (beamdy_f) >= staffline_f / 2))
375 allowed_position.push (straddle);
376 if ((multiple_i_ <= 1) && (beamdy_f <= staffline_f / 2))
377 allowed_position.push (sit);
378 if (beamdy_f >= -staffline_f / 2)
379 allowed_position.push (hang);
386 allowed_position.push (hang);
387 cout << "hang" << hang << endl;
389 else if (test_pos==1)
391 allowed_position.push (straddle);
392 cout << "straddle" << straddle << endl;
394 else if (test_pos==2)
396 allowed_position.push (sit);
397 cout << "sit" << sit << endl;
399 else if (test_pos==3)
401 allowed_position.push (inter);
402 cout << "inter" << inter << endl;
407 // this currently never happens
408 Real q = (dy_f / interline_f - dy_i) * interline_f;
409 if ((quantisation_ < NORMAL) && (q < interline_f / 3 - beam_f / 2))
410 allowed_position.push (inter);
413 Interval iv = quantise_iv (allowed_position, interline_f, dy_f);
415 Real quanty_f = dy_f - iv.min () <= iv.max () - dy_f ? iv.min () : iv.max ();
417 quanty_f = iv.max ();
419 // dim(left_y_) = internote
420 left_y_ = dir_ * quanty_f / internote_f;
424 Beam::set_stemlens ()
426 Real staffline_f = paper ()->rule_thickness ();
428 Real x0 = stems_[0]->hpos_f ();
430 // ugh, rounding problems! (enge floots)
431 Real epsilon = staffline_f / 8;
434 left_y_ += dy * dir_;
435 quantise_left_y (dy);
437 for (int i=0; i < stems_.size (); i++)
440 if (s->transparent_b_)
443 Real x = s->hpos_f () - x0;
444 s->set_stemend (left_y_ + slope_f_ * x);
445 Real y = s->stem_end_f () * dir_;
447 if (y < info.miny_f_)
448 dy = dy >? info.miny_f_ - y;
450 } while (abs (dy) > epsilon);
458 ugh. this is broken and should be rewritten.
462 Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur)
466 assert (cur.children.size () == stems_.size ());
473 for (int j=0; j <stems_.size (); j++)
477 int f = s->flag_i_ - 2;
482 b= cur.generate_beams (flags, fi);
485 assert (stems_.size () == b.size ()/2);
488 for (int j=0, i=0; i < b.size () && j <stems_.size (); i+= 2, j++)
491 s->beams_left_i_ = b[i];
492 s->beams_right_i_ = b[i+1];
493 multiple_i_ = multiple_i_ >? (b[i] >? b[i+1]);
498 beams to go with one stem.
501 Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const
503 assert (!next || next->hpos_f () > here->hpos_f ());
504 assert (!prev || prev->hpos_f () < here->hpos_f ());
506 Real staffline_f = paper ()->rule_thickness ();
507 Real interbeam_f = paper ()->interbeam_f (multiple_i_);
508 Real internote_f = paper ()->internote_f ();
509 Real beam_f = paper ()->beam_thickness_f ();
511 Real dy = interbeam_f;
512 Real stemdx = staffline_f;
513 Real sl = slope_f_* internote_f;
514 paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT);
519 /* half beams extending to the left. */
522 int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
523 int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
524 Real w = (here->hpos_f () - prev->hpos_f ())/4 <? paper ()->note_width ();;
526 if (lhalfs) // generates warnings if not
527 a = paper ()->lookup_l ()->beam (sl, w, beam_f);
528 a.translate (Offset (-w, -w * sl));
529 for (int j = 0; j < lhalfs; j++)
532 b.translate_axis (-dir_ * dy * (lwholebeams+j), Y_AXIS);
539 int rhalfs = here->beams_right_i_ - next->beams_left_i_;
540 int rwholebeams = here->beams_right_i_ <? next->beams_left_i_;
542 Real w = next->hpos_f () - here->hpos_f ();
543 Atom a = paper ()->lookup_l ()->beam (sl, w + stemdx, beam_f);
544 a.translate_axis( - stemdx/2, X_AXIS);
547 if (here->beam_gap_i_)
549 int nogap = rwholebeams - here->beam_gap_i_;
550 for (; j < nogap; j++)
553 b.translate_axis (-dir_ * dy * j, Y_AXIS);
556 // TODO: notehead widths differ for different types
557 gap_f = paper ()->note_width () / 2;
559 a = paper ()->lookup_l ()->beam (sl, w + stemdx, beam_f);
562 for (; j < rwholebeams; j++)
565 b.translate (Offset (gap_f, -dir_ * dy * j));
569 w = w/4 <? paper ()->note_width ();
571 a = paper ()->lookup_l ()->beam (sl, w, beam_f);
573 for (; j < rwholebeams + rhalfs; j++)
576 b.translate_axis (-dir_ * dy * j, Y_AXIS);
581 leftbeams.add (rightbeams);
584 Does beam quanting think of the asymetry of beams?
585 Refpoint is on bottom of symbol. (FIXTHAT) --hwn.