X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=c6ae9c7f896ec8964d66385df1b065e17f0a12b2;hb=670a98f23a2561c6a4a4a19bb72c776189715541;hp=f365889c4fa9ec8c2ff69997166dd38a781143b5;hpb=8ff3ecdb5f5b662e6849ff08b4e2f90bdcf4f8ca;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index f365889c4f..c6ae9c7f89 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -3,7 +3,7 @@ source file of the GNU LilyPond music typesetter - (c) 1997--1998, 1998 Han-Wen Nienhuys + (c) 1997--1999, 1998 Han-Wen Nienhuys Jan Nieuwenhuizen */ @@ -11,39 +11,35 @@ /* [TODO] - * centre beam symbol + * 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 "array.hh" #include "proto.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 "rhythmic-grouping.hh" Beam::Beam () { slope_f_ = 0; - solved_slope_f_ = 0; left_y_ = 0; - damping_i_ = 1; quantisation_ = NORMAL; multiple_i_ = 0; } @@ -51,8 +47,16 @@ Beam::Beam () void Beam::add_stem (Stem*s) { +#if 0 + if (!stems_.size ()) + { + dim_cache_[Y_AXIS]->parent_l_ = s->dim_cache_[Y_AXIS]; + } +#endif stems_.push (s); s->add_dependency (this); + + assert (!s->beam_l_); s->beam_l_ = this; if (!spanned_drul_[LEFT]) @@ -61,12 +65,26 @@ Beam::add_stem (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::do_brew_molecule_p () const { Molecule *mol_p = new Molecule; - Real internote_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_) * internote_f)); + 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 @@ -88,15 +107,21 @@ Beam::do_brew_molecule_p () const Offset Beam::center () const { - Real w= (paper ()->note_width () + extent (X_AXIS).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); } void Beam::do_pre_processing () { if (!dir_) - set_default_dir (); + dir_ = get_default_dir (); + + + set_direction (dir_); } void @@ -114,15 +139,15 @@ Beam::do_post_processing () if (stems_.size () < 2) { warning (_ ("beam with less than two stems")); - transparent_b_ = true; + set_elt_property (transparent_scm_sym, SCM_BOOL_T); return ; } - solve_slope (); + calculate_slope (); set_stemlens (); } void -Beam::do_substitute_dependent (Score_element*o,Score_element*n) +Beam::do_substitute_element_pointer (Score_element*o,Score_element*n) { if (Stem * os = dynamic_cast (o)) stems_.substitute (os, @@ -136,15 +161,16 @@ 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; - + + Direction beamdir; for (int i=0; i get_var ("beam_dir_algorithm")); + Dir_algorithm a = (Dir_algorithm)rint(paper_l ()->get_var ("beam_dir_algorithm")); switch (a) { case MAJORITY: - dir_ = (count[UP] > count[DOWN]) ? UP : DOWN; + beamdir = (count[UP] > count[DOWN]) ? UP : DOWN; break; case MEAN: - // mean centre distance - dir_ = (total[UP] > total[DOWN]) ? UP : DOWN; + // mean center distance + beamdir = (total[UP] > total[DOWN]) ? UP : DOWN; break; default: case MEDIAN: - // median centre distance + // median center distance if (!count[UP]) - dir_ = DOWN; + beamdir = DOWN; else if (!count[DOWN]) - dir_ = UP; + beamdir = UP; else - dir_ = (total[UP] / count[UP] > total[DOWN] / count[DOWN]) ? UP : DOWN; + beamdir = (total[UP] / count[UP] > total[DOWN] / count[DOWN]) ? UP : DOWN; break; } + return beamdir; +} +void +Beam::set_direction (Direction d) +{ + dir_ = d; for (int i=0; i beam_dir_ = dir_; - if (!s->dir_forced_b_) - s->dir_ = dir_; + 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; } } /* See Documentation/tex/fonts.doc */ + void Beam::solve_slope () { - /* - should use minimum energy formulation (cf linespacing) - */ - - assert (multiple_i_); - Array sinfo; + assert (sinfo_.size () > 1); DOUT << "Beam::solve_slope: \n"; - for (int j=0; j mult_i_ = multiple_i_; - 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 - { - Real leftx = sinfo[0].x_; - Least_squares l; - for (int i=0; i < sinfo.size (); i++) - { - sinfo[i].x_ -= leftx; - l.input.push (Offset (sinfo[i].x_, sinfo[i].idealy_f_)); - } - - l.minimise (slope_f_, left_y_); + 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_); - solved_slope_f_ = dir_ * slope_f_; + 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_; - /* - 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_; + // correct for knee + if (dir_ != sinfo_[i].dir_) + { + 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; + } - /* - [TODO] - think + 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; +} - dropping lq for stemlengths solves [d d d] [d g d] "bug..." +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++) + { + Stem *s = stems_[i]; - but may be a bit too crude, and result in lots of - too high beams... + 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++; + } - perhaps only if slope = 0 ? - */ + 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_ invisible_b ()) + continue; -// left_y_ = sinfo[0].minyf_; + 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); + } +} - if (sinfo.size () >= 1) +void +Beam::calculate_slope () +{ + set_steminfo (); + if (!sinfo_.size ()) + slope_f_ = left_y_ = 0; + else if (sinfo_[0].idealy_f_ == sinfo_.top ().idealy_f_) { - Real staffline_f = paper ()->rule_thickness (); - Real epsilon_f = staffline_f / 8; - if (abs (slope_f_) < epsilon_f) - left_y_ = (sinfo[0].idealy_f_ + sinfo.top ().idealy_f_) / 2; - else - /* - symmetrical, but results often in having stemlength = minimal - - left_y_ = sinfo[0].dir_ == dir_ ? sinfo[0].miny_f_ : sinfo[0].maxy_f_; + slope_f_ = 0; + left_y_ = sinfo_[0].idealy_f_; + left_y_ *= dir_; + } + else + { + solve_slope (); + Real solved_slope_f = slope_f_; - what about - */ + /* + 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))) { - Real dx = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); - if (sinfo[0].dir_ == sinfo.top ().dir_) - left_y_ = sinfo[0].idealy_f_ >? sinfo.top ().idealy_f_ - slope_f_ * dx; - // knee - else - left_y_ = sinfo[0].idealy_f_; + slope_f_ = 0; } - } - // uh? - Real dy = 0.0; - for (int i=0; i < sinfo.size (); i++) - { - Real y = sinfo[i].x_ * slope_f_ + left_y_; - Real my = sinfo[i].miny_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 (); - if (my - y > dy) - dy = my -y; - } - left_y_ += dy; - left_y_ *= dir_; - slope_f_ *= dir_; + Real damped_slope_dy_f = (solved_slope_f - slope_f_) * dx_f / 2; + left_y_ += damped_slope_dy_f; - quantise_dy (); + left_y_ *= dir_; + slope_f_ *= dir_; + } } void @@ -338,10 +421,10 @@ Beam::quantise_dy () 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_f = paper ()->rule_thickness (); - Real beam_f = paper ()->beam_thickness_f (); + 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 (); @@ -358,9 +441,9 @@ Beam::quantise_dy () Interval iv = quantise_iv (allowed_fraction, interline_f, dy_f); - quanty_f = (dy_f - iv.min () <= iv.max () - dy_f) - ? iv.min () - : iv.max (); + 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_); @@ -396,10 +479,10 @@ Beam::quantise_left_y (bool extend_b) hang straddle sit inter hang */ - Real interline_f = paper ()->interline_f (); - Real internote_f = paper ()->internote_f (); - Real staffline_f = paper ()->rule_thickness (); - Real beam_f = paper ()->beam_thickness_f (); + 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] @@ -409,8 +492,8 @@ Beam::quantise_left_y (bool extend_b) Real straddle = 0; Real sit = beam_f / 2 - staffline_f / 2; - Real inter = interline_f / 2; - Real hang = interline_f - 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. @@ -454,7 +537,7 @@ Beam::quantise_left_y (bool extend_b) if (test_pos == 0) { allowed_position.push (hang); - cout << "hang" << hang << endl; + cout << "hang" << hang << "\n"; } else if (test_pos==1) { @@ -473,18 +556,11 @@ Beam::quantise_left_y (bool extend_b) } } -#if 0 - // this currently never happens - Real q = (dy_f / interline_f - dy_i) * interline_f; - if ((quantisation_ < NORMAL) && (q < interline_f / 3 - beam_f / 2)) - allowed_position.push (inter); -#endif - - Interval iv = quantise_iv (allowed_position, interline_f, dy_f); + Interval iv = quantise_iv (allowed_position, space, dy_f); - Real quanty_f = dy_f - iv.min () <= iv.max () - dy_f ? iv.min () : iv.max (); + Real quanty_f = dy_f - iv[SMALLER] <= iv[BIGGER] - dy_f ? iv[SMALLER] : iv[BIGGER]; if (extend_b) - quanty_f = iv.max (); + quanty_f = iv[BIGGER]; // dim(left_y_) = internote left_y_ = dir_ * quanty_f / internote_f; @@ -493,89 +569,18 @@ Beam::quantise_left_y (bool extend_b) void Beam::set_stemlens () { - Real staffline_f = paper ()->rule_thickness (); - Real interbeam_f = paper ()->interbeam_f (multiple_i_); - Real internote_f = paper ()->internote_f (); - Real beam_f = paper ()->beam_thickness_f (); - + Real staffline_f = paper_l ()->rule_thickness (); // enge floots Real epsilon_f = staffline_f / 8; - /* - - Damped and quantised slopes, esp. in monotone scales such as - - [c d e f g a b c] - - will soon produce the minimal stem-length for one of the extreme - stems, which is wrong (and ugly). The minimum stemlength should - be kept rather small, in order to handle extreme beaming, such as - - [c c' 'c] %assuming no knee - - correctly. - To avoid these short stems for normal cases, we'll correct for - the loss in slope, if necessary. - - [TODO] - ugh, another hack. who's next? - Writing this all down, i realise (at last) that the Right Thing to - do is to assign uglyness to slope and stem-lengths and then minimise - the total uglyness of a beam. - Steep slopes are ugly, shortened stems are ugly, lengthened stems - are ugly. - How to do this? - - */ - - Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f (); - Real damp_correct_f = paper ()->get_var ("beam_slope_damp_correct_factor"); - Real damped_slope_dy_f = (solved_slope_f_ - slope_f_) * dx_f - * sign (slope_f_); - damped_slope_dy_f *= damp_correct_f; - if (damped_slope_dy_f <= epsilon_f) - damped_slope_dy_f = 0; - - DOUT << "Beam::set_stemlens: \n"; - Real x0 = stems_[0]->hpos_f (); - Real dy_f = 0; - // urg - for (int jj = 0; jj < 10; jj++) + 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 = 0; - for (int i=0; i < stems_.size (); i++) - { - Stem *s = stems_[i]; - if (s->transparent_b_) - continue; - - Real x = s->hpos_f () - x0; - // urg move this to stem-info - Real sy = left_y_ + slope_f_ * x; - if (dir_ != s->dir_) - sy -= dir_ * (beam_f / 2 - + (s->mult_i_ - 1) * interbeam_f) / internote_f; - s->set_stemend (sy); - Real y = s->stem_end_f () * dir_; - Stem_info info (s); - if (y > info.maxy_f_) - dy_f = dy_f ? info.miny_f_ - y; - } - } - if (damped_slope_dy_f && (dy_f >= 0)) - dy_f += damped_slope_dy_f; - damped_slope_dy_f = 0; + dy_f = check_stemlengths_f (true); if (abs (dy_f) <= epsilon_f) { - DOUT << "Beam::set_stemlens: " << jj << " iterations\n"; break; } } @@ -636,13 +641,15 @@ Beam::set_grouping (Rhythmic_grouping def, Rhythmic_grouping cur) 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 ()); + 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 staffline_f = paper ()->rule_thickness (); - Real interbeam_f = paper ()->interbeam_f (multiple_i_); - Real internote_f = paper ()->internote_f (); - Real beam_f = paper ()->beam_thickness_f (); + Real internote_f = here->staff_line_leading_f ()/2; + Real beam_f = paper_l ()->beam_thickness_f (); Real dy = interbeam_f; Real stemdx = staffline_f; @@ -653,7 +660,7 @@ Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const Molecule rightbeams; // UGH - Real nw_f = paper ()->note_width () * 0.8; + Real nw_f = paper_l ()->note_width () * 0.8; /* half beams extending to the left. */ if (prev) @@ -666,15 +673,15 @@ Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const */ Real w = here->hpos_f () - prev->hpos_f (); w = w/2 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_atom (b); + leftbeams.add_molecule (b); } } @@ -684,18 +691,22 @@ Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const int rwholebeams = here->beams_i_drul_[RIGHT] beams_i_drul_[LEFT]; Real w = next->hpos_f () - here->hpos_f (); - Atom a = lookup_l ()->beam (sl, w + stemdx, beam_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 (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_atom (b); + rightbeams.add_molecule (b); } // TODO: notehead widths differ for different types gap_f = nw_f / 2; @@ -705,9 +716,9 @@ Beam::stem_beams (Stem *here, Stem *next, Stem *prev) const for (; j < rwholebeams; j++) { - Atom b (a); + Molecule b (a); b.translate (Offset (gap_f, -dir_ * dy * j)); - rightbeams.add_atom (b); + rightbeams.add_molecule (b); } w = w/2