X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=92a92050a2fc019dcc24bce56191e284d71070c3;hb=refs%2Ftags%2Frelease%2F1.2.13;hp=450c12db14a1e75758bf77c692e14b196574103e;hpb=1bdf3db27451a0873b2c97545f0beab2f5cce06a;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 450c12db14..92a92050a2 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -3,61 +3,66 @@ source file of the GNU LilyPond music typesetter - (c) 1997 Han-Wen Nienhuys + (c) 1997--1999 Han-Wen Nienhuys + Jan Nieuwenhuizen - TODO +*/ - Less hairy code. knee: ([\stem 1; c8 \stem -1; c8] -*/ +/* + [TODO] + * center beam symbol + * less hairy code + * redo grouping + +TODO: + +The relationship Stem <-> Beam is way too hairy. Let's figure who +needs what, and what information should be available when. + + */ #include -#include "p-col.hh" -#include "varray.hh" +#include "chord-tremolo.hh" +#include "beaming.hh" #include "proto.hh" -#include "dimen.hh" +#include "dimensions.hh" #include "beam.hh" -#include "abbreviation-beam.hh" #include "misc.hh" #include "debug.hh" -#include "atom.hh" #include "molecule.hh" #include "leastsquares.hh" #include "stem.hh" #include "paper-def.hh" #include "lookup.hh" -#include "grouping.hh" -#include "stem-info.hh" -#include "main.hh" // experimental features - - -IMPLEMENT_IS_TYPE_B1 (Beam, Spanner); - -// ugh, hardcoded -const int MINIMUM_STEMLEN[] = { - 0, // just in case - 5, - 4, - 3, - 2, - 2, -}; Beam::Beam () { slope_f_ = 0; - left_y_ = 0.0; - damping_i_ = 1; + left_y_ = 0; quantisation_ = NORMAL; multiple_i_ = 0; } void -Beam::add (Stem*s) +Beam::add_stem (Stem*s) { +#if 0 + /* + should figure out why this didn't work. + + --hwn. + */ + if (!stems_.size ()) + { + set_parent (s, Y_AXIS); + } +#endif stems_.push (s); s->add_dependency (this); + + assert (!s->beam_l_); s->beam_l_ = this; if (!spanned_drul_[LEFT]) @@ -66,11 +71,26 @@ Beam::add (Stem*s) set_bounds (RIGHT,s); } +Stem_info +Beam::get_stem_info (Stem *s) +{ + Stem_info i; + for (int i=0; i < sinfo_.size (); i++) + { + if (sinfo_[i].stem_l_ == s) + return sinfo_[i]; + } + assert (false); + return i; +} + Molecule* -Beam::brew_molecule_p () const +Beam::do_brew_molecule_p () const { Molecule *mol_p = new Molecule; - Real inter_f = paper ()->internote_f (); + if (!sinfo_.size ()) + return mol_p; + Real x0 = stems_[0]->hpos_f (); for (int j=0; j hpos_f ()-x0; - sb.translate (Offset (x, (x * slope_f_ + left_y_)* inter_f)); - mol_p->add (sb); + sb.translate (Offset (x, (x * slope_f_ + left_y_) * + i->staff_line_leading_f ()/2 )); + mol_p->add_molecule (sb); } - mol_p->translate_axis (x0 - spanned_drul_[LEFT]->absolute_coordinate (X_AXIS), X_AXIS); + mol_p->translate_axis (x0 + - spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS), X_AXIS); + return mol_p; } Offset Beam::center () const { - Real w= (paper ()->note_width () + width ().length ())/2.0; - return Offset (w, (left_y_ + w* slope_f_)*paper ()->internote_f ()); + Stem_info si = sinfo_[0]; + + Real w= (si.stem_l_->note_delta_f () + extent (X_AXIS).length ())/2.0; + return Offset (w, ( w* slope_f_) * + si.stem_l_->staff_line_leading_f ()/2); } +/* + Simplistic auto-knees; only consider vertical gap between two + adjacent chords + */ +bool +Beam::auto_knee (SCM gap, bool interstaff_b) +{ + bool knee = false; + int knee_y = 0; + Real internote_f = stems_[0]->staff_line_leading_f ()/2; + if (gap != SCM_BOOL_F) + { + int auto_gap_i = gh_scm2int (SCM_CDR (gap)); + for (int i=1; i < stems_.size (); i++) + { + bool is_b = (bool)(sinfo_[i].interstaff_f_ - sinfo_[i-1].interstaff_f_); + int l_y = (int)(stems_[i-1]->chord_start_f () / internote_f) + + (int)sinfo_[i-1].interstaff_f_; + int r_y = (int)(stems_[i]->chord_start_f () / internote_f) + + (int)sinfo_[i].interstaff_f_; + int gap_i = r_y - l_y; + + /* + Forced stem directions are ignored. If you don't want auto-knees, + don't set, or unset autoKneeGap/autoInterstaffKneeGap. + */ + if ((abs (gap_i) >= auto_gap_i) && (!interstaff_b || is_b)) + { + knee_y = (r_y + l_y) / 2; + knee = true; + break; + } + } + } + if (knee) + { + for (int i=0; i < stems_.size (); i++) + { + int y = (int)(stems_[i]->chord_start_f () / internote_f) + + (int)sinfo_[i].interstaff_f_; + stems_[i]->dir_ = y < knee_y ? UP : DOWN; + stems_[i]->set_elt_property (dir_forced_scm_sym, SCM_BOOL_T); + } + } + return knee; +} + +bool +Beam::auto_knees () +{ + if (auto_knee (get_elt_property (auto_interstaff_knee_gap_scm_sym), true)) + return true; + + return auto_knee (get_elt_property (auto_knee_gap_scm_sym), false); +} + + void Beam::do_pre_processing () { + /* + urg: it seems that info on whether beam (voice) dir was forced + is being junked here? + */ if (!dir_) - set_default_dir (); + dir_ = get_default_dir (); + + set_direction (dir_); } void Beam::do_print () const { #ifndef NPRINT - DOUT << "slope_f_ " <is_type_b (Stem::static_name ())) - stems_.substitute ((Stem*)o->item (), n? (Stem*) n->item ():0); + if (Stem * os = dynamic_cast (o)) + stems_.substitute (os, + dynamic_cast (n)); } Interval @@ -137,21 +245,21 @@ Beam::do_width () const stems_.top ()->hpos_f ()); } -void -Beam::set_default_dir () +Direction +Beam::get_default_dir () const { Drul_array total; total[UP] = total[DOWN] = 0; Drul_array count; count[UP] = count[DOWN] = 0; Direction d = DOWN; - + for (int i=0; i dir_ ? (1 + d * s->dir_)/2 - : s->get_center_distance (Direction (-d)); + : s->get_center_distance ((Direction)-d); if (current) { @@ -159,426 +267,582 @@ Beam::set_default_dir () count[d] ++; } - } while ((d *= -1) != DOWN); - - do { - if (!total[d]) - count[d] = 1; - } while ((d *= -1) != DOWN); + } while (flip(&d) != DOWN); /* - [Ross] states that the majority of the notes dictates the direction (and not the mean of "center distance") + + But is that because it really looks better, or because he + wants to provide some real simple hands-on rules. + + We have our doubts, so we simply provide all sensible alternatives. + + If dir is not determined: up (see stem::get_default_dir ()) */ - dir_ = (total[UP] > total[DOWN]) ? UP : DOWN; + Direction beam_dir; + Direction neutral_dir = (Direction)(int)paper_l ()->get_var ("stem_default_neutral_direction"); + + Dir_algorithm a = (Dir_algorithm)rint(paper_l ()->get_var ("beam_dir_algorithm")); + switch (a) + { + case MAJORITY: + beam_dir = (count[UP] == count[DOWN]) ? neutral_dir + : (count[UP] > count[DOWN]) ? UP : DOWN; + break; + case MEAN: + // mean center distance + beam_dir = (total[UP] == total[DOWN]) ? neutral_dir + : (total[UP] > total[DOWN]) ? UP : DOWN; + break; + default: + case MEDIAN: + // median center distance + if (!count[DOWN] || !count[UP]) + { + beam_dir = (count[UP] == count[DOWN]) ? neutral_dir + : (count[UP] > count[DOWN]) ? UP : DOWN; + } + else + { + beam_dir = (total[UP] / count[UP] == total[DOWN] / count[DOWN]) + ? neutral_dir + : (total[UP] / count[UP] > total[DOWN] / count[DOWN]) ? UP : DOWN; + } + break; + } + return beam_dir; +} + +void +Beam::set_direction (Direction d) +{ + dir_ = d; for (int i=0; i dir_ = dir_; + Stem *s = stems_[i]; + s->set_elt_property (beam_dir_scm_sym, gh_int2scm (d)); + + SCM force = s->remove_elt_property (dir_forced_scm_sym); + if (force == SCM_BOOL_F) + s->dir_ = d; } } /* - should use minimum energy formulation (cf linespacing) -*/ + See Documentation/tex/fonts.doc + */ + void Beam::solve_slope () { - Array sinfo; - for (int j=0; j 1); + DEBUG_OUT << "Beam::solve_slope: \n"; - i->set_default_extents (); - if (i->invisible_b ()) - continue; - - Stem_info info (i); - sinfo.push (info); - } - if (! sinfo.size ()) - slope_f_ = left_y_ = 0; - else if (sinfo.size () == 1) + Least_squares l; + for (int i=0; i < sinfo_.size (); i++) { - slope_f_ = 0; - left_y_ = sinfo[0].idealy_f_; + l.input.push (Offset (sinfo_[i].x_, sinfo_[i].idealy_f_)); } - else + l.minimise (slope_f_, left_y_); +} + +/* + ugh. Naming: this doesn't check, but sets as well. + */ + +Real +Beam::check_stemlengths_f (bool set_b) +{ + Real interbeam_f = paper_l ()->interbeam_f (multiple_i_); + + Real beam_f = paper_l ()->beam_thickness_f (); + Real staffline_f = paper_l ()->rule_thickness (); + Real epsilon_f = staffline_f / 8; + Real dy_f = 0.0; + for (int i=0; i < sinfo_.size (); i++) { + Real y = sinfo_[i].x_ * slope_f_ + left_y_; - Real leftx = sinfo[0].x; - Least_squares l; - for (int i=0; i < sinfo.size (); i++) + // correct for knee + if (dir_ != sinfo_[i].dir_) { - sinfo[i].x -= leftx; - l.input.push (Offset (sinfo[i].x, sinfo[i].idealy_f_)); + Real internote_f = sinfo_[i].stem_l_->staff_line_leading_f ()/2; + y -= dir_ * (beam_f / 2 + + (sinfo_[i].mult_i_ - 1) * interbeam_f) / internote_f; + if (!i && sinfo_[i].stem_l_->staff_symbol_l () != + sinfo_.top ().stem_l_->staff_symbol_l ()) + y += dir_ * (multiple_i_ - (sinfo_[i].stem_l_->flag_i_ - 2) >? 0) + * interbeam_f / internote_f; } - l.minimise (slope_f_, left_y_); + if (set_b) + sinfo_[i].stem_l_->set_stemend (y - sinfo_[i].interstaff_f_); + + y *= dir_; + if (y > sinfo_[i].maxy_f_) + dy_f = dy_f ? sinfo_[i].miny_f_ - y; + } } + return dy_f; +} - Real dy = 0.0; - for (int i=0; i < sinfo.size (); i++) +void +Beam::set_steminfo () +{ + if(!stems_.size ()) + return; + + assert (multiple_i_); + + int total_count_i = 0; + int forced_count_i = 0; + for (int i=0; i < stems_.size (); i++) { - Real y = sinfo[i].x * slope_f_ + left_y_; - Real my = sinfo[i].miny_f_; + Stem *s = stems_[i]; - if (my - y > dy) - dy = my -y; + s->set_default_extents (); + if (s->invisible_b ()) + continue; + if (((int)s->chord_start_f ()) && (s->dir_ != s->get_default_dir ())) + forced_count_i++; + total_count_i++; } - left_y_ += dy; - left_y_ *= dir_; - slope_f_ *= dir_; + bool grace_b = get_elt_property (grace_scm_sym) != SCM_BOOL_F; + String type_str = grace_b ? "grace_" : ""; + int stem_max = (int)rint(paper_l ()->get_var ("stem_max")); + Real shorten_f = paper_l ()->get_var (type_str + "forced_stem_shorten" + + to_str (multiple_i_ (this)) + { + if (s->invisible_b ()) + continue; + } - /* - This neat trick is by Werner Lemberg, damped = tanh (slope_f_) corresponds - with some tables in [Wanske] - */ - if (damping_i_) - slope_f_ = 0.6 * tanh (slope_f_) / damping_i_; + Stem_info info (s, multiple_i_); + if (leftx == 0) + leftx = info.x_; + info.x_ -= leftx; + if (info.dir_ == dir_) + { + if (forced_count_i == total_count_i) + info.idealy_f_ -= shorten_f; + else if (forced_count_i > total_count_i / 2) + info.idealy_f_ -= shorten_f / 2; + } + sinfo_.push (info); + } +} - quantise_yspan (); +void +Beam::calculate_slope () +{ + if (!sinfo_.size ()) + slope_f_ = left_y_ = 0; + else if (sinfo_[0].idealy_f_ == sinfo_.top ().idealy_f_) + { + slope_f_ = 0; + left_y_ = sinfo_[0].idealy_f_; + left_y_ *= dir_; + } + else + { + solve_slope (); + Real solved_slope_f = slope_f_; + + /* + steep slope running against lengthened stem is suspect + */ + Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); + + // urg, these y internote-y-dimensions + Real internote_f = stems_[0]->staff_line_leading_f ()/2; + + Real lengthened = paper_l ()->get_var ("beam_lengthened") / internote_f; + Real steep = paper_l ()->get_var ("beam_steep_slope") / internote_f; + if (((left_y_ - sinfo_[0].idealy_f_ > lengthened) + && (slope_f_ > steep)) + || ((left_y_ + slope_f_ * dx_f - sinfo_.top ().idealy_f_ > lengthened) + && (slope_f_ < -steep))) + { + slope_f_ = 0; + } - // y-values traditionally use internote dimension: therefore slope = (y/in)/x - // but mf and beam-lookup use PT dimension for y (as used for x-values) - // ugh --- there goes our simplified but careful quantisation - Real sl = slope_f_ * paper ()->internote_f (); - paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT); - slope_f_ = sl / paper ()->internote_f (); + /* + This neat trick is by Werner Lemberg, + damped = tanh (slope_f_) + corresponds with some tables in [Wanske] + */ + SCM damp = remove_elt_property (damping_scm_sym); + int damping = 1; // ugh. + if (damp!= SCM_BOOL_F) + damping = gh_int2scm (SCM_CDR(damp)); + + if (damping) + slope_f_ = 0.6 * tanh (slope_f_) / damping; + + quantise_dy (); + + Real damped_slope_dy_f = (solved_slope_f - slope_f_) * dx_f / 2; + left_y_ += damped_slope_dy_f; + + left_y_ *= dir_; + slope_f_ *= dir_; + } } void -Beam::quantise_yspan () +Beam::quantise_dy () { /* [Ross] (simplification of) Try to set slope_f_ complying with y-span of: - zero - - beam_thickness / 2 + staffline_thickness / 2 - - beam_thickness + staffline_thickness + - beam_f / 2 + staffline_f / 2 + - beam_f + staffline_f + n * interline */ - if (!quantisation_) + if (quantisation_ <= NONE) return; - Real interline_f = paper ()->interline_f (); + Real interline_f = stems_[0]->staff_line_leading_f (); Real internote_f = interline_f / 2; - Real staffline_thickness = paper ()->rule_thickness (); - Real beam_thickness = 0.48 * (interline_f - staffline_thickness); - - const int QUANTS = 3; - Real qdy[QUANTS] = { - 0, - beam_thickness / 2 + staffline_thickness / 2, - beam_thickness + staffline_thickness - }; - - Real xspan_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); - // y-values traditionally use internote dimension: therefore slope = (y/in)/x - Real yspan_f = xspan_f * abs (slope_f_ * internote_f); - int yspan_i = (int)(yspan_f / interline_f); - Real q = (yspan_f / interline_f - yspan_i) * interline_f; - int i = 0; - for (; i < QUANTS - 1; i++) - if ((q >= qdy[i]) && (q <= qdy[i + 1])) - { - if (q - qdy[i] < qdy[i + 1] - q) - break; - else - { - i++; - break; - } - } - q = qdy[i]; + Real staffline_f = paper_l ()->rule_thickness (); + Real beam_f = paper_l ()->beam_thickness_f (); + + Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); - yspan_f = (Real)yspan_i * interline_f + q; - // y-values traditionally use internote dimension: therefore slope = (y/in)/x - slope_f_ = yspan_f / xspan_f / internote_f * sign (slope_f_); + // dim(y) = internote; so slope = (y/internote)/x + Real dy_f = dx_f * abs (slope_f_ * internote_f); + + Real quanty_f = 0.0; + + /* UGR. ICE in 2.8.1; bugreport filed. */ + Array allowed_fraction (3); + allowed_fraction[0] = 0; + allowed_fraction[1] = (beam_f / 2 + staffline_f / 2); + allowed_fraction[2] = (beam_f + staffline_f); + + + Interval iv = quantise_iv (allowed_fraction, interline_f, dy_f); + quanty_f = (dy_f - iv[SMALLER] <= iv[BIGGER] - dy_f) + ? iv[SMALLER] + : iv[BIGGER]; + + + slope_f_ = (quanty_f / dx_f) / internote_f * sign (slope_f_); } +static int test_pos = 0; + + +/* + + Prevent interference from stafflines and beams. See Documentation/tex/fonts.doc + + */ void -Beam::quantise_left_y (Beam::Pos pos, bool extend_b) +Beam::quantise_left_y (bool extend_b) { - /* - quantising left y should suffice, as slope is quantised too - if extend then stems must not get shorter + /* + we only need to quantise the start of the beam as dy is quantised too + if extend_b then stems must *not* get shorter */ - if (!quantisation_) + if (quantisation_ <= NONE) return; - Real interline_f = paper ()->interline_f (); - Real internote_f = interline_f / 2; - Real staffline_thickness = paper ()->rule_thickness (); - Real beam_thickness = 0.48 * (interline_f - staffline_thickness); - - const int QUANTS = 6; - Real qy[QUANTS] = { - 0, - beam_thickness / 2, - beam_thickness, - interline_f / 2 + beam_thickness / 2 + staffline_thickness / 2, - interline_f, - interline_f + beam_thickness / 2, - }; - /* - ugh, using i triggers gcc 2.7.2.1 internal compiler error (far down): - for (int i = 0; i < QUANTS; i++) + /* + ---------------------------------------------------------- + ######## + ######## + ######## + --------------########------------------------------------ + ######## + + hang straddle sit inter hang + */ + + Real space = stems_[0]->staff_line_leading_f (); + Real internote_f = space /2; + Real staffline_f = paper_l ()->rule_thickness (); + Real beam_f = paper_l ()->beam_thickness_f (); + + /* + [TODO] + it would be nice to have all allowed positions in a runtime matrix: + (multiplicity, minimum_beam_dy, maximum_beam_dy) + */ + + Real straddle = 0; + Real sit = beam_f / 2 - staffline_f / 2; + Real inter = space / 2; + Real hang = space - beam_f / 2 + staffline_f / 2; + + /* + Put all allowed positions into an array. + Whether a position is allowed or not depends on + strictness of quantisation, multiplicity and direction. + + For simplicity, we'll assume dir = UP and correct if + dir = DOWN afterwards. */ - for (int ii = 0; ii < QUANTS; ii++) - qy[ii] -= beam_thickness / 2; - Pos qpos[QUANTS] = { - HANG, - STRADDLE, - SIT, - INTER, - HANG, - STRADDLE - }; - - // y-values traditionally use internote dimension - Real y = left_y_ * internote_f; - int y_i = (int)floor(y / interline_f); - y = (y / interline_f - y_i) * interline_f; - - if (y < 0) - for (int ii = 0; ii < QUANTS; ii++) - qy[ii] -= interline_f; - - int lower_i = 0; - int i = 0; - for (; i < QUANTS; i++) + + // dim(left_y_) = internote + Real dy_f = dir_ * left_y_ * internote_f; + + Real beamdx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); + Real beamdy_f = beamdx_f * slope_f_ * internote_f; + + Array allowed_position; + if (quantisation_ != TEST) { - if (qy[i] > y) - break; - // found if lower_i is allowed, and nearer (from below) y than new pos - if ((pos & qpos[lower_i]) && (y - qy[lower_i] < y - qy[i])) - break; - // if new pos is allowed or old pos isn't: assign new pos - if ((pos & qpos[i]) || !(pos & qpos[lower_i])) - lower_i = i; + if (quantisation_ <= NORMAL) + { + if ((multiple_i_ <= 2) || (abs (beamdy_f) >= staffline_f / 2)) + allowed_position.push (straddle); + if ((multiple_i_ <= 1) || (abs (beamdy_f) >= staffline_f / 2)) + allowed_position.push (sit); + allowed_position.push (hang); + } + else + // TODO: check and fix TRADITIONAL + { + if ((multiple_i_ <= 2) || (abs (beamdy_f) >= staffline_f / 2)) + allowed_position.push (straddle); + if ((multiple_i_ <= 1) && (beamdy_f <= staffline_f / 2)) + allowed_position.push (sit); + if (beamdy_f >= -staffline_f / 2) + allowed_position.push (hang); + } } - - int upper_i = QUANTS - 1; - for (i = QUANTS - 1; i >= 0; i--) + else { - if (qy[i] < y) - break; - // found if upper_i is allowed, and nearer (from above) y than new pos - if ((pos & qpos[upper_i]) && (qy[upper_i] - y < qy[i] - y)) - break; - // if new pos is allowed or old pos isn't: assign new pos - if ((pos & qpos[i]) || !(pos & qpos[upper_i])) - upper_i = i; + if (test_pos == 0) + { + allowed_position.push (hang); + cout << "hang" << hang << "\n"; + } + else if (test_pos==1) + { + allowed_position.push (straddle); + cout << "straddle" << straddle << endl; + } + else if (test_pos==2) + { + allowed_position.push (sit); + cout << "sit" << sit << endl; + } + else if (test_pos==3) + { + allowed_position.push (inter); + cout << "inter" << inter << endl; + } } - // y-values traditionally use internote dimension - Real upper_y = (qy[upper_i] + interline_f * y_i) / internote_f; - Real lower_y = (qy[lower_i] + interline_f * y_i) / internote_f; + Interval iv = quantise_iv (allowed_position, space, dy_f); + Real quanty_f = dy_f - iv[SMALLER] <= iv[BIGGER] - dy_f ? iv[SMALLER] : iv[BIGGER]; if (extend_b) - left_y_ = (dir_ > 0 ? upper_y : lower_y); - else - left_y_ = (upper_y - left_y_ < y - lower_y ? upper_y : lower_y); + quanty_f = iv[BIGGER]; + + // dim(left_y_) = internote + left_y_ = dir_ * quanty_f / internote_f; } void Beam::set_stemlens () { - Real x0 = stems_[0]->hpos_f (); - Real dy = 0; - - Real interline_f = paper ()->interline_f (); - Real internote_f = interline_f / 2; - Real staffline_thickness = paper ()->rule_thickness (); - Real beam_thickness = 0.48 * (interline_f - staffline_thickness); - Real interbeam_f = paper ()->interbeam_f (); - if (multiple_i_ > 3) - interbeam_f += 2.0 * staffline_thickness / 4; - Real xspan_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); - /* - ugh, y values are in "internote" dimension - */ - Real yspan_f = xspan_f * abs (slope_f_ * internote_f); - int yspan_i = (int)(yspan_f / interline_f); - - Pos left_pos = NONE; + Real staffline_f = paper_l ()->rule_thickness (); + // enge floots + Real epsilon_f = staffline_f / 8; - if ((yspan_f < staffline_thickness / 2) || (quantisation_ == NORMAL)) - left_pos = (Pos)(STRADDLE | SIT | HANG); - else - left_pos = (Pos) (sign (slope_f_) > 0 ? STRADDLE | HANG - : SIT | STRADDLE); - /* - ugh, slope currently mangled by availability mf chars... - be more generous regarding beam position between stafflines - */ - Real q = (yspan_f / interline_f - yspan_i) * interline_f; - if (q < interline_f / 3 - beam_thickness / 2) - left_pos = (Pos) (left_pos | INTER); + // je bent zelf eng --hwn. + Real dy_f = check_stemlengths_f (false); + for (int i = 0; i < 2; i++) + { + left_y_ += dy_f * dir_; + quantise_left_y (dy_f); + dy_f = check_stemlengths_f (true); + if (abs (dy_f) <= epsilon_f) + { + break; + } + } - if (multiple_i_ > 1) - left_pos = (Pos) (dir_ > 0 ? HANG : SIT); + test_pos++; + test_pos %= 4; +} - // ugh, rounding problems! - const Real EPSILON = interline_f / 10; - do - { - left_y_ += dy * dir_; - quantise_left_y (left_pos, dy); - dy = 0; - for (int j=0; j < stems_.size (); j++) +void +Beam::set_beaming (Beaming_info_list *beaming) +{ + Direction d = LEFT; + for (int i=0; i < stems_.size (); i++) + { + do { - Stem *s = stems_[j]; - - Real x = s->hpos_f () - x0; - s->set_stemend (left_y_ + slope_f_ * x); - Real y = s->stem_length_f (); - int mult = max (stems_[j]->beams_left_i_, stems_[j]->beams_right_i_); - if (mult > 1) - // dim(y) = internote - y -= (mult - 1) * interbeam_f / internote_f; - if (y < MINIMUM_STEMLEN[mult]) - dy = dy >? (MINIMUM_STEMLEN[mult] - y); + if (stems_[i]->beams_i_drul_[d] < 0) + stems_[i]->beams_i_drul_[d] = beaming->infos_.elem (i).beams_i_drul_[d]; } - } while (abs (dy) > EPSILON); + while (flip (&d) != LEFT); + } } + void -Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur) +Beam::do_add_processing () { - def.OK (); - cur.OK (); - assert (cur.children.size () == stems_.size ()); - - cur.split (def); - - Array b; - { - Array flags; - for (int j=0; j flag_i_ - 2; - assert (f>0); - flags.push (f); - } - int fi =0; - b= cur.generate_beams (flags, fi); - b.insert (0,0); - b.push (0); - assert (stems_.size () == b.size ()/2); - } - - for (int j=0, i=0; i < b.size () && j beams_left_i_ = b[i]; - s->beams_right_i_ = b[i+1]; - multiple_i_ = multiple_i_ >? (b[i] >? b[i+1]); + Direction d = LEFT; + do { + multiple_i_ = multiple_i_ >? stems_[i]->beams_i_drul_[d]; + } while ((flip (&d)) != LEFT); + } + + if (stems_.size ()) + { + stems_[0]->beams_i_drul_[LEFT] =0; + stems_.top()->beams_i_drul_[RIGHT] =0; } } + + /* beams to go with one stem. */ Molecule Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const { - assert (!next || next->hpos_f () > here->hpos_f ()); - assert (!prev || prev->hpos_f () < here->hpos_f ()); - - Real staffline_thickness = paper ()->rule_thickness (); - Real interbeam_f = paper ()->interbeam_f (); - Real internote_f =paper ()->internote_f (); - Real interline_f = 2 * internote_f; - Real beamheight_f = 0.48 * (interline_f - staffline_thickness); - if (multiple_i_ > 3) - interbeam_f += 2.0 * staffline_thickness / 4; + if ((next && !(next->hpos_f () > here->hpos_f ())) || + (prev && !(prev->hpos_f () < here->hpos_f ()))) + programming_error ("Beams are not left-to-right"); + + Real staffline_f = paper_l ()->rule_thickness (); + Real interbeam_f = paper_l ()->interbeam_f (multiple_i_); + + Real internote_f = here->staff_line_leading_f ()/2; + Real beam_f = paper_l ()->beam_thickness_f (); + Real dy = interbeam_f; - Real stemdx = staffline_thickness; + Real stemdx = staffline_f; Real sl = slope_f_* internote_f; - paper ()->lookup_l ()->beam (sl, 20 PT, 1 PT); + lookup_l ()->beam (sl, 20 PT, 1 PT); Molecule leftbeams; Molecule rightbeams; + // UGH + Real nw_f; + if (!here->head_l_arr_.size ()) + nw_f = 0; + else if (here->type_i ()== 1) + nw_f = paper_l ()->get_var ("wholewidth"); + else if (here->type_i () == 2) + nw_f = paper_l ()->note_width () * 0.8; + else + nw_f = paper_l ()->get_var ("quartwidth"); + /* half beams extending to the left. */ if (prev) { - int lhalfs= lhalfs = here->beams_left_i_ - prev->beams_right_i_ ; - int lwholebeams= here->beams_left_i_ beams_right_i_ ; - Real w = (here->hpos_f () - prev->hpos_f ())/4 note_width ();; - Atom a; + int lhalfs= lhalfs = here->beams_i_drul_[LEFT] - prev->beams_i_drul_[RIGHT] ; + int lwholebeams= here->beams_i_drul_[LEFT] beams_i_drul_[RIGHT] ; + /* + Half beam should be one note-width, + but let's make sure two half-beams never touch + */ + Real w = here->hpos_f () - prev->hpos_f (); + w = w/2 lookup_l ()->beam (sl, w, beamheight_f); + a = lookup_l ()->beam (sl, w, beam_f); a.translate (Offset (-w, -w * sl)); for (int j = 0; j < lhalfs; j++) { - Atom b (a); + Molecule b (a); b.translate_axis (-dir_ * dy * (lwholebeams+j), Y_AXIS); - leftbeams.add (b); + leftbeams.add_molecule (b); } } if (next) { - int rhalfs = here->beams_right_i_ - next->beams_left_i_; - int rwholebeams = here->beams_right_i_ beams_left_i_; + int rhalfs = here->beams_i_drul_[RIGHT] - next->beams_i_drul_[LEFT]; + int rwholebeams = here->beams_i_drul_[RIGHT] beams_i_drul_[LEFT]; Real w = next->hpos_f () - here->hpos_f (); - Atom a = paper ()->lookup_l ()->beam (sl, w + stemdx, beamheight_f); + Molecule a = lookup_l ()->beam (sl, w + stemdx, beam_f); a.translate_axis( - stemdx/2, X_AXIS); int j = 0; Real gap_f = 0; - if (here->beam_gap_i_) + + SCM gap = get_elt_property (beam_gap_scm_sym); + if (gap != SCM_BOOL_F) { - int nogap = rwholebeams - here->beam_gap_i_; + int gap_i = gh_scm2int (SCM_CDR (gap)); + int nogap = rwholebeams - gap_i; + for (; j < nogap; j++) { - Atom b (a); + Molecule b (a); b.translate_axis (-dir_ * dy * j, Y_AXIS); - rightbeams.add (b); + rightbeams.add_molecule (b); } // TODO: notehead widths differ for different types - gap_f = paper ()->note_width () / 2; + gap_f = nw_f / 2; w -= 2 * gap_f; - a = paper ()->lookup_l ()->beam (sl, w + stemdx, beamheight_f); + a = lookup_l ()->beam (sl, w + stemdx, beam_f); } for (; j < rwholebeams; j++) { - Atom b (a); - b.translate (Offset (gap_f, -dir_ * dy * j)); - rightbeams.add (b); + Molecule b (a); + if (!here->invisible_b ()) + b.translate (Offset (gap_f, -dir_ * dy * j)); + else + b.translate (Offset (0, -dir_ * dy * j)); + rightbeams.add_molecule (b); } - w = w/4 note_width (); + w = w/2 lookup_l ()->beam (sl, w, beamheight_f); + a = lookup_l ()->beam (sl, w, beam_f); for (; j < rwholebeams + rhalfs; j++) { - Atom b (a); + Molecule b (a); b.translate_axis (-dir_ * dy * j, Y_AXIS); - rightbeams.add (b); + rightbeams.add_molecule (b); } } - leftbeams.add (rightbeams); + leftbeams.add_molecule (rightbeams); /* Does beam quanting think of the asymetry of beams? Refpoint is on bottom of symbol. (FIXTHAT) --hwn. */ - if (experimental_features_global_b && dir_ < 0) - leftbeams.translate_axis (-beamheight_f, Y_AXIS); return leftbeams; } +