Hi Alexander, hi everybody!
And we might need to offer a way to remove a LyricExtender event. Unless we go the radical route and ...
After a bit of thinking I'd say: go the radical route. Attached is a patch against current master that implements it that way. An additional no-extender property is added that can only be overridden by the force-extender property.
If a user doesn't want it, we need to provide a function \extenderOff (that translates, e.g., to \override LyricExtender.stencil = ##f).
\layout { \Lyrics \override LyricExtender.no-extender = ##t }
Only thing to consider there: We'd need a "stop sign" for extenders that shall only extend to some point in a _ _ _ sequence, as required in a divisi lyrics setting.
"" and \markup\null are usefull, see 5th exampled in attached lyrextest.ly/pdf I know that the documentation would need some work, but there is no reason to start with that until it is known that the changed code would be accepted. Please test ... cu, Knut
>From 53e80c9c17cfa2b11deb15ccfef4587b82c06d52 Mon Sep 17 00:00:00 2001 From: Knut Petersen <knut_peter...@t-online.de> Date: Thu, 15 Dec 2016 12:52:06 +0100 Subject: [PATCH] Automated lyric extenders Automatically add lyric extenders whenever they are appropriate. Add new property no-extender to forbid all extenders unless overridden by the 2nd new boolean property force-extender. Enabled by default. Signed-off-by: Knut Petersen <knut_peter...@t-online.de> --- lily/lyric-extender.cc | 44 +++++++++++++++++++++------------------ scm/define-context-properties.scm | 2 ++ scm/define-grob-properties.scm | 6 ++++++ scm/define-grobs.scm | 2 ++ scm/music-functions.scm | 12 ++++++++--- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/lily/lyric-extender.cc b/lily/lyric-extender.cc index 8afe2c5569..f7d49ac916 100644 --- a/lily/lyric-extender.cc +++ b/lily/lyric-extender.cc @@ -45,51 +45,53 @@ Lyric_extender::print (SCM smob) common = common->common_refpoint (me->get_system (), X_AXIS); Real sl = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness")); + bool at_start_of_line = !left_edge->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")); + bool at_end_of_line = me->get_bound (RIGHT)->break_status_dir (); + bool force_extender = to_boolean (me->get_property ("force-extender")); + bool no_extender = to_boolean (me->get_property ("no-extender")); + + if (!force_extender && no_extender) + return SCM_EOL; extract_grob_set (me, "heads", heads); - if (!heads.size ()) + if (!heads.size () || (!force_extender && !at_start_of_line && !at_end_of_line && heads.size () < 2)) return SCM_EOL; common = common_refpoint_of_array (heads, common, X_AXIS); Real left_point = 0.0; - if (left_edge->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))) + if (!at_start_of_line) left_point = left_edge->extent (common, X_AXIS)[RIGHT]; - else if (heads.size ()) - left_point = heads[0]->extent (common, X_AXIS)[LEFT]; else - left_point = left_edge->extent (common, X_AXIS)[RIGHT]; + left_point = heads[0]->extent (common, X_AXIS)[LEFT]; if (isinf (left_point)) return SCM_EOL; - /* It seems that short extenders are even lengthened to go past the - note head, but haven't found a pattern in it yet. --hwn 1/1/04 */ - SCM minlen = me->get_property ("minimum-length"); - Real right_point - = left_point + (robust_scm2double (minlen, 0)); - - right_point = min (right_point, me->get_system ()->get_bound (RIGHT)->relative_coordinate (common, X_AXIS)); - - if (heads.size ()) - right_point = max (right_point, heads.back ()->extent (common, X_AXIS)[RIGHT]); - Real h = sl * robust_scm2double (me->get_property ("thickness"), 0); Drul_array<Real> paddings (robust_scm2double (me->get_property ("left-padding"), h), robust_scm2double (me->get_property ("right-padding"), h)); + Real minlen = robust_scm2double (me->get_property ("minimum-length"), 0); + + Real right_point = heads.back ()->extent (common, X_AXIS)[RIGHT]; + + if (force_extender) + right_point = max (heads.back ()->extent (common, X_AXIS)[RIGHT], left_point + minlen); + if (right_text) right_point = min (right_point, (robust_relative_extent (right_text, common, X_AXIS)[LEFT] - paddings[RIGHT])); - /* run to end of line. */ - if (me->get_bound (RIGHT)->break_status_dir ()) + if (at_end_of_line) right_point = max (right_point, (robust_relative_extent (me->get_bound (RIGHT), common, X_AXIS)[LEFT] - paddings[RIGHT])); - left_point += paddings[LEFT]; + if (!at_start_of_line) + left_point += paddings[LEFT]; + Real w = right_point - left_point; - if (w < 1.5 * h) + if (w < minlen && !at_start_of_line && !at_end_of_line && !force_extender) return SCM_EOL; Stencil mol (Lookup::round_filled_box (Box (Interval (0, w), @@ -111,4 +113,6 @@ ADD_INTERFACE (Lyric_extender, "next " "right-padding " "thickness " + "force-extender " + "no-extender " ); diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index 75f1807e61..7a4024c167 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -331,6 +331,7 @@ staff switches by a thin line.") (fontSize ,number? "The relative size of all grobs in a context.") (forbidBreak ,boolean? "If set to @code{#t}, prevent a line break at this point.") + (force-extender ,boolean? "Whether to force lyric extenders.") (forceClef ,boolean? "Show clef symbol, even if it has not changed. Only active for the first clef after the property is set, not for the full staff.") @@ -483,6 +484,7 @@ for a minor chord") (noChordSymbol ,markup? "Markup to be displayed for rests in a ChordNames context.") + (no-extender ,boolean? "Whether to inhibit lyric extenders.") (noteToFretFunction ,procedure? "Convert list of notes and list of defined strings to full list of strings and fret numbers. Parameters: The context, a list of note events, a list of diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index c234792dd2..0e8cc5d576 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -330,6 +330,10 @@ allowed.") (footnote ,boolean? "Should this be a footnote or in-note?") (footnote-music ,ly:music? "Music creating a footnote.") (footnote-text ,markup? "A footnote for the grob.") + (force-extender ,boolean? "Force a lyric extender to be generated +if none would be generated otherwise and/or force it to be at least as +wide as indicated by property @code{minimum-width} unless it would +collide with the next syllable. Overrides property @code{no-extender}.") (force-hshift ,number? "This specifies a manual shift for notes in collisions. The unit is the note head width of the first voice note. This is used by @rinternals{note-collision-interface}.") @@ -663,6 +667,8 @@ syllable following an extender).") (no-alignment ,boolean? "If set, don't place this grob in a @code{VerticalAlignment}; rather, place it using its own @code{Y-offset} callback.") + (no-extender ,boolean? "Inhibits generation of lyric extenders. +Can be overridden by property @code{force-extender}.") (no-ledgers ,boolean? "If set, don't draw ledger lines on this object.") (no-stem-extend ,boolean? "If set, notes with ledger lines do not diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index e36ea12bf2..d4ad46e644 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1361,7 +1361,9 @@ (LyricExtender . ( + (force-extender . #f) (minimum-length . 1.5) + (no-extender . #f) (stencil . ,ly:lyric-extender::print) (thickness . 0.8) ; line-thickness (Y-extent . (0 . 0)) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index b1dc2f9c61..8cb9cf7ac5 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -728,10 +728,16 @@ making it possible to @code{\\revert} to any previous value afterwards." 'articulation-type name properties)) +(define (add-extender! event) + (ly:music-set-property! event 'articulations + (append (ly:music-property event 'articulations) + (list (make-music (quote ExtenderEvent))))) + event) + (define-public (make-lyric-event string duration) - (make-music 'LyricEvent - 'duration duration - 'text string)) + (if (and (string? string)(string=? " " string)) + (make-music 'LyricEvent 'duration duration 'text string) + (add-extender! (make-music 'LyricEvent 'duration duration 'text string)))) (define-safe-public (make-span-event type span-dir) (make-music type -- 2.11.0
\version "2.19.53" \paper { ragged-right = ##f } \pointAndClickOff #(set-global-staff-size 16) \markup { "automatic extenders, minimum-length 8 "} << { c''1 2 ~ 2 2 4 ~ 4 4 8 ~ 8 8 16 ~ 16 4 1 \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #8 \repeat unfold 4 { foo -- bar }} >> \markup { "automatic extenders, minimum-length 4 "} << { c''1 2 ~ 2 2 4 ~ 4 4 8 ~ 8 8 16 ~ 16 4 1 \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #4 \repeat unfold 4 { foo -- bar }} >> \markup { "automatic extenders, minimum-length 1 "} << { c''1 2 ~ 2 2 4 ~ 4 4 8 ~ 8 8 16 ~ 16 4 1 \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #1 \repeat unfold 4 { foo -- bar }} >> feo = {\once \override Lyrics.LyricExtender.force-extender = ##t} \markup { "automatic extenders, mixed manual and automatic melismata, extender on last note forced "} << { \autoBeamOff c''2 2 4\( 4 4 4\) 4 4 4\( 4( 4) 8[ 8] 8\) 16\(\melisma 16\melismaEnd 4\) 1 \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #8 foo -- _ bar _ _ _ foo -- _ bar _ _ _ foo -- _ \feo bar _ _ _ } >> \markup { "automatic extenders, mixed manual and automatic melismata, first extender shortened, extender on last note forced "} << { \autoBeamOff c''2 2 4\( 4 4 4\) 4 4 4\( 4( 4) 8[ 8] 8\) 16\(\melisma 16\melismaEnd 4\) 1 \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #8 foo -- _ \feo bar _ "" _ foo -- _ bar _ _ _ foo -- _ \feo bar _ _ _ } >> \markup { "Issue 1006 revisited, last extender forced and tweaked to the left, minimum-length 2 "} \score { << \new Staff \relative c'' { \time 2/1 \repeat volta 2 { r4 g4 d'2. a4 bes2~ bes a2 g1~ } \alternative{ { g2 fis4 e fis1 d'1 c2 bes} { g\repeatTie fis4 e fis1 } } \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #2 of Prin -- ces all _ _ the _ flowâr. Who took a- \feo \tweak self-alignment-X #-4 \markup\null the _ flowâr. } >> } \markup { "Issue 1006 revisited, last extender forced and tweaked to the left, minimum-length 1 "} \score { << \new Staff \relative c'' { \time 2/1 \repeat volta 2 { r4 g4 d'2. a4 bes2~ bes a2 g1~ } \alternative{ { g2 fis4 e fis1 d'1 c2 bes} { g\repeatTie fis4 e fis1 } } \bar "|." } \addlyrics { \override Lyrics.LyricExtender.minimum-length = #1 of Prin -- ces all _ _ the _ flowâr. Who took a- \feo \tweak self-alignment-X #-4 \markup\null the _ flowâr. } >> } \layout { \Lyrics \override LyricExtender.no-extender = ##f % Use ##t to disable all but forced extenders }
lyrextest.pdf
Description: Adobe PDF document
_______________________________________________ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel