(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):
+2002-08-12 Jan Nieuwenhuizen <janneke@gnu.org>
+
+ * 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 <hanwen@cs.uu.nl>
* VERSION: 1.5.72 released
(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))))))
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 |
}
--- /dev/null
+\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
--- /dev/null
+\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
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);
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;
}
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);
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);
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));
}
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];
/*
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++;
}
class Stem
{
public:
- DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM ));
-
- static Array<int> 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<Grob*> 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<int> 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<Grob*> 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
}
}
-
Real shorten_f = 0.0;
SCM sshorten = me->get_grob_property ("stem-shorten");
return gh_double2scm (r);
}
-
-
Grob*
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)
{
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");
(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)
(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)
(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