From: Mike Solomon Date: Fri, 31 Aug 2012 07:27:17 +0000 (+0200) Subject: Uses a heuristic to determine if chord tremolos collide with accidentals. X-Git-Tag: release/2.17.2-1~30 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=d8dfa746ead381a80901106b9c9b079dc9b5d004;p=lilypond.git Uses a heuristic to determine if chord tremolos collide with accidentals. 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. --- diff --git a/input/regression/chord-tremolo-accidental.ly b/input/regression/chord-tremolo-accidental.ly new file mode 100644 index 0000000000..f5a89cb6fb --- /dev/null +++ b/input/regression/chord-tremolo-accidental.ly @@ -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 } + \repeat tremolo 16 { c''32 } + \repeat tremolo 8 { c''32 d'' } + \repeat tremolo 8 { c''32 } + \repeat tremolo 8 { c''32 } + \repeat tremolo 4 { c''32 d'' } + \repeat tremolo 4 { c''32 } + \repeat tremolo 16 { b''32 } +} \ No newline at end of file diff --git a/lily/beam.cc b/lily/beam.cc index e5ea57d53b..32bf7c3bd4 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -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 " diff --git a/lily/include/beam.hh b/lily/include/beam.hh index 116ae6aa57..c26d8d2137 100644 --- a/lily/include/beam.hh +++ b/lily/include/beam.hh @@ -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 get_beam_segments (Grob *); static void set_stem_directions (Grob *, Direction); diff --git a/lily/include/note-column.hh b/lily/include/note-column.hh index 280a5c969f..874b542075 100644 --- a/lily/include/note-column.hh +++ b/lily/include/note-column.hh @@ -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 *); diff --git a/lily/note-column.cc b/lily/note-column.cc index da52093797..7f9bac8eca 100644 --- a/lily/note-column.cc +++ b/lily/note-column.cc @@ -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 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) { diff --git a/lily/paper-column.cc b/lily/paper-column.cc index cdf3d595ca..78f2786ef8 100644 --- a/lily/paper-column.cc +++ b/lily/paper-column.cc @@ -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. */ diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 5083c0e5f1..ce260d33cc 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -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 diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 7c709cac9d..df551b2d6f 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -390,9 +390,11 @@ ;; 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.