From: Jan Nieuwenhuizen Date: Mon, 12 Aug 2002 15:14:17 +0000 (+0000) Subject: * scm/grob-property-description.scm (beamed-minimum-free-lengths): X-Git-Tag: release/1.5.73~22 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=b26483e4150ac737d6ada212f8a6164a24df6535;p=lilypond.git * scm/grob-property-description.scm (beamed-minimum-free-lengths): (beamed-extreme-free-lengths): New property. * lily/beam.cc (forced_stem_count): Count boundary cases too. (set_stem_shorten): Integer divide bug fix. * input/mutopia/J.S.Bach/baerenreiter-sarabande.ly: Really expect 6 systems, change warning into error. * scm/grob-description.scm (beamed-stem-shorten): Shorten 8th beams same as normal stem (one staffspace), high order beams less (arbitrary guess). (beamed-lengths): Standard length for all beams. (beamed-minimum-free-lengths): --- diff --git a/ChangeLog b/ChangeLog index 3aacb5eb11..b35657c8a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2002-08-12 Jan Nieuwenhuizen + + * scm/grob-property-description.scm (beamed-minimum-free-lengths): + (beamed-extreme-free-lengths): New property. + + * lily/beam.cc (forced_stem_count): Count boundary cases too. + (set_stem_shorten): Integer divide bug fix. + + * input/mutopia/J.S.Bach/baerenreiter-sarabande.ly: Really expect + 6 systems, change warning into error. + + * scm/grob-description.scm (beamed-stem-shorten): Shorten 8th + beams same as normal stem (one staffspace), high order beams less + (arbitrary guess). + (beamed-lengths): Standard length for all beams. + (beamed-minimum-free-lengths): +o (beamed-extreme-minimum-free-lengths): New property. + + * input/regression/beam-default-lengths.ly: + * input/regression/beam-shortened-lengths.ly: New file. + + * lily/stem.cc (get_stem_info): New function. + (calc_stem_info): Partial rewrite. + + * scm/grob-description.scm (Beam): same beamed-stem-shorten for + all beam counts. + 2002-08-12 Han-Wen Nienhuys * VERSION: 1.5.72 released diff --git a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly index b2ab3df550..37b8d8a768 100644 --- a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly +++ b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly @@ -14,9 +14,8 @@ forcedLastBreak = \notes { \break } (get-original (get-system smob)))))) (if (not (equal? n systems)) - ;; Can't use error yet, as we know that we're not using 6... - ;;(error - (warn + (error + ;;(warn (string-append "Got " (number->string systems) " systems (expecting " (number->string n)))))) @@ -131,7 +130,7 @@ sarabandeA = \context Voice \notes \relative c { d4 \property Thread.NoteHead \override #'after-line-breaking-callback - = #(lambda (smob) (assert-system-count smob 6.1)) + = #(lambda (smob) (assert-system-count smob 6)) d,,2 | } diff --git a/input/regression/beam-default-lengths.ly b/input/regression/beam-default-lengths.ly new file mode 100644 index 0000000000..8935525c4d --- /dev/null +++ b/input/regression/beam-default-lengths.ly @@ -0,0 +1,17 @@ +\version "1.5.68" + +\header{ + texidoc="Beamed stems have standard lengths if possible." + } + +\score{ + \notes\relative c'{ + \property Voice.Beam \set #'position-callbacks = + #`(,Beam::least_squares + ,Beam::check_concave + ,Beam::slope_damping) + + f4 [f8 f] [f16 f] [f32 f] [f64 f] [f128 f] + } + \paper{ linewidth = -1.0 } +} \ No newline at end of file diff --git a/input/regression/beam-shortened-lengths.ly b/input/regression/beam-shortened-lengths.ly new file mode 100644 index 0000000000..f26d273a55 --- /dev/null +++ b/input/regression/beam-shortened-lengths.ly @@ -0,0 +1,17 @@ +\version "1.5.68" + +\header{ + texidoc="Beams in unnatural direction, have shortened stems, but do not look too short." + } + +\score{ + \notes\relative c'{ + \property Voice.Beam \set #'position-callbacks = + #`(,Beam::least_squares + ,Beam::check_concave + ,Beam::slope_damping) + + f'4 [f8 f] [f16 f] [f32 f] [f64 f] [f128 f] + } + \paper{ linewidth = -1.0 } +} \ No newline at end of file diff --git a/lily/beam-quanting.cc b/lily/beam-quanting.cc index e9f992c774..e3fa99efb1 100644 --- a/lily/beam-quanting.cc +++ b/lily/beam-quanting.cc @@ -133,7 +133,7 @@ Beam::quanting (SCM smob) for (int i= 0; i < stems.size(); i++) { Grob*s = stems[i]; - stem_infos.push (Stem::calc_stem_info (s)); + stem_infos.push (Stem::get_stem_info (s)); dirs_found[stem_infos.top ().dir_] = true; bool f = french && i > 0&& (i < stems.size () -1); diff --git a/lily/beam.cc b/lily/beam.cc index dc7cd4cced..731dcb3e6e 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -81,18 +81,15 @@ Beam::get_beam_translation (Grob *me) return gh_scm2double (s); } -/* - Maximum beam_count. - */ +/* Maximum beam_count. */ int Beam::get_beam_count (Grob *me) { int m = 0; for (SCM s = me->get_grob_property ("stems"); gh_pair_p (s); s = ly_cdr (s)) { - Grob *sc = unsmob_grob (ly_car (s)); - - m = m >? (Stem::beam_multiplicity (sc).length () + 1); + Grob *stem = unsmob_grob (ly_car (s)); + m = m >? (Stem::beam_multiplicity (stem).length () + 1); } return m; } @@ -727,7 +724,8 @@ Beam::set_stem_shorten (Grob *me) if (knee_b(me)) return ; - Real forced_fraction = forced_stem_count (me) / visible_stem_count (me); + Real forced_fraction = 1.0 * forced_stem_count (me) + / visible_stem_count (me); int beam_count = get_beam_count (me); @@ -802,9 +800,9 @@ Beam::least_squares (SCM smob) Grob *fvs = first_visible_stem (me); Grob *lvs = last_visible_stem (me); - Interval ideal (Stem::calc_stem_info (fvs).ideal_y_ + Interval ideal (Stem::get_stem_info (fvs).ideal_y_ + fvs->relative_coordinate (commony, Y_AXIS) -my_y, - Stem::calc_stem_info (lvs).ideal_y_ + Stem::get_stem_info (lvs).ideal_y_ + lvs->relative_coordinate (commony, Y_AXIS) - my_y); Real x0 = first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); @@ -863,7 +861,7 @@ Beam::least_squares (SCM smob) if (Stem::invisible_b (s)) continue; ideals.push (Offset (x_posns[i], - Stem::calc_stem_info (s).ideal_y_ + Stem::get_stem_info (s).ideal_y_ + s->relative_coordinate (commony, Y_AXIS) - my_y)); } @@ -939,7 +937,7 @@ Beam::shift_region_to_valid (SCM grob) Direction d = Stem::get_direction (s); Real left_y = - Stem::calc_stem_info (s).shortest_y_ + Stem::get_stem_info (s).shortest_y_ - dydx * x_posns [i]; /* @@ -1306,7 +1304,9 @@ Beam::forced_stem_count (Grob *me) if (Stem::invisible_b (s)) continue; - if (((int)Stem::chord_start_y (s)) + /* I can imagine counting those boundaries as a half forced stem, + but let's count them full for now. */ + if (abs (Stem::chord_start_y (s)) > 0.1 && (Stem::get_direction (s) != Stem::get_default_dir (s))) f++; } diff --git a/lily/include/stem.hh b/lily/include/stem.hh index 0ffdc8bf16..432cd57073 100644 --- a/lily/include/stem.hh +++ b/lily/include/stem.hh @@ -15,36 +15,39 @@ class Stem { public: - DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM )); - - static Array note_head_positions (Grob*); - static int duration_log (Grob*) ; - static void set_beaming (Grob*,int, Direction d); - static Grob * get_beam (Grob*); - static Grob * first_head (Grob*) ; - static Grob * last_head (Grob*) ; - static Drul_array extremal_heads (Grob*); - static Grob * support_head (Grob*) ; - static void add_head (Grob*me, Grob*n); - static Stem_info calc_stem_info (Grob *) ; - static Real chord_start_y (Grob *) ; - static Direction get_direction (Grob*) ; + static Array note_head_positions (Grob *); + static int duration_log (Grob *); + static void set_beaming (Grob *, int, Direction d); + static Grob *get_beam (Grob *); + static Grob *first_head (Grob *); + static Grob *last_head (Grob *); + static Drul_array extremal_heads (Grob *); + static Grob *support_head (Grob *) ; + static void add_head (Grob *me, Grob *n); + static Stem_info get_stem_info (Grob *); + static Real chord_start_y (Grob *); + static Direction get_direction (Grob *); static void set_stemend (Grob *,Real); - static Direction get_default_dir (Grob *) ; - static Slice Stem::beam_multiplicity (Grob *stem); + static Direction get_default_dir (Grob *); + static Slice Stem::beam_multiplicity (Grob *); - static int head_count (Grob *) ; + static int head_count (Grob *); static bool invisible_b (Grob *) ; - static Interval head_positions (Grob *) ; - static Real get_default_stem_end_position (Grob*me) ; - static void position_noteheads (Grob*); - static Real stem_end_position (Grob*) ; + static Interval head_positions (Grob *); + static Real get_default_stem_end_position (Grob*me); + static void position_noteheads (Grob *); + static Real stem_end_position (Grob *); + static Molecule flag (Grob *); + static bool has_interface (Grob *); + static void set_spacing_hints (Grob *); + + DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM)); DECLARE_SCHEME_CALLBACK (off_callback, (SCM element, SCM axis)); - static Molecule flag (Grob*); - DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM )); + DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM)); DECLARE_SCHEME_CALLBACK (dim_callback, (SCM smob, SCM axis)); - DECLARE_SCHEME_CALLBACK (height, (SCM,SCM)); - static bool has_interface (Grob*); - static void set_spacing_hints (Grob*me) ; + DECLARE_SCHEME_CALLBACK (height, (SCM, SCM)); + +private: + static void calc_stem_info (Grob *); }; #endif diff --git a/lily/stem.cc b/lily/stem.cc index b17f0a383a..493a7d0b77 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -305,7 +305,6 @@ Stem::get_default_stem_end_position (Grob*me) } } - Real shorten_f = 0.0; SCM sshorten = me->get_grob_property ("stem-shorten"); @@ -752,8 +751,6 @@ Stem::off_callback (SCM element_smob, SCM) return gh_double2scm (r); } - - Grob* Stem::get_beam (Grob*me) { @@ -761,127 +758,149 @@ Stem::get_beam (Grob*me) return unsmob_grob (b); } -// ugh still very long. Stem_info -Stem::calc_stem_info (Grob*me) +Stem::get_stem_info (Grob *me) { + /* DOCME!!! So, what's this all about? */ SCM up_to_staff = me->get_grob_property ("up-to-staff"); - if (gh_scm2bool(up_to_staff)) { - - // Up-to-staff : the stem end out of the staff. - - /* - FIXME: duplicate code. - */ - int line_count = Staff_symbol_referencer::line_count (me); - - Stem_info si ; - - Direction dir = get_direction (me); - - si.ideal_y_ = dir* (line_count + 1.5); - si.dir_ = dir; - si.shortest_y_ = si.ideal_y_; - - return si; - } - - SCM scm_info = me->get_grob_property ("stem-info"); - - if (gh_pair_p (scm_info )) + if (gh_scm2bool(up_to_staff)) { - Stem_info si ; + /* Up-to-staff : the stem end out of the staff. */ - si.dir_ = Directional_element_interface::get(me); - si.ideal_y_ = gh_scm2double (gh_car (scm_info)); - si.shortest_y_ = gh_scm2double (gh_cadr (scm_info)); + /* FIXME: duplicate code. */ + int line_count = Staff_symbol_referencer::line_count (me); + Stem_info si ; + Direction dir = get_direction (me); + si.ideal_y_ = dir* (line_count + 1.5); + si.dir_ = dir; + si.shortest_y_ = si.ideal_y_; return si; } - Direction mydir = Directional_element_interface::get (me); + + /* Return cached info if available */ + SCM scm_info = me->get_grob_property ("stem-info"); + if (!gh_pair_p (scm_info)) + { + calc_stem_info (me); + scm_info = me->get_grob_property ("stem-info"); + } + + Stem_info si; + si.dir_ = Directional_element_interface::get (me); + si.ideal_y_ = gh_scm2double (gh_car (scm_info)); + si.shortest_y_ = gh_scm2double (gh_cadr (scm_info)); + return si; +} + +void +Stem::calc_stem_info (Grob *me) +{ + Direction my_dir = Directional_element_interface::get (me); Real staff_space = Staff_symbol_referencer::staff_space (me); - Real half_space = staff_space / 2; + Grob *beam = get_beam (me); + Real beam_translation = Beam::get_beam_translation (beam); + Real beam_thickness = gh_scm2double (beam->get_grob_property ("thickness")); + int beam_count = Beam::get_direction_beam_count (beam, my_dir); + + + /* Simple standard stem length */ + Real ideal_length = + gh_scm2double (robust_list_ref + (beam_count - 1, + me->get_grob_property ("beamed-lengths"))) + * staff_space + /* stem only extends to center of beam */ + - 0.5 * beam_thickness; - Grob * beam = get_beam (me); - int beam_count = Beam::get_direction_beam_count (beam, mydir); - Real beam_translation= Beam::get_beam_translation (beam); - Real thick = gh_scm2double (beam->get_grob_property ("thickness")); - Real note_start = chord_start_y (me); - /* from here on, calculate as if dir == UP */ - note_start *= mydir; + /* Condition: sane minimum free stem length (chord to beams) */ + Real ideal_minimum_free = + gh_scm2double (robust_list_ref + (beam_count - 1, + me->get_grob_property ("beamed-minimum-free-lengths"))) + * staff_space; - SCM grace_prop = me->get_grob_property ("grace"); + int my_beam_count = Stem::beam_multiplicity (me).length () + 1; + Real height_of_my_beams = beam_thickness + + (my_beam_count - 1) * beam_translation; - bool grace_b = to_boolean (grace_prop); - SCM bml = robust_list_ref ( beam_count - 1, - me->get_grob_property ("beamed-minimum-lengths")); + Real ideal_minimum_length = ideal_minimum_free + + height_of_my_beams + /* stem only extends to center of beam */ + - 0.5 * beam_thickness; - Real minimum_length = gh_scm2double(bml)*staff_space; - SCM bl = robust_list_ref ( beam_count - 1, - me->get_grob_property ("beamed-lengths")); - Real stem_length = gh_scm2double(bl) * staff_space; + ideal_length = ideal_length >? ideal_minimum_length; + + /* Convert to Y position, calculate for dir == UP */ + Real note_start = + /* staff positions */ + head_positions (me)[my_dir] * 0.5 + * my_dir; + Real ideal_y = note_start + ideal_length; - /* - stem goes to center of beam, hence 0.5 - */ - Real beam_lengthen = beam_translation* (beam_count - 1) - + 0.5 * thick; - Real shortest_y = note_start + minimum_length + beam_lengthen; - Real ideal_y = stem_length + note_start + beam_lengthen; + /* Conditions for Y position */ - /* - lowest beam of (UP) beam must never be lower than second staffline - - Hmm, reference (Wanske?) + /* Lowest beam of (UP) beam must never be lower than second staffline + + Reference? + + Although this (additional) rule is probably correct, + I expect that highest beam (UP) should also never be lower + than middle staffline, just as normal stems. - Although this (additional) rule is probably correct, - I expect that highest beam (UP) should also never be lower - than middle staffline, just as normal stems. + Reference? - Add: not for knees. Not sure if that's is a good thing. - */ + Obviously not for grace beams. + + Also, not for knees. Seems to be a good thing. */ + SCM grace = me->get_grob_property ("grace"); + bool grace_b = to_boolean (grace); bool no_extend_b = to_boolean (me->get_grob_property ("no-stem-extend")); bool knee_b = to_boolean (beam->get_grob_property ("knee")); if (!grace_b && !no_extend_b && !knee_b) { - /* highest beam of (UP) beam must never be lower than middle - staffline - lowest beam of (UP) beam must never be lower than second staffline - */ - ideal_y = - ideal_y >? 0 - >? (- 2 * half_space - thick + beam_lengthen); + /* Highest beam of (UP) beam must never be lower than middle + staffline */ + ideal_y = ideal_y >? 0; + /* Lowest beam of (UP) beam must never be lower than second staffline */ + ideal_y = ideal_y >? (-staff_space + - beam_thickness + height_of_my_beams); } - - - // ideal_y = ideal_y >? shortest_y; - SCM s = beam->get_grob_property ("shorten"); - if (gh_number_p (s)) - ideal_y -= gh_scm2double (s); + + SCM shorten = beam->get_grob_property ("shorten"); + if (gh_number_p (shorten)) + ideal_y -= gh_scm2double (shorten); + + + Real minimum_free = + gh_scm2double (robust_list_ref + (beam_count - 1, + me->get_grob_property + ("beamed-extreme-minimum-free-lengths"))) + * staff_space; + + Real minimum_length = minimum_free + + height_of_my_beams + /* stem only extends to center of beam */ + - 0.5 * beam_thickness; + + Real minimum_y = note_start + minimum_length; - ideal_y *= mydir; - shortest_y *= mydir; + + ideal_y *= my_dir; + Real shortest_y = minimum_y * my_dir; me->set_grob_property ("stem-info", scm_list_n (gh_double2scm (ideal_y), gh_double2scm (shortest_y), SCM_UNDEFINED)); - - Stem_info si; - si.dir_ = mydir; - si.shortest_y_ = shortest_y; - si.ideal_y_ = ideal_y; - - return si; } - -// move to stem? Slice Stem::beam_multiplicity (Grob *stem) { @@ -896,6 +915,6 @@ Stem::beam_multiplicity (Grob *stem) ADD_INTERFACE (Stem,"stem-interface", "A stem", - "up-to-staff avoid-note-head adjust-if-on-staffline thickness stem-info beamed-lengths beamed-minimum-lengths lengths beam stem-shorten duration-log beaming neutral-direction stem-end-position support-head note-heads direction length style no-stem-extend flag-style"); + "up-to-staff avoid-note-head adjust-if-on-staffline thickness stem-info beamed-lengths beamed-minimum-free-lengths beamed-extreme-minimum-free-lengths lengths beam stem-shorten duration-log beaming neutral-direction stem-end-position support-head note-heads direction length style no-stem-extend flag-style"); diff --git a/scm/grob-description.scm b/scm/grob-description.scm index afd86a0ab9..4539a35e58 100644 --- a/scm/grob-description.scm +++ b/scm/grob-description.scm @@ -144,7 +144,23 @@ (after-line-breaking-callback . ,Beam::after_line_breaking) (neutral-direction . -1) (dir-function . ,beam-dir-majority-median) - (beamed-stem-shorten . (1.0 0.5)) + + ;; Whe have some unreferenced problems here. + ;; + ;; If we shorten beamed stems less than normal stems (1 staffspace), + ;; or high order less than 8th beams, patterns like + ;; c''4 [c''8 c''] c''4 [c''16 c] + ;; are ugly (different stem lengths). + ;; + ;; But if we shorten 16th beams as much as 8th beams, a single + ;; forced 16th beam looks *very* short. + + ;; We choose to shorten 8th beams the same as single stems, + ;; and high order beams less than 8th beams, so that all + ;; isolated shortened beams look nice and a bit shortened, + ;; sadly possibly breaking patterns with high order beams. + (beamed-stem-shorten . (1.0 0.5 0.25)) + (outer-stem-length-limit . 0.2) (slope-limit . 0.2) (flag-width-function . ,default-beam-flag-width-function) @@ -822,19 +838,43 @@ (before-line-breaking-callback . ,Stem::before_line_breaking) (molecule-callback . ,Stem::brew_molecule) (thickness . 1.3) - (beamed-lengths . (2.5 2.0 1.5)) - - ;; - (beamed-minimum-lengths . (1.5 1.25 1.0)) - - ;; Stems in unnatural (forced) direction should be shortened, - ;; according to [Roush & Gourlay]. Their suggestion to knock off - ;; a whole staffspace seems a bit drastical: we'll do half. + ;; 3.5 (or 3 measured from note head) is standar length + ;; 32nd, 64th flagged stems should be longer (lengths . (3.5 3.5 3.5 4.5 5.0)) + + ;; Stems in unnatural (forced) direction should be shortened by + ;; one staff space, according to [Roush & Gourlay]. + ;; Flagged stems we shorten only half a staff space. (stem-shorten . (1.0 0.5)) - ; if stem is on middle line, choose this direction. + + ;; default stem direction for note on middle line (neutral-direction . -1) + + ;; [Wanske]: standard length (but no shorter than minimum). + (beamed-lengths . (3.5)) + + ;; [Wanske] lists three sets of minimum lengths. One + ;; set for the nomal case, and one set for beams with `der + ;; Balkenendpunkt weiter "uber bzw. unter die Systemgrenze + ;; hinaus (bei Gruppen mit grossem Tonumfang)' and the extreme + ;; case. + + ;; Note that Wanske lists numbers lengths starting from top of + ;; head, so we must add half a staff space. + + ;; We use the normal minima as minimum for the ideal lengths, + ;; and the extreme minima as abolute minimum length. + + ;; The 'normal' minima + (beamed-minimum-free-lengths . (2.5 2.0 1.5)) + + ;; The 'far outside staff' minima, not used + ;(beamed-far-minimum-free-lengths . (1.83)) + + ;; The 'extreme case' minima + (beamed-extreme-minimum-free-lengths . (1.83 1.5)) + (X-offset-callbacks . (,Stem::off_callback)) (X-extent-callback . ,Stem::dim_callback) (Y-extent-callback . ,Stem::height) diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index ab79c1ce4e..9860ffcae9 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -100,7 +100,8 @@ In the case of alignment grobs, this should contain only one number.") (grob-property-description 'beam-thickness number? "thickness, measured in staffspace.") (grob-property-description 'beam-width number? "width of the tremolo sign.") (grob-property-description 'beamed-lengths list? "list of stem lengths given beam multiplicity .") -(grob-property-description 'beamed-minimum-lengths list? "list of minimum stem lengths given beam multiplicity.") +(grob-property-description 'beamed-minimum-free-lengths list? "list of normal minimum free stem lengths (chord to beams) given beam multiplicity.") +(grob-property-description 'beamed-extreme-free-lengths list? "list of extreme minimum free stem lengths (chord to beams) given beam multiplicity.") (grob-property-description 'beamed-stem-shorten list? "shorten beamed stems in forced direction.") (grob-property-description 'beaming pair? "Pair of number lists. Each number list