X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=48c81d14cf764266d1db2665f99b643dbf370376;hb=9f20df172e374793d1813882e3a793df6cd24673;hp=10bf8d82e8f3e3878f0eeb3822a54c4b45ff9421;hpb=ce9845392e4e22ae9c5f6ec1da914eb301f1892c;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 10bf8d82e8..48c81d14cf 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -3,24 +3,24 @@ source file of the GNU LilyPond music typesetter - (c) 1997--2000 Han-Wen Nienhuys + (c) 1997--2001 Han-Wen Nienhuys Jan Nieuwenhuizen */ /* [TODO] - * shorter! (now +- 1000 lines) - * less hairy code - * move paper vars to scm - remove *-hs variables, and do all y-position stuff in staff-space. -*/ + -* shorter! (now +- 1000 lines) + + -* less hairy code + + */ #include // tanh. - +#include "molecule.hh" #include "directional-element-interface.hh" #include "beaming.hh" #include "beam.hh" @@ -31,32 +31,30 @@ #include "lookup.hh" #include "group-interface.hh" #include "staff-symbol-referencer.hh" -#include "cross-staff.hh" #include "item.hh" #include "spanner.hh" #include "warn.hh" void -Beam::add_stem (Score_element*me, Score_element*s) +Beam::add_stem (Grob*me, Grob*s) { - Pointer_group_interface gi (me, "stems"); - gi.add_element (s); + Pointer_group_interface:: add_element (me, "stems", s); s->add_dependency (me); assert (!Stem::beam_l (s)); - s->set_elt_property ("beam", me->self_scm ()); + s->set_grob_property ("beam", me->self_scm ()); add_bound_item (dynamic_cast (me), dynamic_cast (s)); } int -Beam::get_multiplicity (Score_element*me) +Beam::get_multiplicity (Grob*me) { int m = 0; - for (SCM s = me->get_elt_property ("stems"); gh_pair_p (s); s = gh_cdr (s)) + for (SCM s = me->get_grob_property ("stems"); gh_pair_p (s); s = gh_cdr (s)) { - Score_element * sc = unsmob_element (gh_car (s)); + Grob * sc = unsmob_grob (gh_car (s)); if (Stem::has_interface (sc)) m = m >? Stem::beam_count (sc,LEFT) >? Stem::beam_count (sc,RIGHT); @@ -72,30 +70,35 @@ Beam::get_multiplicity (Score_element*me) [Alternatively, stems could set its own directions, according to their beam, during 'final-pre-processing'.] */ -MAKE_SCHEME_CALLBACK(Beam,before_line_breaking); +MAKE_SCHEME_CALLBACK (Beam,before_line_breaking,1); SCM Beam::before_line_breaking (SCM smob) { - Score_element * me = unsmob_element (smob); + Grob * me = unsmob_grob (smob); // Why? + /* + Why what? Why the warning (beams with less than 2 stems are + degenerate beams, should never happen), or why would this ever + happen (don't know). */ if (visible_stem_count (me) < 2) { warning (_ ("beam has less than two stems")); } - - if (!Directional_element_interface::get (me)) - Directional_element_interface::set (me, get_default_dir (me)); - - auto_knees (me); - set_stem_directions (me); - set_stem_shorten (me); - + if (visible_stem_count (me) >= 1) + { + if (!Directional_element_interface::get (me)) + Directional_element_interface::set (me, get_default_dir (me)); + + consider_auto_knees (me); + set_stem_directions (me); + set_stem_shorten (me); + } return SCM_EOL; } Direction -Beam::get_default_dir (Score_element*me) +Beam::get_default_dir (Grob*me) { Drul_array total; total[UP] = total[DOWN] = 0; @@ -107,8 +110,8 @@ Beam::get_default_dir (Score_element*me) Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); for (int i=0; i get_elt_property ("dir-function"); + SCM func = me->get_grob_property ("dir-function"); SCM s = gh_call2 (func, gh_cons (gh_int2scm (count[UP]), gh_int2scm (count[DOWN])), @@ -134,7 +137,7 @@ Beam::get_default_dir (Score_element*me) /* If dir is not determined: get default */ - return to_dir (me->get_elt_property ("default-neutral-direction")); + return to_dir (me->get_grob_property ("neutral-direction")); } @@ -144,81 +147,89 @@ Beam::get_default_dir (Score_element*me) once stem gets cleaned-up. */ void -Beam::set_stem_directions (Score_element*me) +Beam::set_stem_directions (Grob*me) { Link_array stems - =Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); + =Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); Direction d = Directional_element_interface::get (me); for (int i=0; i remove_elt_property ("dir-forced"); + Grob *s = stems[i]; + SCM force = s->remove_grob_property ("dir-forced"); if (!gh_boolean_p (force) || !gh_scm2bool (force)) Directional_element_interface ::set (s,d); } } -void -Beam::auto_knees (Score_element*me) -{ - if (!auto_knee (me,"auto-interstaff-knee-gap", true)) - auto_knee (me, "auto-knee-gap", false); -} - /* Simplistic auto-knees; only consider vertical gap between two adjacent chords. `Forced' stem directions are ignored. If you don't want auto-knees, - don't set, or unset autoKneeGap/autoInterstaffKneeGap. + don't set, or unset auto-knee-gap. */ -bool -Beam::auto_knee (Score_element*me, String gap_str, bool interstaff_b) +void +Beam::consider_auto_knees (Grob *me) { - bool knee_b = false; - int knee_y = 0; - SCM gap = me->get_elt_property (gap_str.ch_C()); + SCM scm = me->get_grob_property ("auto-knee-gap"); - Direction d = Directional_element_interface::get (me); + if (gh_number_p (scm)) + { + bool knee_b = false; + Real knee_y = 0; + Real staff_space = Staff_symbol_referencer::staff_space (me); + Real gap = gh_scm2double (scm) / staff_space; + + Direction d = Directional_element_interface::get (me); Link_array stems= Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); - - if (gh_number_p (gap)) - { - Spanner*sp = dynamic_cast (me); - int auto_gap_i = gh_scm2int (gap); + + Grob *common = me->common_refpoint (stems[0], Y_AXIS); + for (int i=1; i < stems.size (); i++) + if (!Stem::invisible_b (stems[i])) + common = common->common_refpoint (stems[i], Y_AXIS); + + int l = 0; for (int i=1; i < stems.size (); i++) { - bool is_b = (bool)(calc_interstaff_dist (stems[i], sp) - - calc_interstaff_dist (stems[i-1], sp)); - int l_y = (int)(Stem::head_positions(stems[i-1])[d]) - + (int)calc_interstaff_dist (stems[i-1], sp); - int r_y = (int)(Stem::head_positions(stems[i])[d]) - + (int)calc_interstaff_dist (stems[i], sp); - int gap_i = r_y - l_y; - - if ((abs (gap_i) >= auto_gap_i) && (!interstaff_b || is_b)) + if (!Stem::invisible_b (stems[i-1])) + l = i - 1; + if (Stem::invisible_b (stems[l])) + continue; + if (Stem::invisible_b (stems[i])) + continue; + + Real left = Stem::extremal_heads (stems[l])[d] + ->relative_coordinate (common, Y_AXIS); + Real right = Stem::extremal_heads (stems[i])[-d] + ->relative_coordinate (common, Y_AXIS); + + Real dy = right - left; + + if (abs (dy) >= gap) { - knee_y = (r_y + l_y) / 2; + knee_y = (right + left) / 2; knee_b = true; break; } } - } - if (knee_b) - { - for (int i=0; i < stems.size (); i++) - { - Item *s = stems[i]; - int y = (int)(Stem::head_positions(s)[d]) - + (int)calc_interstaff_dist (s, dynamic_cast (me)); - - Directional_element_interface::set (s,y < knee_y ? UP : DOWN); - s->set_elt_property ("dir-forced", SCM_BOOL_T); + + if (knee_b) + { + for (int i=0; i < stems.size (); i++) + { + if (Stem::invisible_b (stems[i])) + continue; + Item *s = stems[i]; + Real y = Stem::extremal_heads (stems[i])[d] + ->relative_coordinate (common, Y_AXIS); + + Directional_element_interface::set (s, y < knee_y ? UP : DOWN); + s->set_grob_property ("dir-forced", SCM_BOOL_T); + } } } - return knee_b; } /* @@ -228,11 +239,9 @@ Beam::auto_knee (Score_element*me, String gap_str, bool interstaff_b) scmify forced-fraction */ void -Beam::set_stem_shorten (Score_element*m) +Beam::set_stem_shorten (Grob*m) { Spanner*me = dynamic_cast (m); - if (!visible_stem_count (me)) - return; Real forced_fraction = forced_stem_count (me) / visible_stem_count (me); if (forced_fraction < 0.5) @@ -240,7 +249,7 @@ Beam::set_stem_shorten (Score_element*m) int multiplicity = get_multiplicity (me); - SCM shorten = me->get_elt_property ("beamed-stem-shorten"); + SCM shorten = me->get_grob_property ("beamed-stem-shorten"); if (shorten == SCM_EOL) return; @@ -262,157 +271,133 @@ Beam::set_stem_shorten (Score_element*m) Item* s = stems[i]; if (Stem::invisible_b (s)) continue; - if (gh_number_p (s->get_elt_property ("shorten"))) - s->set_elt_property ("shorten", gh_double2scm (shorten_f)); + if (gh_number_p (s->get_grob_property ("shorten"))) + s->set_grob_property ("shorten", gh_double2scm (shorten_f)); } } /* - Set elt properties height and y-position if not set. - Adjust stem lengths to reach beam. + Call list of y-dy-callbacks, that handle setting of + grob-properties y, dy. + + User may set grob-properties: y-position-hs and height-hs + (to be fixed) that override the calculated y and dy. + + Because y and dy cannot be calculated and quanted separately, we + always calculate both, then check for user override. */ -MAKE_SCHEME_CALLBACK(Beam,after_line_breaking); +MAKE_SCHEME_CALLBACK (Beam, after_line_breaking, 1); SCM Beam::after_line_breaking (SCM smob) { - Score_element * me = unsmob_element (smob); - - /* first, calculate y, dy */ - Real y, dy; - calc_default_position_and_height (me, &y, &dy); - if (visible_stem_count (me)) - { - if (suspect_slope_b (me, y, dy)) - dy = 0; - - Real damped_dy = calc_slope_damping_f (me, dy); - Real quantised_dy = quantise_dy_f (me, damped_dy); - - y += (dy - quantised_dy) / 2; - dy = quantised_dy; - } - /* - until here, we used only stem_info, which acts as if dir=up - */ - y *= Directional_element_interface::get (me); - dy *= Directional_element_interface::get (me); - - - Real half_space = Staff_symbol_referencer::staff_space (me) / 2; - - /* weird: why do we do calc_position_and_height () ? regardless of - this setting? - - */ - /* check for user-override of dy */ - SCM s = me->remove_elt_property ("height-hs"); - if (gh_number_p (s)) - { - dy = gh_scm2double (s) * half_space; - } - me->set_elt_property ("height", gh_double2scm (dy)); + Grob * me = unsmob_grob (smob); + + me->set_grob_property ("y", gh_double2scm (0)); + me->set_grob_property ("dy", gh_double2scm (0)); - /* check for user-override of y */ - s = me->remove_elt_property ("y-position-hs"); - if (gh_number_p (s)) - { - y = gh_scm2double (s) * half_space; - } - else - { - /* we can modify y, so we should quantise y */ - Real y_shift = check_stem_length_f (me, y, dy); - y += y_shift; - y = quantise_y_f (me,y, dy, 0); - set_stem_length (me, y, dy); - y_shift = check_stem_length_f (me, y, dy); + /* Hmm, callbacks should be called by, a eh, callback mechanism + somewhere (?), I guess, not by looping here. */ + + SCM list = me->get_grob_property ("y-dy-callbacks"); + for (SCM i = list; gh_pair_p (i); i = gh_cdr (i)) + gh_call1 (gh_car (i), smob); - if (y_shift > half_space / 4) - { - y += y_shift; - - /* - for significantly lengthened or shortened stems, - request quanting the other way. - */ - int quant_dir = 0; - if (abs (y_shift) > half_space / 2) - quant_dir = sign (y_shift) * Directional_element_interface::get (me); - y = quantise_y_f (me, y, dy, quant_dir); - } - } // UGH. Y is not in staff position unit? // Ik dacht datwe daar juist van weg wilden? - set_stem_length (me, y, dy); - me->set_elt_property ("y-position", gh_double2scm (y)); + + // Hmm, nu hebben we 3 dimensies, want inmiddels zijn we daar + // weer terug, maar dan / 2 + // (staff-space iso staff-position) + + set_stem_lengths (me); return SCM_UNSPECIFIED; } -/* - See Documentation/tex/fonts.doc - */ -void -Beam::calc_default_position_and_height (Score_element*me,Real* y, Real* dy) + +MAKE_SCHEME_CALLBACK (Beam, least_squares, 1); +SCM +Beam::least_squares (SCM smob) { - *y = 0; - *dy = 0; - if (visible_stem_count (me) <= 1) - return; + Grob *me = unsmob_grob (smob); + + if (visible_stem_count (me) <= 1) + return SCM_UNSPECIFIED; + Real y = 0; + Real dy = 0; + + /* Stem_info, and thus y,dy in this function are corrected for beam-dir */ Real first_ideal = Stem::calc_stem_info (first_visible_stem (me)).idealy_f_; if (first_ideal == Stem::calc_stem_info (last_visible_stem (me)).idealy_f_) { - *dy = 0; - *y = first_ideal; - return; + y = first_ideal; + dy = 0; } + else + { + Array ideals; - Array ideals; + // ugh -> use commonx + Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); + Link_array stems= + Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); - // ugh -> use commonx - Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); - Link_array stems= - Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); + for (int i=0; i < stems.size (); i++) + { + Item* s = stems[i]; + if (Stem::invisible_b (s)) + continue; + ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0, + Stem::calc_stem_info (s).idealy_f_)); + } + Real dydx; + minimise_least_squares (&dydx, &y, ideals); - for (int i=0; i < stems.size (); i++) - { - Item* s = stems[i]; - if (Stem::invisible_b (s)) - continue; - ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0, - Stem::calc_stem_info (s).idealy_f_)); + Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0; + dy = dydx * dx; } - Real dydx; - minimise_least_squares (&dydx, y, ideals); // duh, takes references - Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0; - *dy = dydx * dx; + /* Store true, not dir-corrected values */ + Direction dir = Directional_element_interface::get (me); + me->set_grob_property ("y", gh_double2scm (y * dir)); + me->set_grob_property ("dy", gh_double2scm (dy * dir)); + return SCM_UNSPECIFIED; } -bool -Beam::suspect_slope_b (Score_element*me, Real y, Real dy) +MAKE_SCHEME_CALLBACK (Beam, cancel_suspect_slope, 1); +SCM +Beam::cancel_suspect_slope (SCM smob) { - /* first, calculate y, dy */ - /* - steep slope running against lengthened stem is suspect - */ - Real ss = me->paper_l ()->get_var ("staffspace"); + Grob *me = unsmob_grob (smob); + + if (visible_stem_count (me) <= 1) + return SCM_UNSPECIFIED; + + /* Stem_info, and thus y,dy in this function are corrected for beam-dir */ + Direction dir = Directional_element_interface::get (me); + Real y = gh_scm2double (me->get_grob_property ("y")) * dir; + Real dy = gh_scm2double (me->get_grob_property ("dy")) * dir; + + /* steep slope running against lengthened stem is suspect */ Real first_ideal = Stem::calc_stem_info (first_visible_stem (me)).idealy_f_; Real last_ideal = Stem::calc_stem_info (last_visible_stem (me)).idealy_f_; - Real lengthened = gh_scm2double (me->get_elt_property ("outer-stem-length-limit")) * ss; - Real steep = gh_scm2double (me->get_elt_property ("slope-limit")); + Real lengthened = gh_scm2double (me->get_grob_property ("outer-stem-length-limit")); + Real steep = gh_scm2double (me->get_grob_property ("slope-limit")); // ugh -> use commonx Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - first_visible_stem (me)->relative_coordinate (0, X_AXIS); Real dydx = dy && dx ? dy/dx : 0; - if (((y - first_ideal > lengthened) && (dydx > steep)) + if (( (y - first_ideal > lengthened) && (dydx > steep)) || ((y + dy - last_ideal > lengthened) && (dydx < -steep))) { - return true; + Real adjusted_y = y + dy / 2; + /* Store true, not dir-corrected values */ + me->set_grob_property ("y", gh_double2scm (adjusted_y * dir)); + me->set_grob_property ("dy", gh_double2scm (0)); } - return false; + return SCM_UNSPECIFIED; } /* @@ -420,37 +405,179 @@ Beam::suspect_slope_b (Score_element*me, Real y, Real dy) damped = tanh (slope) corresponds with some tables in [Wanske] */ -Real -Beam::calc_slope_damping_f (Score_element*me,Real dy) +MAKE_SCHEME_CALLBACK (Beam, slope_damping, 1); +SCM +Beam::slope_damping (SCM smob) { - SCM damp = me->get_elt_property ("damping"); - int damping = gh_scm2int (damp); + Grob *me = unsmob_grob (smob); + + if (visible_stem_count (me) <= 1) + return SCM_UNSPECIFIED; + + SCM s = me->get_grob_property ("damping"); + int damping = gh_scm2int (s); if (damping) { - // ugh -> use commonx + /* y,dy in this function are corrected for beam-dir */ + Direction dir = Directional_element_interface::get (me); + Real y = gh_scm2double (me->get_grob_property ("y")) * dir; + Real dy = gh_scm2double (me->get_grob_property ("dy")) * dir; + + // ugh -> use commonx Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - first_visible_stem (me)->relative_coordinate (0, X_AXIS); Real dydx = dy && dx ? dy/dx : 0; dydx = 0.6 * tanh (dydx) / damping; - return dydx * dx; + + Real damped_dy = dydx * dx; + Real adjusted_y = y + (dy - damped_dy) / 2; + /* Store true, not dir-corrected values */ + me->set_grob_property ("y", gh_double2scm (adjusted_y * dir)); + me->set_grob_property ("dy", gh_double2scm (damped_dy * dir)); + } + return SCM_UNSPECIFIED; +} + +/* + Quantise dy (height) of beam. + Generalisation of [Ross]. + */ +MAKE_SCHEME_CALLBACK (Beam, quantise_dy, 1); +SCM +Beam::quantise_dy (SCM smob) +{ + Grob *me = unsmob_grob (smob); + + if (visible_stem_count (me) <= 1) + return SCM_UNSPECIFIED; + + Array a; + SCM proc = me->get_grob_property ("height-quants"); + SCM quants = gh_call2 (proc, me->self_scm (), + gh_double2scm (me->paper_l ()->get_var ("stafflinethickness") + / 1.0)); + + for (SCM s = quants; gh_pair_p (s); s = gh_cdr (s)) + a.push (gh_scm2double (gh_car (s))); + + if (a.size () > 1) + { + /* y,dy in this function are corrected for beam-dir */ + Direction dir = Directional_element_interface::get (me); + Real y = gh_scm2double (me->get_grob_property ("y")) * dir; + Real dy = gh_scm2double (me->get_grob_property ("dy")) * dir; + + Real staff_space = Staff_symbol_referencer::staff_space (me); + + Interval iv = quantise_iv (a, abs (dy)/staff_space) * staff_space; + Real q = (abs (dy) - iv[SMALLER] <= iv[BIGGER] - abs (dy)) + ? iv[SMALLER] + : iv[BIGGER]; + + Real quantised_dy = q * sign (dy); + Real adjusted_y = y + (dy - quantised_dy) / 2; + /* Store true, not dir-corrected values */ + me->set_grob_property ("y", gh_double2scm (adjusted_y * dir)); + me->set_grob_property ("dy", gh_double2scm (quantised_dy * dir)); } - return dy; + return SCM_UNSPECIFIED; } +/* It's tricky to have the user override y,dy directly, so we use this + translation func. Also, if our staff_space != 1 (smaller staff, eg), + user will expect staff-position to be discrete values. */ +MAKE_SCHEME_CALLBACK (Beam, user_override, 1); +SCM +Beam::user_override (SCM smob) +{ + Grob *me = unsmob_grob (smob); + Real staff_space = Staff_symbol_referencer::staff_space (me); + + SCM s = me->get_grob_property ("staff-position"); + if (gh_number_p (s)) + { + Real y = gh_scm2double (s) * staff_space * 0.5; + me->set_grob_property ("y", gh_double2scm (y)); + } + + /* Name suggestions? Tilt, slope, vertical-* ? */ + s = me->get_grob_property ("height"); + if (gh_number_p (s)) + { + Real dy = gh_scm2double (s) * staff_space * 0.5; + me->set_grob_property ("dy", gh_double2scm (dy)); + } + + return SCM_UNSPECIFIED; +} + +/* + Ugh, this must be last, after user_override + Assumes directionised y/dy. + */ +MAKE_SCHEME_CALLBACK (Beam, do_quantise_y, 1); +SCM +Beam::do_quantise_y (SCM smob) +{ + Grob *me = unsmob_grob (smob); + + /* + If the user set y-position, we shouldn't do quanting. + */ + if (gh_number_p (me->get_grob_property ("y-position-hs"))) + return SCM_UNSPECIFIED; + + Real y = gh_scm2double (me->get_grob_property ("y")); + Real dy = gh_scm2double (me->get_grob_property ("dy")); + + /* we can modify y, so we should quantise y */ + Real half_space = Staff_symbol_referencer::staff_space (me) / 2; + Real y_shift = check_stem_length_f (me, y, dy); + y += y_shift; + y = quantise_y_f (me, y, dy, 0); + + /* + Hmm, this is a bit keyhole operation: we're passing `this' as a + parameter, and member vars as SCM properties. We should decide on + SCM/C/C++ boundary */ + me->set_grob_property ("y", gh_double2scm (y)); + set_stem_lengths (me); + y = gh_scm2double (me->get_grob_property ("y")); + + y_shift = check_stem_length_f (me, y, dy); + + if (y_shift > half_space / 4) + { + y += y_shift; + + /* + for significantly lengthened or shortened stems, + request quanting the other way. + */ + int quant_dir = 0; + if (abs (y_shift) > half_space / 2) + quant_dir = sign (y_shift) * Directional_element_interface::get (me); + y = quantise_y_f (me, y, dy, quant_dir); + } + + me->set_grob_property ("y", gh_double2scm (y)); + // me->set_grob_property ("dy", gh_double2scm (dy)); + return SCM_UNSPECIFIED; +} + + Real -Beam::calc_stem_y_f (Score_element*me,Item* s, Real y, Real dy) +Beam::calc_stem_y_f (Grob*me,Item* s, Real y, Real dy) { int beam_multiplicity = get_multiplicity (me); int stem_multiplicity = (Stem::flag_i (s) - 2) >? 0; - Real staffspace = me->paper_l ()->get_var ("staffspace"); - - SCM space_proc = me->get_elt_property ("space-function"); + SCM space_proc = me->get_grob_property ("space-function"); SCM space = gh_call1 (space_proc, gh_int2scm (beam_multiplicity)); - Real thick = gh_scm2double (me->get_elt_property ("thickness")) *staffspace; - Real interbeam_f = gh_scm2double (space) * staffspace; + Real thick = gh_scm2double (me->get_grob_property ("thickness")) ; + Real interbeam_f = gh_scm2double (space) ; // ugh -> use commonx Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); @@ -480,7 +607,7 @@ Beam::calc_stem_y_f (Score_element*me,Item* s, Real y, Real dy) } Real -Beam::check_stem_length_f (Score_element*me,Real y, Real dy) +Beam::check_stem_length_f (Grob*me,Real y, Real dy) { Real shorten = 0; Real lengthen = 0; @@ -489,7 +616,7 @@ Beam::check_stem_length_f (Score_element*me,Real y, Real dy) Link_array stems= Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); - for (int i=0; i < stems.size(); i++) + for (int i=0; i < stems.size (); i++) { Item* s = stems[i]; if (Stem::invisible_b (s)) @@ -518,12 +645,22 @@ Beam::check_stem_length_f (Score_element*me,Real y, Real dy) stem directions and length should set to relative to the chord's position of the beam. */ void -Beam::set_stem_length (Score_element*me,Real y, Real dy) +Beam::set_stem_lengths (Grob *me) { + if (visible_stem_count (me) <= 1) + return; + + Real y = gh_scm2double (me->get_grob_property ("y")); + Real dy = gh_scm2double (me->get_grob_property ("dy")); + Real half_space = Staff_symbol_referencer::staff_space (me)/2; Link_array stems= Pointer_group_interface__extract_elements (me, (Item*)0, "stems"); + Grob *common = me->common_refpoint (stems[0], Y_AXIS); + for (int i=1; i < stems.size (); i++) + if (!Stem::invisible_b (stems[i])) + common = common->common_refpoint (stems[i], Y_AXIS); for (int i=0; i < stems.size (); i++) { @@ -533,56 +670,29 @@ Beam::set_stem_length (Score_element*me,Real y, Real dy) Real stem_y = calc_stem_y_f (me, s, y, dy); + // doesn't play well with dvips + if (scm_definedp (ly_symbol2scm ("ps-testing"), SCM_UNDEFINED) + == SCM_BOOL_T) + if (Stem::get_direction (s) == Directional_element_interface::get (me)) + stem_y += Stem::get_direction (s) + * gh_scm2double (me->get_grob_property ("thickness")) / 2; + /* caution: stem measures in staff-positions */ - Stem::set_stemend (s,(stem_y + calc_interstaff_dist (s, dynamic_cast (me))) / half_space); + Real id = me->relative_coordinate (common, Y_AXIS) + - stems[i]->relative_coordinate (common, Y_AXIS); + Stem::set_stemend (s, (stem_y + id) / half_space); } } -/* - [Ross] (simplification of) - Set dy complying with: - - zero - - thick / 2 + staffline_f / 2 - - thick + staffline_f - + n * staff_space -*/ -Real -Beam::quantise_dy_f (Score_element*me,Real dy) -{ - Array a; - - SCM proc = me->get_elt_property ("height-quants"); - SCM quants = gh_call2 (proc, me->self_scm (), - gh_double2scm (me->paper_l ()->get_var ("stafflinethickness") - / me->paper_l ()->get_var ("staffspace"))); - - - for (SCM s = quants; gh_pair_p (s); s = gh_cdr (s)) - a.push (gh_scm2double (gh_car (s))); - - if (a.size () <= 1) - return dy; - - Real staff_space = Staff_symbol_referencer::staff_space (me); - - Interval iv = quantise_iv (a, abs (dy)/staff_space) * staff_space; - Real q = (abs (dy) - iv[SMALLER] <= iv[BIGGER] - abs (dy)) - ? iv[SMALLER] - : iv[BIGGER]; - - return q * sign (dy); -} - /* Prevent interference from stafflines and beams. - See Documentation/tex/fonts.doc - We only need to quantise the (left) y-position of the beam, + We only need to quantise the (left) y of the beam, since dy is quantised too. if extend_b then stems must *not* get shorter */ Real -Beam::quantise_y_f (Score_element*me,Real y, Real dy, int quant_dir) +Beam::quantise_y_f (Grob*me,Real y, Real dy, int quant_dir) { int multiplicity = get_multiplicity (me); @@ -590,7 +700,7 @@ Beam::quantise_y_f (Score_element*me,Real y, Real dy, int quant_dir) Real thick = me->paper_l ()->get_var ("stafflinethickness"); - SCM proc = me->get_elt_property ("vertical-position-quant-function"); + SCM proc = me->get_grob_property ("vertical-position-quant-function"); SCM quants = scm_apply (proc, me->self_scm (), gh_list (gh_int2scm (multiplicity), @@ -612,24 +722,31 @@ Beam::quantise_y_f (Score_element*me,Real y, Real dy, int quant_dir) Real q = up_y - iv[SMALLER] <= iv[BIGGER] - up_y ? iv[SMALLER] : iv[BIGGER]; if (quant_dir) - q = iv[(Direction)quant_dir]; + q = iv[ (Direction)quant_dir]; return q * Directional_element_interface::get (me); } void -Beam::set_beaming (Score_element*me,Beaming_info_list *beaming) +Beam::set_beaming (Grob*me,Beaming_info_list *beaming) { - Link_array stems= - Pointer_group_interface__extract_elements (me, (Score_element*)0, "stems"); + Link_array stems= + Pointer_group_interface__extract_elements (me, (Grob*)0, "stems"); Direction d = LEFT; - for (int i=0; i < stems.size(); i++) + for (int i=0; i < stems.size (); i++) { do { - if (Stem::beam_count (stems[i], d) == 0) - Stem::set_beaming ( stems[i], beaming->infos_.elem (i).beams_i_drul_[d],d); + /* Don't overwrite user override (?) */ + if (Stem::beam_count (stems[i], d) == 0 + /* Don't set beaming for outside of outer stems */ + && ! (d == LEFT && i == 0) + && ! (d == RIGHT && i == stems.size () -1)) + { + int b = beaming->infos_.elem (i).beams_i_drul_[d]; + Stem::set_beaming (stems[i], b, d); + } } while (flip (&d) != LEFT); } @@ -643,33 +760,32 @@ Beam::set_beaming (Score_element*me,Beaming_info_list *beaming) FIXME: clean me up. */ Molecule -Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) +Beam::stem_beams (Grob*me,Item *here, Item *next, Item *prev, + Real dy, Real dydx + ) { // ugh -> use commonx - if ((next && !(next->relative_coordinate (0, X_AXIS) > here->relative_coordinate (0, X_AXIS))) || - (prev && !(prev->relative_coordinate (0, X_AXIS) < here->relative_coordinate (0, X_AXIS)))) + if ((next && ! (next->relative_coordinate (0, X_AXIS) > here->relative_coordinate (0, X_AXIS))) || + (prev && ! (prev->relative_coordinate (0, X_AXIS) < here->relative_coordinate (0, X_AXIS)))) programming_error ("Beams are not left-to-right"); - Real staffline_f = me->paper_l ()->get_var ("stafflinethickness"); int multiplicity = get_multiplicity (me); - Real staffspace =me->paper_l ()->get_var ("staffspace"); - SCM space_proc = me->get_elt_property ("space-function"); + SCM space_proc = me->get_grob_property ("space-function"); SCM space = gh_call1 (space_proc, gh_int2scm (multiplicity)); - Real thick = gh_scm2double (me->get_elt_property ("thickness")) *staffspace; - Real interbeam_f = gh_scm2double (space) * staffspace; + Real thick = gh_scm2double (me->get_grob_property ("thickness")) ; + Real interbeam_f = gh_scm2double (space) ; Real bdy = interbeam_f; - Real stemdx = staffline_f; - + +#if 0 // ugh -> use commonx Real dx = visible_stem_count (me) ? last_visible_stem (me)->relative_coordinate (0, X_AXIS) - first_visible_stem (me)->relative_coordinate (0, X_AXIS) : 0.0; - Real dy = gh_scm2double (me->get_elt_property ("height")); - Real dydx = dy && dx ? dy/dx : 0; - +#endif + Molecule leftbeams; Molecule rightbeams; @@ -679,14 +795,18 @@ Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) else { int t = Stem::type_i (here); - SCM proc = me->get_elt_property ("flag-width-function"); + SCM proc = me->get_grob_property ("flag-width-function"); SCM result = gh_call1 (proc, gh_int2scm (t)); - nw_f = gh_scm2double (result) * staffspace; + nw_f = gh_scm2double (result); } Direction dir = Directional_element_interface::get (me); + /* [Tremolo] beams on whole notes may not have direction set? */ + if (dir == CENTER) + dir = Directional_element_interface::get (here); + /* half beams extending to the left. */ if (prev) { @@ -696,12 +816,20 @@ Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) Half beam should be one note-width, but let's make sure two half-beams never touch */ - Real w = here->relative_coordinate (0, X_AXIS) - prev->relative_coordinate (0, X_AXIS); + + // FIXME: TODO (check) stem width / sloped beams + Real w = here->relative_coordinate (0, X_AXIS) + - prev->relative_coordinate (0, X_AXIS); + Real stem_w = gh_scm2double (prev->get_grob_property ("thickness")) + // URG + * me->paper_l ()->get_var ("stafflinethickness"); + w = w/2 lookup_l ()->beam (dydx, w, thick); + a = Lookup::beam (dydx, w + stem_w, thick); a.translate (Offset (-w, -w * dydx)); + a.translate_axis (-stem_w/2, X_AXIS); for (int j = 0; j < lhalfs; j++) { Molecule b (a); @@ -712,19 +840,27 @@ Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) if (next) { - int rhalfs = Stem::beam_count (here,RIGHT) - Stem::beam_count (next,LEFT); - int rwholebeams= Stem::beam_count (here,RIGHT) relative_coordinate (0, X_AXIS) + - here->relative_coordinate (0, X_AXIS); - Real w = next->relative_coordinate (0, X_AXIS) - here->relative_coordinate (0, X_AXIS); - Molecule a = me->lookup_l ()->beam (dydx, w + stemdx, thick); - a.translate_axis( - stemdx/2, X_AXIS); + Real stem_w = gh_scm2double (next->get_grob_property ("thickness")) + // URG + * me->paper_l ()->get_var ("stafflinethickness"); + + Molecule a = Lookup::beam (dydx, w + stem_w, thick); + a.translate_axis (- stem_w/2, X_AXIS); int j = 0; Real gap_f = 0; - - SCM gap = me->get_elt_property ("gap"); + + SCM gap = me->get_grob_property ("gap"); if (gh_number_p (gap)) { - int gap_i = gh_scm2int ( (gap)); + int gap_i = gh_scm2int ((gap)); int nogap = rwholebeams - gap_i; for (; j < nogap; j++) @@ -733,22 +869,30 @@ Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) b.translate_axis (-dir * bdy * j, Y_AXIS); rightbeams.add_molecule (b); } - // TODO: notehead widths differ for different types - gap_f = nw_f / 2; + if (Stem::invisible_b (here)) + gap_f = nw_f; + else + gap_f = nw_f / 2; w -= 2 * gap_f; - a = me->lookup_l ()->beam (dydx, w + stemdx, thick); + a = Lookup::beam (dydx, w + stem_w, thick); } for (; j < rwholebeams; j++) { Molecule b (a); - b.translate (Offset (Stem::invisible_b (here) ? 0 : gap_f, -dir * bdy * j)); + Real tx = 0; + if (Stem::invisible_b (here)) + // ugh, see chord-tremolo.ly + tx = (-dir + 1) / 2 * nw_f * 1.5 + gap_f/4; + else + tx = gap_f; + b.translate (Offset (tx, -dir * bdy * j)); rightbeams.add_molecule (b); } w = w/2 lookup_l ()->beam (dydx, w, thick); + a = Lookup::beam (dydx, w, thick); for (; j < rwholebeams + rhalfs; j++) { @@ -767,14 +911,14 @@ Beam::stem_beams (Score_element*me,Item *here, Item *next, Item *prev) return leftbeams; } -MAKE_SCHEME_CALLBACK(Beam,brew_molecule); +MAKE_SCHEME_CALLBACK (Beam,brew_molecule,1); SCM Beam::brew_molecule (SCM smob) { - Score_element * me =unsmob_element (smob); + Grob * me =unsmob_grob (smob); Molecule mol; - if (!gh_pair_p (me->get_elt_property ("stems"))) + if (!gh_pair_p (me->get_grob_property ("stems"))) return SCM_EOL; Real x0,dx; Link_arraystems = @@ -788,22 +932,30 @@ Beam::brew_molecule (SCM smob) else { x0 = stems[0]->relative_coordinate (0, X_AXIS); - dx = stems.top()->relative_coordinate (0, X_AXIS) - x0; + dx = stems.top ()->relative_coordinate (0, X_AXIS) - x0; } + + + /* + TODO: the naming of the grob properties sucks. + */ + SCM dy_s = me->get_grob_property ("dy"); + SCM y_s = me->get_grob_property ("y"); + - Real dy = gh_scm2double (me->get_elt_property ("height")); + Real dy = gh_number_p (dy_s) ? gh_scm2double (dy_s) : 0.0; Real dydx = dy && dx ? dy/dx : 0; - Real y = gh_scm2double (me->get_elt_property ("y-position")); + Real y = gh_number_p (y_s) ? gh_scm2double (y_s) : 0.0; - for (int j=0; j 0)? stems[j-1] : 0; - Item * next = (j < stems.size()-1) ? stems[j+1] :0; + Item * next = (j < stems.size ()-1) ? stems[j+1] :0; - Molecule sb = stem_beams (me, i, next, prev); + Molecule sb = stem_beams (me, i, next, prev, dy, dydx); Real x = i->relative_coordinate (0, X_AXIS)-x0; sb.translate (Offset (x, x * dydx + y)); mol.add_molecule (sb); @@ -811,14 +963,14 @@ Beam::brew_molecule (SCM smob) mol.translate_axis (x0 - dynamic_cast (me)->get_bound (LEFT)->relative_coordinate (0, X_AXIS), X_AXIS); - return mol.create_scheme (); + return mol.smobbed_copy (); } int -Beam::forced_stem_count (Score_element*me) +Beam::forced_stem_count (Grob*me) { Link_arraystems = - Pointer_group_interface__extract_elements ( me, (Item*) 0, "stems"); + Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); int f = 0; for (int i=0; i < stems.size (); i++) { @@ -827,8 +979,8 @@ Beam::forced_stem_count (Score_element*me) if (Stem::invisible_b (s)) continue; - if (((int)Stem::chord_start_f (s)) - && (Stem::get_direction (s ) != Stem::get_default_dir (s ))) + if (( (int)Stem::chord_start_f (s)) + && (Stem::get_direction (s) != Stem::get_default_dir (s))) f++; } return f; @@ -841,7 +993,7 @@ Beam::forced_stem_count (Score_element*me) use filter and standard list functions. */ int -Beam::visible_stem_count (Score_element*me) +Beam::visible_stem_count (Grob*me) { Link_arraystems = Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); @@ -855,10 +1007,10 @@ Beam::visible_stem_count (Score_element*me) } Item* -Beam::first_visible_stem(Score_element*me) +Beam::first_visible_stem (Grob*me) { Link_arraystems = - Pointer_group_interface__extract_elements ( me, (Item*) 0, "stems"); + Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); for (int i = 0; i < stems.size (); i++) { @@ -869,10 +1021,10 @@ Beam::first_visible_stem(Score_element*me) } Item* -Beam::last_visible_stem(Score_element*me) +Beam::last_visible_stem (Grob*me) { Link_arraystems = - Pointer_group_interface__extract_elements ( me, (Item*) 0, "stems"); + Pointer_group_interface__extract_elements (me, (Item*) 0, "stems"); for (int i = stems.size (); i--;) { if (!Stem::invisible_b (stems[i])) @@ -891,18 +1043,22 @@ Beam::last_visible_stem(Score_element*me) rest -> stem -> beam -> interpolate_y_position () */ -Real -Beam::rest_collision_callback (Score_element *rest, Axis a ) +MAKE_SCHEME_CALLBACK (Beam,rest_collision_callback,2); +SCM +Beam::rest_collision_callback (SCM element_smob, SCM axis) { + Grob *rest = unsmob_grob (element_smob); + Axis a = (Axis) gh_scm2int (axis); + assert (a == Y_AXIS); - Score_element * st = unsmob_element (rest->get_elt_property ("stem")); - Score_element * stem = st; + Grob * st = unsmob_grob (rest->get_grob_property ("stem")); + Grob * stem = st; if (!stem) - return 0.0; - Score_element * beam = unsmob_element (stem->get_elt_property ("beam")); + return gh_double2scm (0.0); + Grob * beam = unsmob_grob (stem->get_grob_property ("beam")); if (!beam || !Beam::has_interface (beam) || !Beam::visible_stem_count (beam)) - return 0.0; + return gh_double2scm (0.0); // make callback for rest from this. Real beam_dy = 0; @@ -910,27 +1066,29 @@ Beam::rest_collision_callback (Score_element *rest, Axis a ) // todo: make sure this calced already. - SCM s = beam->get_elt_property ("height"); + SCM s = beam->get_grob_property ("dy"); if (gh_number_p (s)) beam_dy = gh_scm2double (s); - s = beam->get_elt_property ("y-position"); + s = beam->get_grob_property ("y"); if (gh_number_p (s)) beam_y = gh_scm2double (s); // ugh -> use commonx - Real x0 = first_visible_stem(beam)->relative_coordinate (0, X_AXIS); - Real dx = last_visible_stem(beam)->relative_coordinate (0, X_AXIS) - x0; + Real x0 = first_visible_stem (beam)->relative_coordinate (0, X_AXIS); + Real dx = last_visible_stem (beam)->relative_coordinate (0, X_AXIS) - x0; Real dydx = beam_dy && dx ? beam_dy/dx : 0; Direction d = Stem::get_direction (stem); Real beamy = (stem->relative_coordinate (0, X_AXIS) - x0) * dydx + beam_y; Real staff_space = Staff_symbol_referencer::staff_space (rest); - Real rest_dim = rest->extent (Y_AXIS)[d]*2.0 / staff_space ; + + + Real rest_dim = rest->extent (rest, Y_AXIS)[d]*2.0 / staff_space ; // refp?? Real minimum_dist - = gh_scm2double (rest->get_elt_property ("minimum-beam-collision-distance")); + = gh_scm2double (rest->get_grob_property ("minimum-beam-collision-distance")); Real dist = minimum_dist + -d * (beamy - rest_dim) >? 0; @@ -943,26 +1101,13 @@ Beam::rest_collision_callback (Score_element *rest, Axis a ) if (discrete_dist < stafflines+1) discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0); - return (-d * discrete_dist); + return gh_double2scm (-d * discrete_dist); } bool -Beam::has_interface (Score_element*me) +Beam::has_interface (Grob*me) { return me->has_interface (ly_symbol2scm ("beam-interface")); } -void -Beam::set_interface (Score_element*me) -{ - Pointer_group_interface g (me, "stems"); - g.set_interface (); - - /* - why the init? No way to tell difference between default and user - override. */ - me->set_elt_property ("height", gh_int2scm (0)); // ugh. - me->set_elt_property ("y-position" ,gh_int2scm (0)); - me->set_interface (ly_symbol2scm("beam-interface")); -}