X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fstem.cc;h=2dd984cac7a9f698f915af59a4e7017fcfbb5aa5;hb=abc2e31b608746a1ac924085a87244cc32ee7178;hp=0950ada3717f2839e1929c0f4d9c99fcb63a60bd;hpb=4bdf5f822b18b10b48f619c116641e6aee1968ac;p=lilypond.git diff --git a/lily/stem.cc b/lily/stem.cc index 0950ada371..2dd984cac7 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -1,200 +1,401 @@ +/* + stem.cc -- implement Stem + + source file of the GNU LilyPond music typesetter + + (c) 1996, 1997--1999 Han-Wen Nienhuys + + TODO: This is way too hairy +*/ + #include "stem.hh" -#include "dimen.hh" #include "debug.hh" #include "paper-def.hh" -#include "notehead.hh" +#include "note-head.hh" #include "lookup.hh" #include "molecule.hh" -#include "pcol.hh" +#include "paper-column.hh" #include "misc.hh" +#include "beam.hh" +#include "rest.hh" + +void +Stem::set_direction (Direction d) +{ + if (!dir_) + warning ("Stem direction set already!"); -const int STEMLEN=7; + dir_ = d; + /* + todo + */ +} -Stem::Stem(int c) //, Moment len) +Stem::Stem () { - beams_left = 0; - beams_right = 0; - minnote = 1000; // invalid values - maxnote = -1000; - bot = top = 0; - flag = 4; - dir =0; - staff_center=c; - stemlen=0; - print_flag=true; - stem_xoffset=0; + beams_i_drul_[LEFT] = beams_i_drul_[RIGHT] = -1; + yextent_drul_[DOWN] = yextent_drul_[UP] = 0; + flag_i_ = 2; + dir_ = CENTER; + beam_l_ = 0; +} + +Interval_t +Stem::head_positions () const +{ + /* + Mysterious FreeBSD fix by John Galbraith. Somehow, the empty intervals + trigger FP exceptions on FreeBSD. Fix: do not return infinity + + */ + if (!head_l_arr_.size ()) + { + return Interval_t (100,-100); + } + + Interval_t r; + for (int i =0; i < head_l_arr_.size (); i++) + { + int p = head_l_arr_[i]->position_i_; + r[BIGGER] = r[BIGGER] >? p; + r[SMALLER] = r[SMALLER] = se*dir_) + warning (_ ("weird stem size; check for narrow beams")); + + + yextent_drul_[dir_] = se; + yextent_drul_[Direction(-dir_)] = head_positions()[-dir_]; +} - // todo: margins - if (! ((dir > 0 && se >= maxnote) || (se <= minnote && dir <0)) ) - warning("Weird stem size; check for narrow beams",0); - - top = (dir < 0) ? maxnote : se; - bot = (dir < 0) ? se : minnote; - flag = dir*abs(flag); +int +Stem::type_i () const +{ + return head_l_arr_[0]->balltype_i_; } void -Stem::add(Notehead *n) +Stem::add_head (Rhythmic_head *n) { - assert(status < PRECALCED); - - if (n->balltype == 1) - return; - int p = n->position; - if (p < minnote) - minnote = p; - if (p > maxnote) - maxnote = p; - heads.push(n); - n->add_dependency(this); + n->stem_l_ = this; + n->add_dependency (this); // ? + if (Note_head *nh = dynamic_cast (n)) + { + head_l_arr_.push (nh); + } + else if (Rest *r = dynamic_cast (n)) + { + rest_l_arr_.push (r); + } } +bool +Stem::invisible_b () const +{ + return (!head_l_arr_.size () || + head_l_arr_[0]->balltype_i_ <= 0); +} int -Stem::get_default_dir() +Stem::get_center_distance (Direction d) const { - if (dir) - return dir; - Real mean = (minnote+maxnote)/2; - return (mean > staff_center) ? -1: 1; + int staff_center = 0; + int distance = d*(head_positions()[d] - staff_center); + return distance >? 0; } -void -Stem::set_default_dir() +Direction +Stem::get_default_dir () const { - dir = get_default_dir(); + int du = get_center_distance (UP); + int dd = get_center_distance (DOWN); + + if (sign (dd - du)) + return Direction (sign (dd -du)); + + return Direction (int(paper_l ()->get_var ("stem_default_neutral_direction"))); } +Direction +Stem::get_dir () const +{ + return dir_; +} + + void -Stem::set_default_stemlen() -{ - if (!dir) - set_default_dir(); - - int stafftop = 2*staff_center; - stemlen = STEMLEN + (maxnote - minnote); - - // uhh... how about non 5-line staffs? - if (maxnote < -2 && dir == 1){ - int t = staff_center - staff_center/2; - stemlen = t - minnote +2; - } else if (minnote > stafftop + 2 && dir == -1) { - int t = staff_center + staff_center/2; - stemlen = maxnote -t +2; +Stem::set_default_stemlen () +{ + Real length_f = 0.; + SCM scm_len = get_elt_property(length_scm_sym); + if (scm_len != SCM_BOOL_F) + { + length_f = gh_scm2double (SCM_CDR(scm_len)); } + else + length_f = paper_l ()->get_var ("stem_length0"); + + bool grace_b = get_elt_property (grace_scm_sym) != SCM_BOOL_F; + String type_str = grace_b ? "grace_" : ""; + + Real shorten_f = paper_l ()->get_var (type_str + "forced_stem_shorten0"); + + if (!dir_) + dir_ = get_default_dir (); - assert(stemlen); + /* + stems in unnatural (forced) direction should be shortened, + according to [Roush & Gourlay] + */ + if (((int)chord_start_f ()) + && (dir_ != get_default_dir ())) + length_f -= shorten_f; + + if (flag_i_ >= 5) + length_f += 2.0; + if (flag_i_ >= 6) + length_f += 1.0; + + set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + length_f: + head_positions()[SMALLER] - length_f); + + if (!grace_b && (dir_ * stem_end_f () < 0)) + set_stemend (0); } +//xxx +void +Stem::set_default_extents () +{ + if (!stem_length_f ()) + set_default_stemlen (); + +} void -Stem::set_default_extents() +Stem::set_noteheads () { - if (minnote > maxnote) { - warning("Empty stem. Ugh!", 0); - minnote = -10; - maxnote = 20; - } + if (!head_l_arr_.size ()) + return; + head_l_arr_.sort (Note_head::compare); + if (dir_ < 0) + head_l_arr_.reverse (); - if (!stemlen) - set_default_stemlen(); + Note_head * beginhead = head_l_arr_[0]; + beginhead->set_elt_property (extremal_scm_sym, SCM_BOOL_T); + if (beginhead != head_l_arr_.top ()) + head_l_arr_.top ()->set_elt_property (extremal_scm_sym, SCM_BOOL_T); + + int parity=1; + int lastpos = beginhead->position_i_; + for (int i=1; i < head_l_arr_.size (); i ++) + { + int dy =abs (lastpos- head_l_arr_[i]->position_i_); - set_stemend((dir< 0) ? maxnote-stemlen: minnote +stemlen); - if (dir > 0){ - stem_xoffset = paper()->note_width()-paper()->rule_thickness(); - } else - stem_xoffset = 0; + if (dy <= 1) + { + if (parity) + head_l_arr_[i]->flip_around_stem (dir_); + parity = !parity; + } + else + parity = 1; + lastpos = head_l_arr_[i]->position_i_; + } } void -Stem::set_noteheads() -{ - if(!heads.size()) - return; - heads.sort(Notehead::compare); - heads[0]->extremal = -1; - heads.top()->extremal = 1; - int parity=1; - int lastpos = heads[0]->position; - for (int i=1; i < heads.size(); i ++) { - int dy =abs(lastpos- heads[i]->position); - - if (dy <= 1) { - if (parity) - heads[i]->x_dir = (stem_xoffset>0) ? 1:-1; - parity = !parity; - } else - parity = 0; - lastpos = heads[i]->position; +Stem::do_pre_processing () +{ + if (yextent_drul_[DOWN]== yextent_drul_[UP]) + set_default_extents (); + set_noteheads (); + + if (invisible_b ()) + { + set_elt_property (transparent_scm_sym, SCM_BOOL_T); } + set_empty (invisible_b ()); + set_spacing_hints (); } + + +/** + set stem directions for hinting the optical spacing correction. + + Modifies DIR_LIST property of the Stem's Score_column + + TODO: more advanced: supply height of noteheads as well, for more advanced spacing possibilities + */ void -Stem::do_pre_processing() +Stem::set_spacing_hints () { - if (bot == top) - set_default_extents(); - set_noteheads(); + if (!invisible_b ()) + { + SCM scmdir = gh_int2scm (dir_); + SCM dirlist = column_l ()->get_elt_property (dir_list_scm_sym); + if (dirlist == SCM_BOOL_F) + dirlist = SCM_EOL; + else + dirlist = SCM_CDR (dirlist); + + if (scm_sloppy_memq (scmdir, dirlist) == SCM_EOL) + { + dirlist = gh_cons (scmdir, dirlist); + column_l ()->set_elt_property (dir_list_scm_sym, dirlist); + } + } } +Molecule +Stem::flag () const +{ + String style; + SCM st = get_elt_property (style_scm_sym); + if ( st != SCM_BOOL_F) + { + st = SCM_CDR(st); + style = ly_scm2string (st); + } + + char c = (dir_ == UP) ? 'u' : 'd'; + Molecule m = lookup_l ()->afm_find (String ("flags-") + to_str (c) + + to_str (flag_i_)); + if (!style.empty_b ()) + m.add_molecule(lookup_l ()->afm_find (String ("flags-") + to_str (c) + style)); + return m; +} Interval -Stem::width()const +Stem::do_width () const { - if (!print_flag || abs(flag) <= 4) - return Interval(0,0); // TODO! - Paper_def*p= paper(); - Interval r(p->lookup_l()->flag(flag).dim.x); - r+= stem_xoffset; - return r; + Interval r (0, 0); + if (beam_l_ || abs (flag_i_) <= 2) + ; // TODO! + else + { + r = flag ().dim_.x (); + r += note_delta_f (); + } + return r; } + + + +const Real ANGLE = 20* (2.0*M_PI/360.0); // ugh! + Molecule* -Stem::brew_molecule_p()const return out; -{ - assert(bot!=top); - - - Paper_def *p =paper(); - - Real dy = p->internote(); - Symbol ss =p->lookup_l()->stem(bot*dy,top*dy); - - - out = new Molecule(Atom(ss)); - - if (print_flag&&abs(flag) > 4){ - Symbol fl = p->lookup_l()->flag(flag); - Molecule m(fl); - if (flag < -4){ - out->add_bottom(m); - } else if (flag > 4) { - out->add_top(m); - } else - assert(false); +Stem::do_brew_molecule_p () const +{ + Molecule *mol_p =new Molecule; + Drul_array stem_y = yextent_drul_; + Real dy = staff_line_leading_f ()/2.0; + + Real head_wid = 0; + if (head_l_arr_.size ()) + head_wid = head_l_arr_[0]->extent (X_AXIS).length (); + stem_y[Direction(-dir_)] += dir_ * head_wid * tan(ANGLE)/(2*dy); + + if (!invisible_b ()) + { + Real stem_width = paper_l ()->get_var ("stemthickness"); + Molecule ss =lookup_l ()->filledbox (Box (Interval (-stem_width/2, stem_width/2), + Interval (stem_y[DOWN]*dy, stem_y[UP]*dy))); + mol_p->add_molecule (ss); } - out->translate(Offset(stem_xoffset,0)); + if (!beam_l_ && abs (flag_i_) > 2) + { + Molecule fl = flag (); + fl.translate_axis(stem_y[dir_]*dy, Y_AXIS); + mol_p->add_molecule (fl); + } + + if (head_l_arr_.size()) + { + mol_p->translate_axis (note_delta_f (), X_AXIS); + } + return mol_p; } Real -Stem::hindex()const +Stem::note_delta_f () const { - return pcol_l_->hpos + stem_xoffset; // hmm. + offset_.x; + Real r=0; + if (head_l_arr_.size()) + { + Interval head_wid(0, head_l_arr_[0]->extent (X_AXIS).length ()); + Real rule_thick(paper_l ()->rule_thickness ()); + Interval stem_wid(-rule_thick/2, rule_thick/2); + if (dir_ == CENTER) + r = head_wid.center (); + else + r = head_wid[dir_] - stem_wid[dir_]; + } + return r; } +Real +Stem::hpos_f () const +{ + return note_delta_f () + Item::hpos_f (); +} +void +Stem::do_substitute_element_pointer (Score_element*o,Score_element*n) +{ + if (Note_head*h=dynamic_cast (o)) + head_l_arr_.substitute (h, dynamic_cast(n)); + if (Rest *r=dynamic_cast (o)) + rest_l_arr_.substitute (r, dynamic_cast(n)); + if (Beam* b = dynamic_cast (o)) + { + if (b == beam_l_) + beam_l_ = dynamic_cast (n); + } + Staff_symbol_referencer::do_substitute_element_pointer (o,n); +}