From 97b66b1443a8907763d0e6c5e3ee9c1834bb02b5 Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Fri, 31 Aug 2012 09:24:31 +0200 Subject: [PATCH] Better automation of tremolo direction for whole note tremolos. --- .../regression/stem-tremolo-note-collision.ly | 20 ++++ lily/include/note-collision.hh | 1 + lily/include/stem-tremolo.hh | 1 + lily/note-collision.cc | 16 ++++ lily/stem-tremolo.cc | 95 +++++++++++++------ scm/define-grobs.scm | 1 + 6 files changed, 105 insertions(+), 29 deletions(-) create mode 100644 input/regression/stem-tremolo-note-collision.ly diff --git a/input/regression/stem-tremolo-note-collision.ly b/input/regression/stem-tremolo-note-collision.ly new file mode 100644 index 0000000000..6b5b32a93c --- /dev/null +++ b/input/regression/stem-tremolo-note-collision.ly @@ -0,0 +1,20 @@ +\version "2.17.2" + +\header { + texidoc = "Tremolos should avoid other notes in the staff as +best as possible and issue a warning otherwise. +" +} + +#(ly:expect-warning (_ "ignoring too many clashing note columns")) + +{ +<< + { b'4 f'2. } + \\ + { + \grace a8 + \repeat tremolo 32 32 + } +>> +} \ No newline at end of file diff --git a/lily/include/note-collision.hh b/lily/include/note-collision.hh index ae0f3271b0..db192bf19a 100644 --- a/lily/include/note-collision.hh +++ b/lily/include/note-collision.hh @@ -40,6 +40,7 @@ public: static SCM automatic_shift (Grob *, Drul_array >); static SCM forced_shift (Grob *); + static vector note_head_positions (Grob *me); static Drul_array > get_clash_groups (Grob *me); DECLARE_SCHEME_CALLBACK (calc_positioning_done, (SCM smob)); static void add_column (Grob *me, Grob *ncol); diff --git a/lily/include/stem-tremolo.hh b/lily/include/stem-tremolo.hh index 03a6f8c908..7137046d30 100644 --- a/lily/include/stem-tremolo.hh +++ b/lily/include/stem-tremolo.hh @@ -35,6 +35,7 @@ public: DECLARE_SCHEME_CALLBACK (print, (SCM)); DECLARE_SCHEME_CALLBACK (width, (SCM)); DECLARE_SCHEME_CALLBACK (calc_style, (SCM)); + DECLARE_SCHEME_CALLBACK (calc_direction, (SCM)); DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM)); static Stencil raw_stencil (Grob *, Real slope, Direction stemdir); static Real y_offset (Grob *, bool pure); diff --git a/lily/note-collision.cc b/lily/note-collision.cc index 3ab245ca5e..cf0e013b9d 100644 --- a/lily/note-collision.cc +++ b/lily/note-collision.cc @@ -593,6 +593,22 @@ Note_collision_interface::add_column (Grob *me, Grob *ncol) Axis_group_interface::add_element (me, ncol); } +vector +Note_collision_interface::note_head_positions (Grob *me) +{ + vector out; + extract_grob_set (me, "elements", elts); + for (vsize i = 0; i < elts.size (); i++) + if (Grob *stem = unsmob_grob (elts[i]->get_object ("stem"))) + { + vector nhp = Stem::note_head_positions (stem); + out.insert (out.end (), nhp.begin (), nhp.end ()); + } + + vector_sort (out, less ()); + return out; +} + ADD_INTERFACE (Note_collision_interface, "An object that handles collisions between notes with" " different stem directions and horizontal shifts. Most of" diff --git a/lily/stem-tremolo.cc b/lily/stem-tremolo.cc index d48091537a..5c5ee051d4 100644 --- a/lily/stem-tremolo.cc +++ b/lily/stem-tremolo.cc @@ -24,6 +24,8 @@ #include "directional-element-interface.hh" #include "item.hh" #include "lookup.hh" +#include "note-collision.hh" +#include "note-column.hh" #include "output-def.hh" #include "staff-symbol-referencer.hh" #include "stem.hh" @@ -56,7 +58,7 @@ Stem_tremolo::calc_slope (SCM smob) else /* down stems with flags should have more sloped trems (helps avoid flag/stem collisions without making the stem very long) */ - return scm_from_double ((Stem::duration_log (stem) >= 3 && get_grob_direction (stem) == DOWN) + return scm_from_double ((Stem::duration_log (stem) >= 3 && get_grob_direction (me) == DOWN) ? 0.40 : 0.25); } @@ -66,12 +68,12 @@ Stem_tremolo::calc_width (SCM smob) { Grob *me = unsmob_grob (smob); Grob *stem = unsmob_grob (me->get_object ("stem")); - Direction stemdir = get_grob_direction (stem); + Direction dir = get_grob_direction (me); bool beam = Stem::get_beam (stem); bool flag = Stem::duration_log (stem) >= 3 && !beam; /* beamed stems and up-stems with flags have shorter tremolos */ - return scm_from_double (((stemdir == UP && flag) || beam) ? 1.0 : 1.5); + return scm_from_double (((dir == UP && flag) || beam) ? 1.0 : 1.5); } MAKE_SCHEME_CALLBACK (Stem_tremolo, calc_style, 1) @@ -80,11 +82,11 @@ Stem_tremolo::calc_style (SCM smob) { Grob *me = unsmob_grob (smob); Grob *stem = unsmob_grob (me->get_object ("stem")); - Direction stemdir = get_grob_direction (stem); + Direction dir = get_grob_direction (me); bool beam = Stem::get_beam (stem); bool flag = Stem::duration_log (stem) >= 3 && !beam; - return ly_symbol2scm (((stemdir == UP && flag) || beam) ? "rectangle" : "default"); + return ly_symbol2scm (((dir == UP && flag) || beam) ? "rectangle" : "default"); } Real @@ -100,7 +102,7 @@ Stem_tremolo::get_beam_translation (Grob *me) } Stencil -Stem_tremolo::raw_stencil (Grob *me, Real slope, Direction stemdir) +Stem_tremolo::raw_stencil (Grob *me, Real slope, Direction dir) { Real ss = Staff_symbol_referencer::staff_space (me); Real thick = robust_scm2double (me->get_property ("beam-thickness"), 1); @@ -137,7 +139,7 @@ Stem_tremolo::raw_stencil (Grob *me, Real slope, Direction stemdir) for (int i = 0; i < tremolo_flags; i++) { Stencil b (a); - b.translate_axis (beam_translation * i * stemdir * -1, Y_AXIS); + b.translate_axis (beam_translation * i * dir * -1, Y_AXIS); mol.add_stencil (b); } return mol; @@ -157,9 +159,7 @@ Stem_tremolo::pure_height (SCM smob, SCM, SCM) if (!stem) return ly_interval2scm (s1.extent (Y_AXIS)); - Direction stemdir = get_grob_direction (stem); - if (stemdir == 0) - stemdir = UP; + Direction dir = get_grob_direction (me); Spanner *beam = Stem::get_beam (stem); @@ -168,11 +168,11 @@ Stem_tremolo::pure_height (SCM smob, SCM, SCM) Interval ph = stem->pure_height (stem, 0, INT_MAX); Stem_info si = Stem::get_stem_info (stem); - ph[-stemdir] = si.shortest_y_; + ph[-dir] = si.shortest_y_; int beam_count = Stem::beam_multiplicity (stem).length () + 1; Real beam_translation = get_beam_translation (me); - ph = ph - stemdir * max (beam_count, 1) * beam_translation; + ph = ph - dir * max (beam_count, 1) * beam_translation; ph = ph - ph.center (); return ly_interval2scm (ph); @@ -208,15 +208,13 @@ Stem_tremolo::untranslated_stencil (Grob *me, Real slope) return Stencil (); } - Direction stemdir = get_grob_direction (stem); - if (!stemdir) - stemdir = UP; + Direction dir = get_grob_direction (me); bool whole_note = Stem::duration_log (stem) <= 0; /* for a whole note, we position relative to the notehead, so we want the stencil aligned on the flag closest to the head */ - Direction stencil_dir = whole_note ? -stemdir : stemdir; + Direction stencil_dir = whole_note ? -dir : dir; return raw_stencil (me, slope, stencil_dir); } @@ -238,6 +236,46 @@ Stem_tremolo::pure_calc_y_offset (SCM smob, return scm_from_double (y_offset (me, true)); } +MAKE_SCHEME_CALLBACK (Stem_tremolo, calc_direction, 1); +SCM +Stem_tremolo::calc_direction (SCM smob) +{ + Item *me = unsmob_item (smob); + + Item *stem = unsmob_item (me->get_object ("stem")); + if (!stem) + return scm_from_int (CENTER); + + Direction stemdir = get_grob_direction (stem); + + vector nhp = Stem::note_head_positions (stem); + /* + * We re-decide stem-dir if there may be collisions with other + * note heads in the staff. + */ + Grob *maybe_nc = stem->get_parent (X_AXIS)->get_parent (X_AXIS); + bool whole_note = Stem::duration_log (stem) <= 0; + if (whole_note && Note_collision_interface::has_interface (maybe_nc)) + { + Drul_array avoid_me (false, false); + vector all_nhps = Note_collision_interface::note_head_positions (maybe_nc); + if (all_nhps[0] < nhp[0]) + avoid_me[DOWN] = true; + if (all_nhps.back () > nhp.back ()) + avoid_me[UP] = true; + if (avoid_me[stemdir]) + { + stemdir = -stemdir; + if (avoid_me[stemdir]) + { + me->warning ("Whole-note tremolo may collide with simultaneous notes."); + stemdir = -stemdir; + } + } + } + return scm_from_int (stemdir); +} + Real Stem_tremolo::y_offset (Grob *me, bool pure) { @@ -245,9 +283,7 @@ Stem_tremolo::y_offset (Grob *me, bool pure) if (!stem) return 0.0; - Direction stemdir = get_grob_direction (stem); - if (stemdir == 0) - stemdir = UP; + Direction dir = get_grob_direction (me); Spanner *beam = Stem::get_beam (stem); Real beam_translation = get_beam_translation (me); @@ -258,23 +294,23 @@ Stem_tremolo::y_offset (Grob *me, bool pure) { Interval ph = stem->pure_height (stem, 0, INT_MAX); Stem_info si = Stem::get_stem_info (stem); - ph[-stemdir] = si.shortest_y_; + ph[-dir] = si.shortest_y_; - return (ph - stemdir * max (beam_count, 1) * beam_translation)[stemdir] - stemdir * 0.5 * me->pure_height (me, 0, INT_MAX).length (); + return (ph - dir * max (beam_count, 1) * beam_translation)[dir] - dir * 0.5 * me->pure_height (me, 0, INT_MAX).length (); } Real end_y = (pure - ? stem->pure_height (stem, 0, INT_MAX)[stemdir] - : stem->extent (stem, Y_AXIS)[stemdir]) - - stemdir * max (beam_count, 1) * beam_translation + ? stem->pure_height (stem, 0, INT_MAX)[dir] + : stem->extent (stem, Y_AXIS)[dir]) + - dir * max (beam_count, 1) * beam_translation - Stem::beam_end_corrective (stem); if (!beam && Stem::duration_log (stem) >= 3) { - end_y -= stemdir * (Stem::duration_log (stem) - 2) * beam_translation; - if (stemdir == UP) - end_y -= stemdir * beam_translation * 0.5; + end_y -= dir * (Stem::duration_log (stem) - 2) * beam_translation; + if (dir == UP) + end_y -= dir * beam_translation * 0.5; } bool whole_note = Stem::duration_log (stem) <= 0; @@ -284,8 +320,8 @@ Stem_tremolo::y_offset (Grob *me, bool pure) is invisible */ Real ss = Staff_symbol_referencer::staff_space (me); vector nhp = Stem::note_head_positions (stem); - Real note_head = (stemdir == UP ? nhp.back () : nhp[0]) * ss / 2; - end_y = note_head + stemdir * 1.5; + Real note_head = (dir == UP ? nhp.back () : nhp[0]) * ss / 2; + end_y = note_head + dir * 1.5; } return end_y; @@ -308,6 +344,7 @@ ADD_INTERFACE (Stem_tremolo, /* properties */ "beam-thickness " "beam-width " + "direction " "flag-count " "length-fraction " "stem " diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 40218b3d2d..7c709cac9d 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -2038,6 +2038,7 @@ . ( (beam-thickness . 0.48) ; staff-space (beam-width . ,ly:stem-tremolo::calc-width) ; staff-space + (direction . ,ly:stem-tremolo::calc-direction) (slope . ,ly:stem-tremolo::calc-slope) (stencil . ,ly:stem-tremolo::print) (style . ,ly:stem-tremolo::calc-style) -- 2.39.5