/*
- stem.cc -- implement Stem
+ This file is part of LilyPond, the GNU music typesetter.
- source file of the GNU LilyPond music typesetter
-
- (c) 1996--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
TODO: This is way too hairy
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 <http://www.gnu.org/licenses/>.
*/
#include "stem.hh"
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);
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);
+ }
/* extend the stem (away from the head) to cover the staff */
if (dir == UP)
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 = ly_assoc_get (ly_symbol2scm ("lengths"), details, SCM_EOL);
if (scm_is_pair (s))
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;
+ 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;
}
programming_error ("no stem direction");
dir = UP;
}
- iv[dir] += dir * Beam::get_thickness (beam) * 0.5;
+ iv[dir] += dir * Beam::get_beam_thickness (beam) * 0.5;
}
return ly_interval2scm (iv);
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
}
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);
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 = ly_assoc_get (ly_symbol2scm ("beamed-minimum-free-lengths"), details, SCM_EOL);
+ 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"));
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
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