]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/stem.cc
Imported Upstream version 2.14.2
[lilypond.git] / lily / stem.cc
index 8ba6f2b6c9cdba33022481ba5b0113d4abdecfbe..04bc4105922e0ecfbca2ea41da058b007ff25fe7 100644 (file)
@@ -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--2009 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
@@ -11,6 +9,19 @@
   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"
@@ -244,7 +255,13 @@ Stem::pure_height (SCM smob,
 
   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);
@@ -254,7 +271,10 @@ Stem::pure_height (SCM smob,
        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)
@@ -311,6 +331,7 @@ Stem::calc_length (SCM smob)
   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))
@@ -326,11 +347,25 @@ Stem::calc_length (SCM smob)
       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;
     }
@@ -557,7 +592,7 @@ Stem::height (SCM smob)
          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);
@@ -740,7 +775,7 @@ Stem::print (SCM smob)
   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
@@ -884,7 +919,7 @@ Stem::calc_stem_info (SCM smob)
     }
   
   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);
@@ -894,21 +929,26 @@ Stem::calc_stem_info (SCM smob)
   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"));
@@ -925,7 +965,7 @@ Stem::calc_stem_info (SCM smob)
      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
@@ -979,9 +1019,11 @@ Stem::calc_stem_info (SCM smob)
                            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