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>
14 * lowest beam of (UP) beam must never be lower than second staffline
18 * (future) knee: ([\stem 1; c8 \stem -1; c8]
28 #include "abbreviation-beam.hh"
32 #include "molecule.hh"
33 #include "leastsquares.hh"
35 #include "paper-def.hh"
37 #include "grouping.hh"
38 #include "stem-info.hh"
39 #include "main.hh" // experimental features
42 IMPLEMENT_IS_TYPE_B1 (Beam, Spanner);
49 quantisation_ = NORMAL;
57 s->add_dependency (this);
60 if (!spanned_drul_[LEFT])
67 Beam::brew_molecule_p () const
69 Molecule *mol_p = new Molecule;
71 Real interline_f = paper ()->interline_f ();
72 Real internote_f = interline_f / 2;
73 Real staffline_f = paper ()->rule_thickness ();
74 Real beam_f = 0.48 * (interline_f - staffline_f);
76 Real x0 = stems_[0]->hpos_f ();
77 for (int j=0; j <stems_.size (); j++)
80 Stem * prev = (j > 0)? stems_[j-1] : 0;
81 Stem * next = (j < stems_.size ()-1) ? stems_[j+1] :0;
83 Molecule sb = stem_beams (i, next, prev);
84 Real x = i->hpos_f ()-x0;
85 sb.translate (Offset (x, (x * slope_f_ + left_y_) * internote_f));
88 mol_p->translate_axis (x0
89 - spanned_drul_[LEFT]->absolute_coordinate (X_AXIS), X_AXIS);
97 Real w= (paper ()->note_width () + width ().length ())/2.0;
98 return Offset (w, (left_y_ + w* slope_f_)*paper ()->internote_f ());
102 Beam::do_pre_processing ()
109 Beam::do_print () const
112 DOUT << "slope_f_ " <<slope_f_ << "left ypos " << left_y_;
113 Spanner::do_print ();
118 Beam::do_post_processing ()
120 if (stems_.size () < 2)
122 warning (_ ("Beam with less than 2 stems"));
123 transparent_b_ = true;
131 Beam::do_substitute_dependent (Score_elem*o,Score_elem*n)
133 if (o->is_type_b (Stem::static_name ()))
134 stems_.substitute ((Stem*)o->item (), n? (Stem*) n->item ():0);
138 Beam::do_width () const
140 return Interval (stems_[0]->hpos_f (),
141 stems_.top ()->hpos_f ());
145 Beam::set_default_dir ()
147 Drul_array<int> total;
148 total[UP] = total[DOWN] = 0;
149 Drul_array<int> count;
150 count[UP] = count[DOWN] = 0;
153 for (int i=0; i <stems_.size (); i++)
156 int current = s->dir_
157 ? (1 + d * s->dir_)/2
158 : s->get_center_distance ((Direction)-d);
166 } while (flip(&d) != DOWN);
171 } while (flip(&d) != DOWN);
175 [Ross] states that the majority of the notes dictates the
176 direction (and not the mean of "center distance")
178 dir_ = (total[UP] > total[DOWN]) ? UP : DOWN;
180 for (int i=0; i <stems_.size (); i++)
182 Stem *sl = stems_[i];
188 See Documentation/tex/fonts.doc
194 should use minimum energy formulation (cf linespacing)
197 assert (multiple_i_);
198 Array<Stem_info> sinfo;
199 for (int j=0; j <stems_.size (); j++)
203 i->mult_i_ = multiple_i_;
204 i->set_default_extents ();
205 if (i->invisible_b ())
212 slope_f_ = left_y_ = 0;
213 else if (sinfo.size () == 1)
216 left_y_ = sinfo[0].idealy_f_;
221 Real leftx = sinfo[0].x_;
223 for (int i=0; i < sinfo.size (); i++)
225 sinfo[i].x_ -= leftx;
226 l.input.push (Offset (sinfo[i].x_, sinfo[i].idealy_f_));
229 l.minimise (slope_f_, left_y_);
233 for (int i=0; i < sinfo.size (); i++)
235 Real y = sinfo[i].x_ * slope_f_ + left_y_;
236 Real my = sinfo[i].miny_f_;
247 This neat trick is by Werner Lemberg, damped = tanh (slope_f_) corresponds
248 with some tables in [Wanske]
251 slope_f_ = 0.6 * tanh (slope_f_) / damping_i_;
255 Real sl = slope_f_ * paper ()->internote_f ();
256 paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT);
257 slope_f_ = sl / paper ()->internote_f ();
264 [Ross] (simplification of)
265 Try to set slope_f_ complying with y-span of:
267 - beam_f / 2 + staffline_f / 2
268 - beam_f + staffline_f
272 if (quantisation_ <= NONE)
275 Real interline_f = paper ()->interline_f ();
276 Real internote_f = interline_f / 2;
277 Real staffline_f = paper ()->rule_thickness ();
278 Real beam_f = 0.48 * (interline_f - staffline_f);
280 Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
282 // dim(y) = internote; so slope = (y/internote)/x
283 Real dy_f = dx_f * abs (slope_f_ * internote_f);
287 /* UGR. ICE in 2.8.1; bugreport filed. */
288 Array<Real> allowed_fraction (3);
289 allowed_fraction[0] = 0;
290 allowed_fraction[1] = (beam_f / 2 + staffline_f / 2);
291 allowed_fraction[2] = (beam_f + staffline_f);
294 Interval iv = quantise_iv (allowed_fraction, interline_f, dy_f);
295 quanty_f = (dy_f - iv.min () <= iv.max () - dy_f)
300 slope_f_ = (quanty_f / dx_f) / internote_f * sign (slope_f_);
303 static int test_pos = 0;
308 Prevent interference from stafflines and beams. See Documentation/tex/fonts.doc
312 Beam::quantise_left_y (bool extend_b)
315 we only need to quantise the start of the beam as dy is quantised too
316 if extend_b then stems must *not* get shorter
319 if (quantisation_ <= NONE)
323 ----------------------------------------------------------
327 --------------########------------------------------------
330 hang straddle sit inter hang
333 Real interbeam_f = paper ()->interbeam_f ();
334 Real interline_f = paper ()->interline_f ();
335 Real internote_f = interline_f / 2;
336 Real staffline_f = paper ()->rule_thickness ();
337 Real beam_f = 0.48 * (interline_f - staffline_f);
338 Real symbol_f = beam_f + interbeam_f * (multiple_i_ - 1);
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 Array<Real> allowed_position;
358 if (quantisation_ != TEST)
360 if (quantisation_ <= NORMAL)
362 if ((multiple_i_ <= 2) || (abs (dy_f) >= staffline_f / 2))
363 allowed_position.push (straddle);
364 if ((multiple_i_ <= 1) || (abs (dy_f) >= staffline_f / 2))
365 allowed_position.push (sit);
366 allowed_position.push (hang);
369 // TODO: check and fix TRADITIONAL
371 if ((multiple_i_ <= 2) || (abs (dy_f) >= staffline_f / 2))
372 allowed_position.push (straddle);
373 if ((multiple_i_ <= 1) && (dy_f <= staffline_f / 2))
374 allowed_position.push (sit);
375 if (dy_f >= -staffline_f / 2)
376 allowed_position.push (hang);
383 allowed_position.push (hang);
384 cout << "hang" << hang << endl;
386 else if (test_pos==1)
388 allowed_position.push (straddle);
389 cout << "straddle" << straddle << endl;
391 else if (test_pos==2)
393 allowed_position.push (sit);
394 cout << "sit" << sit << endl;
396 else if (test_pos==3)
398 allowed_position.push (inter);
399 cout << "inter" << inter << endl;
404 // this currently never happens
405 Real q = (dy_f / interline_f - dy_i) * interline_f;
406 if ((quantisation_ < NORMAL) && (q < interline_f / 3 - beam_f / 2))
407 allowed_position.push (inter);
410 Interval iv = quantise_iv (allowed_position, interline_f, dy_f);
412 Real quanty_f = dy_f - iv.min () <= iv.max () - dy_f ? iv.min () : iv.max ();
414 quanty_f = iv.max ();
416 // dim(left_y_) = internote
417 left_y_ = dir_ * quanty_f / internote_f;
421 Beam::set_stemlens ()
423 Real interbeam_f = paper ()->interbeam_f ();
424 Real interline_f = paper ()->interline_f ();
425 Real internote_f = interline_f / 2;
426 Real staffline_f = paper ()->rule_thickness ();
427 Real beam_f = 0.48 * (interline_f - staffline_f);
430 if we have more than three beams they must open-up
431 in order to not collide with staff lines
434 interbeam_f += 2.0 * staffline_f / 4;
436 Real x0 = stems_[0]->hpos_f ();
438 // ugh, rounding problems! (enge floots)
439 Real epsilon = staffline_f / 8;
442 left_y_ += dy * dir_;
443 quantise_left_y (dy);
445 for (int i=0; i < stems_.size (); i++)
448 if (s->transparent_b_)
451 Real x = s->hpos_f () - x0;
452 s->set_stemend (left_y_ + slope_f_ * x);
453 Real y = s->stem_end_f () * dir_;
455 if (y < info.miny_f_)
456 dy = dy >? info.miny_f_ - y;
458 } while (abs (dy) > epsilon);
460 // ugh asymmetric symbol ?
462 left_y_ -= dir_ * staffline_f / 4;
464 if ((multiple_i_ >= 3) && (dir_ == UP))
465 left_y_ -= dir_ * staffline_f / 4;
473 ugh. this is broken and should be rewritten.
477 Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur)
481 assert (cur.children.size () == stems_.size ());
488 for (int j=0; j <stems_.size (); j++)
492 int f = s->flag_i_ - 2;
497 b= cur.generate_beams (flags, fi);
500 assert (stems_.size () == b.size ()/2);
503 for (int j=0, i=0; i < b.size () && j <stems_.size (); i+= 2, j++)
506 s->beams_left_i_ = b[i];
507 s->beams_right_i_ = b[i+1];
508 multiple_i_ = multiple_i_ >? (b[i] >? b[i+1]);
513 beams to go with one stem.
516 Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const
518 assert (!next || next->hpos_f () > here->hpos_f ());
519 assert (!prev || prev->hpos_f () < here->hpos_f ());
521 Real staffline_f = paper ()->rule_thickness ();
522 Real interbeam_f = paper ()->interbeam_f ();
523 Real internote_f =paper ()->internote_f ();
524 Real interline_f = 2 * internote_f;
525 Real beamheight_f = 0.48 * (interline_f - staffline_f);
528 interbeam_f += 2.0 * staffline_f / 4;
529 Real dy = interbeam_f;
530 Real stemdx = staffline_f;
531 Real sl = slope_f_* internote_f;
532 paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT);
537 /* half beams extending to the left. */
540 int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ;
541 int lwholebeams= here->beams_left_i_ <? prev->beams_right_i_ ;
542 Real w = (here->hpos_f () - prev->hpos_f ())/4 <? paper ()->note_width ();;
544 if (lhalfs) // generates warnings if not
545 a = paper ()->lookup_l ()->beam (sl, w, beamheight_f);
546 a.translate (Offset (-w, -w * sl));
547 for (int j = 0; j < lhalfs; j++)
550 b.translate_axis (-dir_ * dy * (lwholebeams+j), Y_AXIS);
557 int rhalfs = here->beams_right_i_ - next->beams_left_i_;
558 int rwholebeams = here->beams_right_i_ <? next->beams_left_i_;
560 Real w = next->hpos_f () - here->hpos_f ();
561 Atom a = paper ()->lookup_l ()->beam (sl, w + stemdx, beamheight_f);
562 a.translate_axis( - stemdx/2, X_AXIS);
565 if (here->beam_gap_i_)
567 int nogap = rwholebeams - here->beam_gap_i_;
568 for (; j < nogap; j++)
571 b.translate_axis (-dir_ * dy * j, Y_AXIS);
574 // TODO: notehead widths differ for different types
575 gap_f = paper ()->note_width () / 2;
577 a = paper ()->lookup_l ()->beam (sl, w + stemdx, beamheight_f);
580 for (; j < rwholebeams; j++)
583 b.translate (Offset (gap_f, -dir_ * dy * j));
587 w = w/4 <? paper ()->note_width ();
589 a = paper ()->lookup_l ()->beam (sl, w, beamheight_f);
591 for (; j < rwholebeams + rhalfs; j++)
594 b.translate_axis (-dir_ * dy * j, Y_AXIS);
599 leftbeams.add (rightbeams);
602 Does beam quanting think of the asymetry of beams?
603 Refpoint is on bottom of symbol. (FIXTHAT) --hwn.