From: Mike Solomon Date: Fri, 16 Dec 2011 08:25:29 +0000 (+0100) Subject: Implements padding at right-broken hairpins that come up against span bars. X-Git-Tag: release/2.15.23-1~22 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=f417a6007e951fda4f1fb5fd3da0ecd1d25cec2f;p=lilypond.git Implements padding at right-broken hairpins that come up against span bars. Uses a concurrent-hairpin-engraver to find all concurrent hairpins in a score and shortens all end-of-line hairpins for a given system by 0.6 if there are collisions with a span bar. --- diff --git a/input/regression/hairpin-span-bar.ly b/input/regression/hairpin-span-bar.ly new file mode 100644 index 0000000000..800a7f39f8 --- /dev/null +++ b/input/regression/hairpin-span-bar.ly @@ -0,0 +1,30 @@ +\version "2.15.22" + +\header { + texidoc = "@code{Hairpin} grobs do not collide with @code{SpanBar} grobs. +@code{Hairpin} grobs should, however, go to the end of a line when the +@code{SpanBar} is not present. +" +} + +\score { + << + \new GrandStaff << + \new Staff \relative c'' { a\< a a a \break a a a a \break a a a a\! } + \new Staff \relative c'' { a4 a a a s1 a4 a a a } + >> + \new GrandStaff << + \new Staff \relative c'' { a^\< a a a a a a a a a a a\! } + \new Staff \relative c'' { \repeat unfold 12 a4 } + >> + \new GrandStaff << + \new Staff \relative c'' { a4 a a a s1 a4 a a a } + \new Staff \relative c'' { a^\< a a a a a a a a a a a\! } + >> + >> + \layout { + \context { + \RemoveEmptyStaffContext + } + } +} \ No newline at end of file diff --git a/lily/concurrent-hairpin-engraver.cc b/lily/concurrent-hairpin-engraver.cc new file mode 100644 index 0000000000..652b9cb477 --- /dev/null +++ b/lily/concurrent-hairpin-engraver.cc @@ -0,0 +1,118 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2011 Mike Solomon + + 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 . +*/ + +#include "engraver.hh" + +#include "international.hh" +#include "pointer-group-interface.hh" +#include "spanner.hh" +#include "stream-event.hh" +#include "warn.hh" +#include "item.hh" + +#include "translator.icc" + +class Concurrent_hairpin_engraver : public Engraver +{ +public: + TRANSLATOR_DECLARATIONS (Concurrent_hairpin_engraver); + +protected: + DECLARE_ACKNOWLEDGER (hairpin); + DECLARE_END_ACKNOWLEDGER (hairpin); + + void stop_translation_timestep (); + void finalize (); + +private: + vector arriving_hairpins_; + vector departing_hairpins_; + vector hairpins_hanging_out_; +}; + +Concurrent_hairpin_engraver::Concurrent_hairpin_engraver () +{ +} + +void +Concurrent_hairpin_engraver::acknowledge_hairpin (Grob_info info) +{ + arriving_hairpins_.push_back (info.grob ()); +} + +void +Concurrent_hairpin_engraver::acknowledge_end_hairpin (Grob_info info) +{ + departing_hairpins_.push_back (info.grob ()); +} + +void +Concurrent_hairpin_engraver::stop_translation_timestep () +{ + for (vsize i = 0; i < departing_hairpins_.size (); i++) + for (vsize j = 0; j < hairpins_hanging_out_.size (); j++) + if (departing_hairpins_[i] == hairpins_hanging_out_[j]) + { + hairpins_hanging_out_.erase (hairpins_hanging_out_.begin () + j); + break; + } + if (arriving_hairpins_.size ()) + { + if (arriving_hairpins_.size () > 1) + for (vsize i = 0; i < arriving_hairpins_.size (); i++) + for (vsize j = i; j < arriving_hairpins_.size (); j++) + { + Pointer_group_interface::add_grob (arriving_hairpins_[i], ly_symbol2scm ("concurrent-hairpins"), arriving_hairpins_[j]); + Pointer_group_interface::add_grob (arriving_hairpins_[j], ly_symbol2scm ("concurrent-hairpins"), arriving_hairpins_[i]); + } + + for (vsize i = 0; i < arriving_hairpins_.size (); i++) + for (vsize j = 0; j < hairpins_hanging_out_.size (); j++) + { + Pointer_group_interface::add_grob (arriving_hairpins_[i], ly_symbol2scm ("concurrent-hairpins"), hairpins_hanging_out_[j]); + Pointer_group_interface::add_grob (hairpins_hanging_out_[j], ly_symbol2scm ("concurrent-hairpins"), arriving_hairpins_[i]); + } + } + hairpins_hanging_out_.insert (hairpins_hanging_out_.end (), arriving_hairpins_.begin (), arriving_hairpins_.end ()); + arriving_hairpins_.resize (0); + departing_hairpins_.resize (0); +} + +void +Concurrent_hairpin_engraver::finalize () +{ + hairpins_hanging_out_.resize (0); +} + +ADD_ACKNOWLEDGER (Concurrent_hairpin_engraver, hairpin); +ADD_END_ACKNOWLEDGER (Concurrent_hairpin_engraver, hairpin); + +ADD_TRANSLATOR (Concurrent_hairpin_engraver, + /* doc */ + "Collect concurrent hairpins.", + + /* create */ + "", + + /* read */ + "", + + /* write */ + "" + ); diff --git a/lily/hairpin.cc b/lily/hairpin.cc index 9f5bb1a7e4..403e7bcd08 100644 --- a/lily/hairpin.cc +++ b/lily/hairpin.cc @@ -20,7 +20,9 @@ #include "hairpin.hh" #include "axis-group-interface.hh" +#include "bar-line.hh" #include "dimensions.hh" +#include "directional-element-interface.hh" #include "international.hh" #include "line-interface.hh" #include "output-def.hh" @@ -30,6 +32,7 @@ #include "staff-symbol-referencer.hh" #include "text-interface.hh" #include "note-column.hh" +#include "system.hh" #include "warn.hh" MAKE_SCHEME_CALLBACK (Hairpin, pure_height, 3); @@ -47,6 +50,62 @@ Hairpin::pure_height (SCM smob, SCM, SCM) return ly_interval2scm (Interval (-height, height)); } +MAKE_SCHEME_CALLBACK (Hairpin, broken_bound_padding, 1); +SCM +Hairpin::broken_bound_padding (SCM smob) +{ + Spanner *me = unsmob_spanner (smob); + Item *r_bound = me->get_bound (RIGHT); + if (r_bound->break_status_dir () != -1) + { + me->warning ("Asking for broken bound padding at a non-broken bound."); + return scm_from_double (0.0); + } + + System *sys = dynamic_cast (me->get_system ()); + Direction dir = get_grob_direction (me->get_parent (Y_AXIS)); + if (!dir) + return scm_from_double (0.0); + + Grob *my_vertical_axis_group = Grob::get_vertical_axis_group (me); + Drul_array vertical_axis_groups; + Direction d = DOWN; + do + vertical_axis_groups[d] = d == dir + ? sys->get_neighboring_staff (d, my_vertical_axis_group, Interval_t (me->spanned_rank_interval ())) + : my_vertical_axis_group; + while (flip (&d) != DOWN); + + if (!vertical_axis_groups[dir]) + return scm_from_double (0.0); + + Drul_array span_bars (0, 0); + d = DOWN; + do + { + extract_grob_set (vertical_axis_groups[d], "elements", elts); + for (vsize i = elts.size (); i--;) + if (Bar_line::has_interface (elts[i]) + && dynamic_cast (elts[i])->break_status_dir () == -1) + { + SCM hsb = elts[i]->get_property ("has-span-bar"); + if (!scm_is_pair (hsb)) + break; + + span_bars[d] = unsmob_grob ((d == UP ? scm_car : scm_cdr) (hsb)); + break; + } + if (!span_bars[d]) + return scm_from_double (0.0); + } + while (flip (&d) != DOWN); + + if (span_bars[DOWN] != span_bars[UP]) + return scm_from_double (0.0); + + return scm_from_double (0.6); +} + MAKE_SCHEME_CALLBACK (Hairpin, print, 1); SCM Hairpin::print (SCM smob) @@ -173,17 +232,33 @@ Hairpin::print (SCM smob) x_points[d] = e[-d]; else x_points[d] = e[d]; - - Item *bound = me->get_bound (d); - if (bound->is_non_musical (bound)) - x_points[d] -= d * padding; } } } } while (flip (&d) != LEFT); + // here, add padding for barlines that are not at the end of a staff + if (Item::is_non_musical (bounds[RIGHT]) && bounds[RIGHT]->break_status_dir () == 0) + x_points[RIGHT] -= padding; + + // here, add padding for barlines that are at the end of a staff + Real broken_bound_padding = 0.0; + if (bounds[RIGHT]->break_status_dir () == -1) + { + extract_grob_set (me, "concurrent-hairpins", chp); + for (vsize i = 0; i < chp.size (); i++) + { + Spanner *span_elt = dynamic_cast (chp[i]); + if (span_elt->get_bound (RIGHT)->break_status_dir () == -1) + broken_bound_padding = max (broken_bound_padding, + robust_scm2double (span_elt->get_property ("broken-bound-padding"), 0.0)); + } + } + x_points[RIGHT] -= broken_bound_padding; + Real width = x_points[RIGHT] - x_points[LEFT]; + if (width < 0) { me->warning (_ ((grow_dir < 0) ? "decrescendo too small" @@ -262,6 +337,8 @@ ADD_INTERFACE (Hairpin, /* properties */ "adjacent-spanners " "circled-tip " + "concurrent-hairpins " + "broken-bound-padding " "bound-padding " "grow-direction " "height " diff --git a/lily/include/hairpin.hh b/lily/include/hairpin.hh index c6cfb7dcd4..4bbf288637 100644 --- a/lily/include/hairpin.hh +++ b/lily/include/hairpin.hh @@ -26,7 +26,9 @@ struct Hairpin { public: + static Real span_bar_correction (Spanner *me); DECLARE_SCHEME_CALLBACK (print, (SCM)); + DECLARE_SCHEME_CALLBACK (broken_bound_padding, (SCM)); DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM)); DECLARE_GROB_INTERFACE (); }; diff --git a/lily/include/system.hh b/lily/include/system.hh index 5ce98171b8..8dad61bd0b 100644 --- a/lily/include/system.hh +++ b/lily/include/system.hh @@ -42,6 +42,7 @@ public: Paper_score *paper_score () const; Grob *get_vertical_alignment (); Grob *get_extremal_staff (Direction dir, Interval const &); + Grob * get_neighboring_staff (Direction dir, Grob *vertical_axis_group, Interval_t bounds); Grob *get_pure_bound (Direction dir, int start, int end); Grob *get_maybe_pure_bound (Direction dir, bool pure, int start, int end); int get_rank () const; diff --git a/lily/span-bar.cc b/lily/span-bar.cc index d64b6ba87c..d9b9aa0cc3 100644 --- a/lily/span-bar.cc +++ b/lily/span-bar.cc @@ -222,8 +222,8 @@ Span_bar::notify_grobs_of_my_existence (Grob *me) vector_sort (sortable, Grob::vertical_less); for (vsize i = 0; i < sortable.size (); i++) sortable[i]->set_property ("has-span-bar", - scm_cons (scm_from_bool (i != 0), - scm_from_bool (i != sortable.size () - 1))); + scm_cons (i != sortable.size () - 1 ? me->self_scm () : scm_from_bool (false), + i != 0 ? me->self_scm () : scm_from_bool (false))); } Interval diff --git a/lily/system.cc b/lily/system.cc index 4e5fc1bb4c..87f139d164 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -753,6 +753,36 @@ System::get_extremal_staff (Direction dir, Interval const &iv) return 0; } +// Finds the neighboring staff in the given direction over bounds +Grob * +System::get_neighboring_staff (Direction dir, Grob *vertical_axis_group, Interval_t bounds) +{ + Grob *align = get_vertical_alignment (); + if (!align) + return 0; + + extract_grob_set (align, "elements", elts); + vsize start = (dir == UP) ? 0 : elts.size () - 1; + vsize end = (dir == UP) ? elts.size () : VPOS; + + Grob *out = 0; + + for (vsize i = start; i != end; i += dir) + { + if (elts[i] == vertical_axis_group) + return out; + + if (Hara_kiri_group_spanner::has_interface (elts[i])) + Hara_kiri_group_spanner::consider_suicide (elts[i]); + + bounds.intersect (elts[i]->spanned_rank_interval ()); + if (elts[i]->is_live () && !bounds.is_empty ()) + out = elts[i]; + } + + return 0; +} + vector System::get_simple_spacers (Real line_len, Real indent, bool ragged) { diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index e5409daa43..093b88e9b2 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -538,6 +538,7 @@ automatically when an output definition (a @code{\score} or \consists "Stanza_number_align_engraver" \consists "Bar_number_engraver" \consists "Parenthesis_engraver" + \consists "Concurrent_hairpin_engraver" \defaultchild "Staff" diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index f209fe649a..2391c4e6f0 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -162,6 +162,8 @@ stick out of its bounds?") @code{#(@var{end-of-line} @var{unbroken} @var{begin-of-line})}. @code{#t} means visible, @code{#f} means killed.") (breakable ,boolean? "Allow breaks here.") + (broken-bound-padding ,number? "The amount of padding to insert +around spanner bounds at a line break.") ;; ;; c @@ -1018,6 +1020,7 @@ bounds are spaced.") (columns ,ly:grob-array? "An array of grobs, typically containing @code{PaperColumn} or @code{NoteColumn} objects.") + (concurrent-hairpins ,ly:grob-array? "All concurrent hairpins.") (conditional-elements ,ly:grob-array? "Internal use only.") (covered-grobs ,ly:grob-array? "Grobs that could potentially collide with a beam.") @@ -1047,8 +1050,9 @@ for a full score's worth of grobs.") column.") (grace-spacing ,ly:grob? "A run of grace notes.") - (has-span-bar ,pair? "A pair of booleans indicating whether a a span bar -is drawn above, or respectively below, this staff.") + (has-span-bar ,pair? "A pair of grobs containing the span bars to +be drawn below and above the staff. If no span bar is in a position, +the respective element is set to @code{#f}.") (heads ,ly:grob-array? "An array of note heads.") (items-worth-living ,ly:grob-array? "An array of interesting items. If @@ -1177,6 +1181,7 @@ to be within staff spaces.") (quantized-positions ,number-pair? "The beam positions after quanting.") + (script-stencil ,pair? "A pair @code{(@var{type} . @var{arg})} which acts as an index for looking up a @code{Stencil} object.") (shorten ,ly:dimension? "The amount of space that a stem is shortened. diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 806f720697..08b3ff5f14 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1023,6 +1023,7 @@ . ( (after-line-breaking . ,ly:spanner::kill-zero-spanned-time) (bound-padding . 1.0) + (broken-bound-padding . ,ly:hairpin::broken-bound-padding) (circled-tip . #f) (grow-direction . ,hairpin::calc-grow-direction) (height . 0.6666) diff --git a/scm/output-lib.scm b/scm/output-lib.scm index 9137d5be17..84f9984b33 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -409,10 +409,10 @@ and duration-log @var{log}." (hsb (ly:grob-property grob 'has-span-bar)) (ii (interval-intersection esh (cons -1.01 1.01)))) (if (pair? hsb) - (cons (car (if (and (cdr hsb) + (cons (car (if (and (car hsb) (ly:grob-property grob 'allow-span-bar)) esh ii)) - (cdr (if (car hsb) esh ii))) + (cdr (if (cdr hsb) esh ii))) ii))) (define-public (pure-from-neighbor-interface::extra-spacing-height-including-staff grob)