X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fstem.cc;h=e83ffd9893226a95672f70ebf284d7cd8d926733;hb=4a401ca1c60f428daa242dbdd102fdb3f327ebfb;hp=6016eebbb439b7b067201225a0f7adcdd84d85b0;hpb=86fcede8899ba1abd58db8afe7e1e537bec80c30;p=lilypond.git diff --git a/lily/stem.cc b/lily/stem.cc index 6016eebbb4..e83ffd9893 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -1,9 +1,7 @@ /* - stem.cc -- implement Stem + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter - - (c) 1996--2007 Han-Wen Nienhuys + Copyright (C) 1996--2011 Han-Wen Nienhuys Jan Nieuwenhuizen TODO: This is way too hairy @@ -11,12 +9,25 @@ TODO: fix naming. Stem-end, chord-start, etc. is all confusing naming. + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ #include "stem.hh" #include "spanner.hh" -#include // rint +#include // rint using namespace std; #include "beam.hh" @@ -54,7 +65,7 @@ Stem::set_beaming (Grob *me, int beam_count, Direction d) lst = scm_cons (scm_from_int (i), lst); else lst = SCM_BOOL_F; - + index_set_cell (pair, d, lst); } @@ -78,7 +89,7 @@ Stem::head_positions (Grob *me) { Drul_array e (extremal_heads (me)); return Interval (Staff_symbol_referencer::get_position (e[DOWN]), - Staff_symbol_referencer::get_position (e[UP])); + Staff_symbol_referencer::get_position (e[UP])); } return Interval (); } @@ -89,12 +100,10 @@ Stem::chord_start_y (Grob *me) Interval hp = head_positions (me); if (!hp.is_empty ()) return hp[get_grob_direction (me)] * Staff_symbol_referencer::staff_space (me) - * 0.5; + * 0.5; return 0; } - - void Stem::set_stemend (Grob *me, Real se) { @@ -169,13 +178,13 @@ Stem::extremal_heads (Grob *me) Direction d = LEFT; do - { - if (d * p > d * extpos[d]) - { - exthead[d] = n; - extpos[d] = p; - } - } + { + if (d * p > d * extpos[d]) + { + exthead[d] = n; + extpos[d] = p; + } + } while (flip (&d) != DOWN); } return exthead; @@ -215,25 +224,22 @@ bool Stem::is_invisible (Grob *me) { return !is_normal_stem (me) - && (robust_scm2double (me->get_property ("stemlet-length"), - 0.0) == 0.0); + && (robust_scm2double (me->get_property ("stemlet-length"), + 0.0) == 0.0); } - bool Stem::is_normal_stem (Grob *me) { return head_count (me) && scm_to_int (me->get_property ("duration-log")) >= 1; } - MAKE_SCHEME_CALLBACK (Stem, pure_height, 3) SCM -Stem::pure_height (SCM smob, SCM start, SCM end) +Stem::pure_height (SCM smob, + SCM /* start */, + SCM /* end */) { - (void) start; - (void) end; - Grob *me = unsmob_grob (smob); Interval iv; @@ -241,26 +247,39 @@ Stem::pure_height (SCM smob, SCM start, SCM end) return ly_interval2scm (iv); Real ss = Staff_symbol_referencer::staff_space (me); + Real rad = Staff_symbol_referencer::staff_radius (me); if (!to_boolean (me->get_property ("cross-staff"))) { - Real len = scm_to_double (calc_length (smob)) * ss / 2; + Real len_in_halfspaces; + SCM user_set_len_scm = me->get_property_data ("length"); + if (scm_is_number (user_set_len_scm)) + len_in_halfspaces = scm_to_double (user_set_len_scm); + else + len_in_halfspaces = scm_to_double (calc_length (smob)); + Real len = len_in_halfspaces * ss / 2; Direction dir = get_grob_direction (me); Interval hp = head_positions (me); if (dir == UP) - iv = Interval (0, len); + iv = Interval (0, len); else - iv = Interval (-len, 0); + iv = Interval (-len, 0); if (!hp.is_empty ()) - iv.translate (hp[dir] * ss / 2); - } + { + iv.translate (hp[dir] * ss / 2); + iv.add_point (hp[-dir] * ss / 2); + } - /* at a minimum, make the pure-height cover the staff symbol */ - Real rad = Staff_symbol_referencer::staff_radius (me); - iv.add_point (-rad * ss); - iv.add_point (rad * ss); + /* extend the stem (away from the head) to cover the staff */ + if (dir == UP) + iv[UP] = max (iv[UP], rad * ss); + else + iv[DOWN] = min (iv[DOWN], -rad * ss); + } + else + iv = Interval (-rad * ss, rad * ss); return ly_interval2scm (iv); } @@ -279,7 +298,7 @@ Stem::calc_stem_end_position (SCM smob) (void) beam->get_property ("quantized-positions"); return me->get_property ("stem-end-position"); } - + vector a; /* WARNING: IN HALF SPACES */ @@ -303,13 +322,14 @@ SCM Stem::calc_length (SCM smob) { Grob *me = unsmob_grob (smob); - + SCM details = me->get_property ("details"); int durlog = duration_log (me); Real ss = Staff_symbol_referencer::staff_space (me); + Real staff_rad = Staff_symbol_referencer::staff_radius (me); Real length = 7; - SCM s = scm_cdr (scm_assq (ly_symbol2scm ("lengths"), details)); + SCM s = ly_assoc_get (ly_symbol2scm ("lengths"), details, SCM_EOL); if (scm_is_pair (s)) length = 2 * scm_to_double (robust_list_ref (durlog - 2, s)); @@ -320,14 +340,28 @@ Stem::calc_length (SCM smob) Interval hp = head_positions (me); if (dir && dir * hp[dir] >= 0) { - SCM sshorten = scm_cdr (scm_assq (ly_symbol2scm ("stem-shorten"), details)); + SCM sshorten = ly_assoc_get (ly_symbol2scm ("stem-shorten"), details, SCM_EOL); SCM scm_shorten = scm_is_pair (sshorten) - ? robust_list_ref (max (duration_log (me) - 2, 0), sshorten) : SCM_EOL; - Real shorten = 2* robust_scm2double (scm_shorten, 0); - - /* On boundary: shorten only half */ - if (abs (head_positions (me)[dir]) <= 1) - shorten *= 0.5; + ? robust_list_ref (max (duration_log (me) - 2, 0), sshorten) : SCM_EOL; + Real shorten_property = 2 * robust_scm2double (scm_shorten, 0); + /* change in length between full-size and shortened stems is executed gradually. + "transition area" = stems between full-sized and fully-shortened. + */ + Real quarter_stem_length = 2 * scm_to_double (robust_list_ref (0, s)); + /* shortening_step = difference in length between consecutive stem lengths + in transition area. The bigger the difference between full-sized + and shortened stems, the bigger shortening_step is. + (but not greater than 1/2 and not smaller than 1/4). + value 6 is heuristic; it determines the suggested transition slope steepnesas. + */ + Real shortening_step = min (max (0.25, (shorten_property / 6)), 0.5); + /* Shortening of unflagged stems should begin on the first stem that sticks + more than 1 staffspace (2 units) out of the staff. + Shortening of flagged stems begins in the same moment as unflagged ones, + but not earlier than on the middle line note. + */ + Real which_step = (min (1.0, quarter_stem_length - (2 * staff_rad) - 2.0)) + abs (hp[dir]); + Real shorten = min (max (0.0, (shortening_step * which_step)), shorten_property); length -= shorten; } @@ -344,7 +378,7 @@ Stem::calc_length (SCM smob) (Stem_tremolo::raw_stencil () looks at the beam.) --hwn */ Real minlen = 1.0 - + 2 * Stem_tremolo::vertical_length (t_flag) / ss; + + 2 * Stem_tremolo::vertical_length (t_flag) / ss; /* We don't want to add the whole extent of the flag because the trem and the flag can overlap partly. beam_translation gives a good @@ -363,7 +397,7 @@ Stem::calc_length (SCM smob) } length = max (length, minlen + 1.0); } - + return scm_from_double (length); } /* The log of the duration (Number of hooks on the flag minus two) */ @@ -378,14 +412,14 @@ MAKE_SCHEME_CALLBACK (Stem, calc_positioning_done, 1); SCM Stem::calc_positioning_done (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob_grob (smob); if (!head_count (me)) return SCM_BOOL_T; me->set_property ("positioning-done", SCM_BOOL_T); - + extract_grob_set (me, "note-heads", ro_heads); - vector heads (ro_heads); + vector heads (ro_heads); vector_sort (heads, position_less); Direction dir = get_grob_direction (me); @@ -404,8 +438,8 @@ Stem::calc_positioning_done (SCM smob) bool is_harmonic_centered = false; for (vsize i = 0; i < heads.size (); i++) - is_harmonic_centered = is_harmonic_centered - || heads[i]->get_property ("style") == ly_symbol2scm ("harmonic"); + is_harmonic_centered = is_harmonic_centered + || heads[i]->get_property ("style") == ly_symbol2scm ("harmonic"); is_harmonic_centered = is_harmonic_centered && is_invisible (me); Real w = hed->extent (hed, X_AXIS)[dir]; @@ -414,10 +448,10 @@ Stem::calc_positioning_done (SCM smob) Real amount = w - heads[i]->extent (heads[i], X_AXIS)[dir]; if (is_harmonic_centered) - amount = - hed->extent (hed, X_AXIS).linear_combination (CENTER) - - heads[i]->extent (heads[i], X_AXIS).linear_combination (CENTER); - + amount + = hed->extent (hed, X_AXIS).linear_combination (CENTER) + - heads[i]->extent (heads[i], X_AXIS).linear_combination (CENTER); + heads[i]->translate_axis (amount, X_AXIS); } bool parity = true; @@ -425,54 +459,54 @@ Stem::calc_positioning_done (SCM smob) for (vsize i = 1; i < heads.size (); i++) { Real p = Staff_symbol_referencer::get_position (heads[i]); - Real dy = fabs (lastpos- p); + Real dy = fabs (lastpos - p); /* - dy should always be 0.5, 0.0, 1.0, but provide safety margin - for rounding errors. + dy should always be 0.5, 0.0, 1.0, but provide safety margin + for rounding errors. */ if (dy < 1.1) - { - if (parity) - { - Real ell = heads[i]->extent (heads[i], X_AXIS).length (); + { + if (parity) + { + Real ell = heads[i]->extent (heads[i], X_AXIS).length (); - Direction d = get_grob_direction (me); - /* - Reversed head should be shifted ell-thickness, but this - looks too crowded, so we only shift ell-0.5*thickness. + Direction d = get_grob_direction (me); + /* + Reversed head should be shifted ell-thickness, but this + looks too crowded, so we only shift ell-0.5*thickness. - This leads to assymetry: Normal heads overlap the - stem 100% whereas reversed heads only overlaps the - stem 50% - */ + This leads to assymetry: Normal heads overlap the + stem 100% whereas reversed heads only overlaps the + stem 50% + */ - Real reverse_overlap = 0.5; - heads[i]->translate_axis ((ell - thick * reverse_overlap) * d, - X_AXIS); + Real reverse_overlap = 0.5; + heads[i]->translate_axis ((ell - thick * reverse_overlap) * d, + X_AXIS); - if (is_invisible (me)) - heads[i]->translate_axis (-thick * (2 - reverse_overlap) * d, - X_AXIS); + if (is_invisible (me)) + heads[i]->translate_axis (-thick * (2 - reverse_overlap) * d, + X_AXIS); - /* TODO: + /* TODO: - For some cases we should kern some more: when the - distance between the next or prev note is too large, we'd - get large white gaps, eg. + For some cases we should kern some more: when the + distance between the next or prev note is too large, we'd + get large white gaps, eg. - | + | X| - |X <- kern this. - | - X - - */ - } - parity = !parity; - } + |X <- kern this. + | + X + + */ + } + parity = !parity; + } else - parity = true; + parity = true; lastpos = int (p); } @@ -497,9 +531,9 @@ Stem::calc_direction (SCM smob) SCM dd = me->get_property ("default-direction"); dir = to_dir (dd); if (!dir) - return me->get_property ("neutral-direction"); + return me->get_property ("neutral-direction"); } - + return scm_from_int (dir); } @@ -516,14 +550,13 @@ Stem::calc_default_direction (SCM smob) { int udistance = (int) (UP * hp[UP] - staff_center); int ddistance = (int) (DOWN * hp[DOWN] - staff_center); - + dir = Direction (sign (ddistance - udistance)); } - + return scm_from_int (dir); } - MAKE_SCHEME_CALLBACK (Stem, height, 1); SCM Stem::height (SCM smob) @@ -531,9 +564,9 @@ Stem::height (SCM smob) Grob *me = unsmob_grob (smob); if (!is_normal_stem (me)) return ly_interval2scm (Interval ()); - + Direction dir = get_grob_direction (me); - + Grob *beam = get_beam (me); if (beam) { @@ -550,11 +583,11 @@ Stem::height (SCM smob) if (beam) { if (dir == CENTER) - { - programming_error ("no stem direction"); - dir = UP; - } - iv[dir] += dir * Beam::get_thickness (beam) * 0.5; + { + programming_error ("no stem direction"); + dir = UP; + } + iv[dir] += dir * Beam::get_beam_thickness (beam) * 0.5; } return ly_interval2scm (iv); @@ -566,17 +599,13 @@ Stem::stem_end_position (Grob *me) return robust_scm2double (me->get_property ("stem-end-position"), 0); } -Stencil -Stem::flag (Grob *me) +MAKE_SCHEME_CALLBACK (Stem, calc_flag, 1); +SCM +Stem::calc_flag (SCM smob) { - int log = duration_log (me); - if (log < 3 - || unsmob_grob (me->get_object ("beam"))) - return Stencil (); + Grob *me = unsmob_grob (smob); - if (!is_normal_stem (me)) - return Stencil (); - + int log = duration_log (me); /* TODO: maybe property stroke-style should take different values, e.g. "" (i.e. no stroke), "single" and "double" (currently, it's @@ -588,7 +617,7 @@ Stem::flag (Grob *me) flag_style = ly_symbol2string (flag_style_scm); if (flag_style == "no-flag") - return Stencil (); + return Stencil ().smobbed_copy (); bool adjust = true; @@ -603,20 +632,20 @@ Stem::flag (Grob *me) */ { if (adjust) - { - int p = (int) (rint (stem_end_position (me))); - staffline_offs - = Staff_symbol_referencer::on_line (me, p) ? "0" : "1"; - } + { + int p = (int) (rint (stem_end_position (me))); + staffline_offs + = Staff_symbol_referencer::on_line (me, p) ? "0" : "1"; + } else - staffline_offs = "2"; + staffline_offs = "2"; } else staffline_offs = ""; char dir = (get_grob_direction (me) == UP) ? 'u' : 'd'; string font_char = flag_style - + to_string (dir) + staffline_offs + to_string (log); + + to_string (dir) + staffline_offs + to_string (log); Font_metric *fm = Font_interface::get_default_font (me); Stencil flag = fm->find_by_name ("flags." + font_char); if (flag.is_empty ()) @@ -627,17 +656,47 @@ Stem::flag (Grob *me) { string stroke_style = ly_scm2string (stroke_style_scm); if (!stroke_style.empty ()) - { - string font_char = to_string (dir) + stroke_style; - Stencil stroke = fm->find_by_name ("flags." + font_char); - if (stroke.is_empty ()) - me->warning (_f ("flag stroke `%s' not found", font_char)); - else - flag.add_stencil (stroke); - } + { + string font_char = flag_style + to_string (dir) + stroke_style; + Stencil stroke = fm->find_by_name ("flags." + font_char); + if (stroke.is_empty ()) + { + font_char = to_string (dir) + stroke_style; + stroke = fm->find_by_name ("flags." + font_char); + } + if (stroke.is_empty ()) + me->warning (_f ("flag stroke `%s' not found", font_char)); + else + flag.add_stencil (stroke); + } } - return flag; + return flag.smobbed_copy (); +} + +Stencil +Stem::flag (Grob *me) +{ + int log = duration_log (me); + if (log < 3 + || unsmob_grob (me->get_object ("beam"))) + return Stencil (); + + if (!is_normal_stem (me)) + return Stencil (); + + // This get_property call already evaluates the scheme function with + // the grob passed as argument! Thus, we only have to check if a valid + // stencil is returned. + SCM flag_style_scm = me->get_property ("flag"); + if (Stencil *flag = unsmob_stencil (flag_style_scm)) + { + return *flag; + } + else + { + return Stencil (); + } } MAKE_SCHEME_CALLBACK (Stem, width, 1); @@ -651,7 +710,7 @@ Stem::width (SCM e) if (is_invisible (me)) r.set_empty (); else if (unsmob_grob (me->get_object ("beam")) - || abs (duration_log (me)) <= 2) + || abs (duration_log (me)) <= 2) { r = Interval (-1, 1); r *= thickness (me) / 2; @@ -668,7 +727,33 @@ Real Stem::thickness (Grob *me) { return scm_to_double (me->get_property ("thickness")) - * Staff_symbol_referencer::line_thickness (me); + * Staff_symbol_referencer::line_thickness (me); +} + +MAKE_SCHEME_CALLBACK (Stem, calc_stem_begin_position, 1); +SCM +Stem::calc_stem_begin_position (SCM smob) +{ + Grob *me = unsmob_grob (smob); + Direction d = get_grob_direction (me); + Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5; + Grob *lh + = to_boolean (me->get_property ("avoid-note-head")) + ? last_head (me) + : first_head (me); + + Real pos = Staff_symbol_referencer::get_position (lh); + + if (Grob *head = support_head (me)) + { + Interval head_height = head->extent (head, Y_AXIS); + Real y_attach = Note_head::stem_attachment_coordinate (head, Y_AXIS); + + y_attach = head_height.linear_combination (y_attach); + pos += d * y_attach / half_space; + } + + return scm_from_double (pos); } MAKE_SCHEME_CALLBACK (Stem, print, 1); @@ -677,20 +762,20 @@ Stem::print (SCM smob) { Grob *me = unsmob_grob (smob); Grob *beam = get_beam (me); - + Stencil mol; Direction d = get_grob_direction (me); Real stemlet_length = robust_scm2double (me->get_property ("stemlet-length"), - 0.0); + 0.0); bool stemlet = stemlet_length > 0.0; /* TODO: make the stem start a direction ? This is required to avoid stems passing in tablature chords. */ Grob *lh = to_boolean (me->get_property ("avoid-note-head")) - ? last_head (me) - : first_head (me); + ? last_head (me) + : first_head (me); if (!lh && !stemlet) return SCM_EOL; @@ -698,6 +783,9 @@ Stem::print (SCM smob) if (!lh && stemlet && !beam) return SCM_EOL; + if (lh && robust_scm2int (lh->get_property ("duration-log"), 0) < 1) + return SCM_EOL; + if (is_invisible (me)) return SCM_EOL; @@ -706,40 +794,28 @@ Stem::print (SCM smob) Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5; if (lh) - y2 = Staff_symbol_referencer::get_position (lh); + y2 = robust_scm2double (me->get_property ("stem-begin-position"), 0.0); else if (stemlet) { Real beam_translation = Beam::get_beam_translation (beam); - Real beam_thickness = Beam::get_thickness (beam); + Real beam_thickness = Beam::get_beam_thickness (beam); int beam_count = beam_multiplicity (me).length () + 1; y2 -= d - * (0.5 * beam_thickness - + beam_translation * max (0, (beam_count - 1)) - + stemlet_length) / half_space; + * (0.5 * beam_thickness + + beam_translation * max (0, (beam_count - 1)) + + stemlet_length) / half_space; } Interval stem_y (min (y1, y2), max (y2, y1)); - if (Grob *head = support_head (me)) - { - /* - must not take ledgers into account. - */ - Interval head_height = head->extent (head, Y_AXIS); - Real y_attach = Note_head::stem_attachment_coordinate (head, Y_AXIS); - - y_attach = head_height.linear_combination (y_attach); - stem_y[Direction (-d)] += d * y_attach / half_space; - } - // URG Real stem_width = thickness (me); Real blot = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")); Box b = Box (Interval (-stem_width / 2, stem_width / 2), - Interval (stem_y[DOWN] * half_space, stem_y[UP] * half_space)); + Interval (stem_y[DOWN] * half_space, stem_y[UP] * half_space)); Stencil ss = Lookup::round_filled_box (b, blot); mol.add_stencil (ss); @@ -757,7 +833,7 @@ Stem::get_translated_flag (Grob *me) { Direction d = get_grob_direction (me); Real blot - = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")); + = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")); Real stem_width = thickness (me); Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5; Real y2 = robust_scm2double (me->get_property ("stem-end-position"), 0.0); @@ -767,7 +843,6 @@ Stem::get_translated_flag (Grob *me) return fl; } - /* move the stem to right of the notehead if it is up. */ @@ -785,16 +860,15 @@ Stem::offset_callback (SCM smob) return scm_from_double (r); } - if (Grob *f = first_head (me)) { Interval head_wid = f->extent (f, X_AXIS); Real attach = 0.0; if (is_invisible (me)) - attach = 0.0; + attach = 0.0; else - attach = Note_head::stem_attachment_coordinate (f, X_AXIS); + attach = Note_head::stem_attachment_coordinate (f, X_AXIS); Direction d = get_grob_direction (me); Real real_attach = head_wid.linear_combination (d * attach); @@ -802,10 +876,10 @@ Stem::offset_callback (SCM smob) /* If not centered: correct for stem thickness. */ if (attach) - { - Real rule_thick = thickness (me); - r += -d * rule_thick * 0.5; - } + { + Real rule_thick = thickness (me); + r += -d * rule_thick * 0.5; + } return scm_from_double (r); } @@ -825,7 +899,7 @@ Stem::get_stem_info (Grob *me) { Stem_info si; si.dir_ = get_grob_direction (me); - + SCM scm_info = me->get_property ("stem-info"); si.ideal_y_ = scm_to_double (scm_car (scm_info)); si.shortest_y_ = scm_to_double (scm_cadr (scm_info)); @@ -852,68 +926,72 @@ Stem::calc_stem_info (SCM smob) { (void) beam->get_property ("beaming"); } - + Real beam_translation = Beam::get_beam_translation (beam); - Real beam_thickness = Beam::get_thickness (beam); + Real beam_thickness = Beam::get_beam_thickness (beam); int beam_count = Beam::get_direction_beam_count (beam, my_dir); Real length_fraction = robust_scm2double (me->get_property ("length-fraction"), 1.0); /* Simple standard stem length */ SCM details = me->get_property ("details"); - SCM lengths = scm_cdr (scm_assq (ly_symbol2scm ("beamed-lengths"), details)); - + SCM lengths = ly_assoc_get (ly_symbol2scm ("beamed-lengths"), details, SCM_EOL); + Real ideal_length - = scm_to_double (robust_list_ref (beam_count - 1, lengths)) - * staff_space - * length_fraction - - /* stem only extends to center of beam - */ - - 0.5 * beam_thickness; + = (scm_is_pair (lengths) + ? (scm_to_double (robust_list_ref (beam_count - 1, lengths)) + * staff_space + * length_fraction + /* + stem only extends to center of beam + */ + - 0.5 * beam_thickness) + : 0.0); /* Condition: sane minimum free stem length (chord to beams) */ - lengths = scm_cdr (scm_assq (ly_symbol2scm ("beamed-minimum-free-lengths"), details)); + lengths = ly_assoc_get (ly_symbol2scm ("beamed-minimum-free-lengths"), + details, SCM_EOL); Real ideal_minimum_free - = scm_to_double (robust_list_ref (beam_count - 1, lengths)) - * staff_space - * length_fraction; + = (scm_is_pair (lengths) + ? (scm_to_double (robust_list_ref (beam_count - 1, lengths)) + * staff_space + * length_fraction) + : 0.0); Real height_of_my_trem = 0.0; Grob *trem = unsmob_grob (me->get_object ("tremolo-flag")); if (trem) { height_of_my_trem - = Stem_tremolo::vertical_length (trem) - /* hack a bit of space around the trem. */ - + beam_translation; + = Stem_tremolo::vertical_length (trem) + /* hack a bit of space around the trem. */ + + beam_translation; } - /* UGH It seems that also for ideal minimum length, we must use the maximum beam count (for this direction): - \score{ \notes\relative c''{ [a8 a32] }} + \score { \relative c'' { a8[ a32] } } must be horizontal. */ Real height_of_my_beams = beam_thickness - + (beam_count - 1) * beam_translation; + + (beam_count - 1) * beam_translation; Real ideal_minimum_length = ideal_minimum_free - + height_of_my_beams - + height_of_my_trem - /* stem only extends to center of beam */ - - 0.5 * beam_thickness; + + height_of_my_beams + + height_of_my_trem + /* stem only extends to center of beam */ + - 0.5 * beam_thickness; ideal_length = max (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 * staff_space; + head_positions (me)[my_dir] * 0.5 + * my_dir * staff_space; Real ideal_y = note_start + ideal_length; /* Conditions for Y position */ @@ -936,34 +1014,36 @@ Stem::calc_stem_info (SCM smob) if (!no_extend && !is_knee) { /* Highest beam of (UP) beam must never be lower than middle - staffline */ + staffline */ ideal_y = max (ideal_y, 0.0); /* Lowest beam of (UP) beam must never be lower than second staffline */ ideal_y = max (ideal_y, (-staff_space - - beam_thickness + height_of_my_beams)); + - beam_thickness + height_of_my_beams)); } ideal_y -= robust_scm2double (beam->get_property ("shorten"), 0); - SCM bemfl = scm_cdr (scm_assq (ly_symbol2scm ("beamed-extreme-minimum-free-lengths"), - details)); - + SCM bemfl = ly_assoc_get (ly_symbol2scm ("beamed-extreme-minimum-free-lengths"), + details, SCM_EOL); + Real minimum_free - = scm_to_double (robust_list_ref (beam_count - 1, bemfl)) - * staff_space - * length_fraction; + = (scm_is_pair (bemfl) + ? (scm_to_double (robust_list_ref (beam_count - 1, bemfl)) + * staff_space + * length_fraction) + : 0.0); Real minimum_length = max (minimum_free, height_of_my_trem) - + height_of_my_beams - /* stem only extends to center of beam */ - - 0.5 * beam_thickness; + + height_of_my_beams + /* stem only extends to center of beam */ + - 0.5 * beam_thickness; ideal_y *= my_dir; Real minimum_y = note_start + minimum_length; Real shortest_y = minimum_y * my_dir; return scm_list_2 (scm_from_double (ideal_y), - scm_from_double (shortest_y)); + scm_from_double (shortest_y)); } Slice @@ -992,53 +1072,60 @@ Stem::calc_cross_staff (SCM smob) /* FIXME: Too many properties */ ADD_INTERFACE (Stem, - "The stem represent the graphical stem. " - "In addition, it internally connects note heads, beams and" - "tremolos. " - "Rests and whole notes have invisible stems." - - "\n\nThe following properties may be set in the details list." - "@table @code\n" - "@item beamed-lengths \n" - "list of stem lengths given beam multiplicity. \n" - "@item beamed-minimum-free-lengths \n" - "list of normal minimum free stem lengths (chord to beams) given beam multiplicity.\n" - "@item beamed-extreme-minimum-free-lengths\n" - "list of extreme minimum free stem lengths (chord to beams) given beam multiplicity.\n" - "@item lengths\n" - "Default stem lengths. The list gives a length for each flag-count.\n" - "@item stem-shorten\n" - "How much a stem in a forced direction " - "should be shortened. The list gives an amount depending on the number " - "of flags/beams." - "@end table\n" - , - - /* properties */ - "avoid-note-head " - "beam " - "beaming " - "default-direction " - "details " - "direction " - "duration-log " - "flag-style " - "french-beaming " - "length " - "length-fraction " - "max-beam-connect " - "neutral-direction " - "no-stem-extend " - "note-heads " - "positioning-done " - "rests " - "stem-end-position " - "stem-info " - "stemlet-length " - "stroke-style " - "thickness " - "tremolo-flag " - ); + "The stem represents the graphical stem. In addition, it" + " internally connects note heads, beams, and tremolos. Rests" + " and whole notes have invisible stems.\n" + "\n" + "The following properties may be set in the @code{details}" + " list.\n" + "\n" + "@table @code\n" + "@item beamed-lengths\n" + "List of stem lengths given beam multiplicity.\n" + "@item beamed-minimum-free-lengths\n" + "List of normal minimum free stem lengths (chord to beams)" + " given beam multiplicity.\n" + "@item beamed-extreme-minimum-free-lengths\n" + "List of extreme minimum free stem lengths (chord to beams)" + " given beam multiplicity.\n" + "@item lengths\n" + "Default stem lengths. The list gives a length for each" + " flag count.\n" + "@item stem-shorten\n" + "How much a stem in a forced direction should be shortened." + " The list gives an amount depending on the number of flags" + " and beams.\n" + "@end table\n", + + /* properties */ + "avoid-note-head " + "beam " + "beaming " + "beamlet-default-length " + "beamlet-max-length-proportion " + "default-direction " + "details " + "direction " + "duration-log " + "flag " + "flag-style " + "french-beaming " + "length " + "length-fraction " + "max-beam-connect " + "neutral-direction " + "no-stem-extend " + "note-heads " + "positioning-done " + "rests " + "stem-begin-position " + "stem-end-position " + "stem-info " + "stemlet-length " + "stroke-style " + "thickness " + "tremolo-flag " + ); /****************************************************************/