]> git.donarmstrong.com Git - lilypond.git/commitdiff
Uses a heuristic to determine if chord tremolos collide with accidentals.
authorMike Solomon <mike@apollinemike.com>
Fri, 31 Aug 2012 07:27:17 +0000 (09:27 +0200)
committerMike Solomon <mike@apollinemike.com>
Fri, 31 Aug 2012 07:27:17 +0000 (09:27 +0200)
This heuristic makes several assumptions about when a chord tremolo
will collide with accidentals. It must be between whole notes, it
must be in the staff, and it must be an ascending major third or lower.
The heuristic is entirely contained in Beam::whole_note_close_chord_tremolo,
which should be modified if other cases involving chord tremolos arise.

input/regression/chord-tremolo-accidental.ly [new file with mode: 0644]
lily/beam.cc
lily/include/beam.hh
lily/include/note-column.hh
lily/note-column.cc
lily/paper-column.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

diff --git a/input/regression/chord-tremolo-accidental.ly b/input/regression/chord-tremolo-accidental.ly
new file mode 100644 (file)
index 0000000..f5a89cb
--- /dev/null
@@ -0,0 +1,18 @@
+\version "2.17.2"
+
+\header {
+  texidoc = "Chord tremolos adapt to the presence of accidentals.
+"
+}
+
+{
+  \repeat tremolo 16 { c''32 d'' }
+  \repeat tremolo 16 { c''32 <dis''> }
+  \repeat tremolo 16 { c''32 <dis'' fis''> }
+  \repeat tremolo 8 { c''32 d'' }
+  \repeat tremolo 8 { c''32 <dis''> }
+  \repeat tremolo 8 { c''32 <dis'' fis''> }
+  \repeat tremolo 4 { c''32 d'' }
+  \repeat tremolo 4 { c''32 <dis''> }
+  \repeat tremolo 16 { b''32 <cis'''> }
+}
\ No newline at end of file
index e5ea57d53b0089233e3897e88d276b840dc0be35..32bf7c3bd468618c13668fa2014dcd72d355d0f6 100644 (file)
@@ -49,6 +49,7 @@
 #include "lookup.hh"
 #include "main.hh"
 #include "misc.hh"
+#include "note-column.hh"
 #include "note-head.hh"
 #include "output-def.hh"
 #include "pointer-group-interface.hh"
@@ -141,6 +142,92 @@ Beam::get_beam_count (Grob *me)
   return m;
 }
 
+//------ for whole note chord tremolos
+
+bool
+Beam::whole_note_close_chord_tremolo (Grob *me)
+{
+  if (!scm_is_integer (me->get_property ("gap-count")))
+    return false;
+
+  extract_grob_set (me, "stems", stems);
+  for (vsize i = 0; i < stems.size (); i++)
+    if (Stem::duration_log (stems[i]))
+      return false;
+
+  Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
+  if (staff)
+    {
+      Grob *outside_stems[2] = {Stem::extremal_heads (stems[0])[DOWN],
+                                Stem::extremal_heads (stems.back ())[DOWN]};
+
+      Interval lines = Staff_symbol::line_span (staff);
+      for (int i = 0; i < 2; i++)
+        {
+          Real my_pos = Staff_symbol_referencer::get_position (outside_stems[i]);
+          if (my_pos > lines[UP] + 1)
+            return false;
+          else if (my_pos < lines[DOWN] - 1)
+            return false;
+        }
+    }
+
+  return (Staff_symbol_referencer::get_position (Stem::extremal_heads (stems.back ())[DOWN])
+          - Staff_symbol_referencer::get_position (Stem::extremal_heads (stems[0])[DOWN]))
+         < 2;
+}
+
+MAKE_SCHEME_CALLBACK (Beam, calc_beam_gap, 1);
+SCM
+Beam::calc_beam_gap (SCM smob)
+{
+  Spanner *me = unsmob_spanner (smob);
+  SCM default_value = scm_cons (scm_from_double (0.8), scm_from_double (0.8));
+  if (!whole_note_close_chord_tremolo (me))
+    return default_value;
+
+  Interval left = Note_column::accidental_width
+                    (me->get_bound (RIGHT)->get_parent (X_AXIS));
+
+  if (left.length () > 0.4)
+    return scm_cons (scm_from_double (0.8), scm_from_double (1.3 + left.length ()));
+  else
+    return default_value;
+}
+
+MAKE_SCHEME_CALLBACK (Beam, calc_springs_and_rods, 1);
+SCM
+Beam::calc_springs_and_rods (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  if (!whole_note_close_chord_tremolo (me))
+    return SCM_BOOL_F;
+
+  return scm_call_1 (Spanner::set_spacing_rods_proc, smob);
+}
+
+MAKE_SCHEME_CALLBACK (Beam, calc_minimum_length, 1);
+SCM
+Beam::calc_minimum_length (SCM smob)
+{
+  Spanner *me = unsmob_spanner (smob);
+  SCM default_value = scm_from_double (0.0);
+
+  if (!whole_note_close_chord_tremolo (me))
+    return SCM_BOOL_F;
+
+  Interval left = Note_column::accidental_width
+                    (me->get_bound (RIGHT)->get_parent (X_AXIS));
+
+  if (left.length () > 0.4)
+    return scm_from_double (left.length () + 4.0);
+  else
+    return default_value;
+}
+
+//------ and everything else
+
 MAKE_SCHEME_CALLBACK (Beam, calc_normal_stems, 1);
 SCM
 Beam::calc_normal_stems (SCM smob)
@@ -353,7 +440,7 @@ Beam::calc_beam_segments (SCM smob)
     commonx = me->get_bound (d)->common_refpoint (commonx, X_AXIS);
 
   int gap_count = robust_scm2int (me->get_property ("gap-count"), 0);
-  Real gap_length = robust_scm2double (me->get_property ("gap"), 0.0);
+  Interval gap_lengths = robust_scm2interval (me->get_property ("beam-gap"), Interval (0.0, 0.0));
 
   Position_stem_segments_map stem_segments;
   Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
@@ -509,7 +596,7 @@ Beam::calc_beam_segments (SCM smob)
                   current.horizontal_[event_dir] += event_dir * seg.width_ / 2;
                   if (seg.gapped_)
                     {
-                      current.horizontal_[event_dir] -= event_dir * gap_length;
+                      current.horizontal_[event_dir] -= event_dir * gap_lengths[event_dir];
 
                       if (Stem::is_invisible (seg.stem_))
                         {
@@ -522,7 +609,7 @@ Beam::calc_beam_segments (SCM smob)
                           for (vsize k = 0; k < heads.size (); k++)
                             current.horizontal_[event_dir]
                               = event_dir * min (event_dir * current.horizontal_[event_dir],
-                                                 - gap_length / 2
+                                                 - gap_lengths[event_dir] / 2
                                                  + event_dir
                                                  * heads[k]->extent (commonx,
                                                                      X_AXIS)[-event_dir]);
@@ -1481,6 +1568,7 @@ ADD_INTERFACE (Beam,
                "auto-knee-gap "
                "beamed-stem-shorten "
                "beaming "
+               "beam-gap "
                "beam-segments "
                "beam-thickness "
                "break-overshoot "
@@ -1492,7 +1580,6 @@ ADD_INTERFACE (Beam,
                "damping "
                "details "
                "direction "
-               "gap "
                "gap-count "
                "grow-direction "
                "inspect-quants "
index 116ae6aa5730a72ad616594c69bc89bb34991672..c26d8d213785f770a29cff6a7072fe54d1a500fb 100644 (file)
@@ -72,6 +72,9 @@ public:
   DECLARE_SCHEME_CALLBACK (rest_collision_callback, (SCM element, SCM prev_off));
   DECLARE_SCHEME_CALLBACK (pure_rest_collision_callback, (SCM element, SCM, SCM, SCM prev_off));
   DECLARE_SCHEME_CALLBACK (print, (SCM));
+  DECLARE_SCHEME_CALLBACK (calc_beam_gap, (SCM));
+  DECLARE_SCHEME_CALLBACK (calc_springs_and_rods, (SCM));
+  DECLARE_SCHEME_CALLBACK (calc_minimum_length, (SCM));
   DECLARE_SCHEME_CALLBACK (calc_beaming, (SCM));
   DECLARE_SCHEME_CALLBACK (calc_stem_shorten, (SCM));
   DECLARE_SCHEME_CALLBACK (calc_direction, (SCM));
@@ -89,6 +92,7 @@ public:
 private:
   friend class Beam_scoring_problem;
 
+  static bool whole_note_close_chord_tremolo (Grob *me);
   static Direction get_default_dir (Grob *);
   static vector<Beam_segment> get_beam_segments (Grob *);
   static void set_stem_directions (Grob *, Direction);
index 280a5c969f474c1c3996fe42365025a224678e19..874b54207539a8238cfcd7d777a74c0c14e3e516 100644 (file)
@@ -43,6 +43,7 @@ public:
   static bool has_rests (Grob *me);
   static Grob *dot_column (Grob *me);
   static Interval cross_staff_extent (Grob *me, Grob *refp);
+  static Interval accidental_width (Grob *me);
   DECLARE_GROB_INTERFACE ();
 
   static Item *get_stem (Grob *);
index da52093797fb1f3b98c91f42c07ad0835f70a441..7f9bac8eca3bb4305b68278b8eaa07cb9a2f3e96 100644 (file)
@@ -40,6 +40,31 @@ using namespace std;
   annoying layer between (rest)collision & (note-head + stem)
 */
 
+Interval
+Note_column::accidental_width (Grob *me)
+{
+  extract_grob_set (me, "note-heads", nhs);
+  vector<Grob *> accs;
+  for (vsize i = 0; i < nhs.size (); i++)
+    if (Grob *acc = unsmob_grob (nhs[i]->get_object ("accidental-grob")))
+      accs.push_back (acc);
+
+  Grob *common = common_refpoint_of_array (accs, me, X_AXIS);
+  common = common_refpoint_of_array (nhs, common, X_AXIS);
+
+  Interval nhs_ex = Axis_group_interface::relative_group_extent (nhs, common, X_AXIS);
+  Interval accs_ex = Axis_group_interface::relative_group_extent (accs, common, X_AXIS);
+
+  if (nhs_ex.is_empty ())
+    return accs_ex;
+
+  // want an empty interval here
+  if (accs_ex.is_empty ())
+    return Interval ();
+
+  return Interval (accs_ex[LEFT], nhs_ex[LEFT]);
+}
+
 bool
 Note_column::has_rests (Grob *me)
 {
index cdf3d595ca554ec9ee0c1afcf5deaf9fa7aa493f..78f2786ef89b34f41cefcb63cc8d8e4c352a9bbf 100644 (file)
@@ -27,6 +27,7 @@
 #include "lookup.hh"
 #include "lookup.hh"
 #include "moment.hh"
+#include "note-head.hh"
 #include "output-def.hh"
 #include "paper-score.hh"
 #include "pointer-group-interface.hh"
@@ -218,6 +219,7 @@ Paper_column::break_align_width (Grob *me, SCM align_sym)
   return align->extent (p, X_AXIS);
 }
 
+
 /*
   Print a vertical line and  the rank number, to aid debugging.
 */
index 5083c0e5f1b119f16e098fb7499ac6d47d8afccb..ce260d33cc5ee39c53fcb83bbb5881d0dc0a40cb 100644 (file)
@@ -108,6 +108,7 @@ default length of the beamlet to the right.  The actual length of a
 beamlet is determined by taking either the default length or the
 length specified by @code{beamlet-max-length-proportion}, whichever is
 smaller.")
+     (beam-gap ,number-pair? "Size of a gap in a @code{Beam}.")
      (beamlet-max-length-proportion ,pair? "The maximum length of a
 beamlet, as a proportion of the distance between two adjacent stems.")
      (before-line-breaking ,boolean? "Dummy property, used to trigger
index 7c709cac9d14c2a402ca89cd004ecb9380049ce4..df551b2d6fa2b0b1ba61f5a21ebe7db5317fac1e 100644 (file)
        ;; only for debugging.
        (font-family . roman)
 
-       (gap . 0.8)
+       (beam-gap . ,ly:beam::calc-beam-gap)
+       (minimum-length . ,ly:beam::calc-minimum-length)
        (neutral-direction . ,DOWN)
        (positions . ,beam::place-broken-parts-individually)
+       (springs-and-rods . ,ly:beam::calc-springs-and-rods)
        (X-positions . ,ly:beam::calc-x-positions)
 
        ;; this is a hack to set stem lengths, if positions is set.