lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: bug in magnetic snapping lyrics engraver


From: Werner LEMBERG
Subject: Re: bug in magnetic snapping lyrics engraver
Date: Thu, 14 Apr 2022 16:18:40 +0000 (UTC)

> How did you do that?  Sorry to rain on your parade, but I would not
> want you to put a lot of work in it if it will not be of mergeable
> quality.

Attached.  In the end the necessary modifications were surprisingly
minor.  Please comment, there is certainly room for improvements.


    Werner

diff --git a/lily/lyric-hyphen.cc b/lily/lyric-hyphen.cc
index 23cd76bd94..897de7d7f7 100644
--- a/lily/lyric-hyphen.cc
+++ b/lily/lyric-hyphen.cc
@@ -48,6 +48,10 @@ Lyric_hyphen::print (SCM smob)
           && !from_scm<bool> (get_property (me, "after-line-breaking"))))
     return SCM_EOL;
 
+  // Ensure that bounds are displaced first.
+  (void) get_property (bounds[LEFT], "after-line-breaking");
+  (void) get_property (bounds[RIGHT], "after-line-breaking");
+
   Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS);
 
   Interval span_points;
diff --git a/scm/scheme-engravers.scm b/scm/scheme-engravers.scm
index 07e3be3691..5131beef1f 100644
--- a/scm/scheme-engravers.scm
+++ b/scm/scheme-engravers.scm
@@ -943,6 +943,101 @@ Engraver to print a line between two @code{Fingering} 
grobs.")))
    (description . "Create repeat counts within lyrics for modern
 transcriptions of Gregorian chant.")))
 
+(define (Left_hyphen_pointer_engraver context)
+  (let ((hyphen #f)
+        (text #f))
+    (make-engraver
+     (acknowledgers
+      ((lyric-syllable-interface engraver grob source-engraver)
+       (set! text grob)))
+     (end-acknowledgers
+      ((lyric-hyphen-interface engraver grob source-engraver)
+       (when (not (grob::has-interface grob 'lyric-space-interface))
+         (set! hyphen grob))))
+     ((stop-translation-timestep engraver)
+      (when (and text hyphen)
+        (ly:grob-set-object! text 'left-hyphen hyphen))
+      (set! text #f)
+      (set! hyphen #f)))))
+
+(define-public (lyric-text::apply-magnetic-offset! grob)
+  "If the space between two syllables is less than the value in
+property @code{LyricText@/.details@/.squash-threshold}, move the right
+syllable to the left so that it gets concatenated with the left
+syllable.
+
+Use this function as a hook for
+@code{LyricText@/.after-@/line-@/breaking} if the
+@code{Left_@/hyphen_@/pointer_@/engraver} is active."
+  (let ((hyphen (ly:grob-object grob 'left-hyphen #f)))
+    (when hyphen
+      (let ((left-text (ly:spanner-bound hyphen LEFT)))
+        (when (grob::has-interface left-text 'lyric-syllable-interface)
+          (let* ((common (ly:grob-common-refpoint grob left-text X))
+                 (this-x-ext (ly:grob-extent grob common X))
+                 (left-x-ext
+                  (begin
+                    ;; Trigger magnetism for left-text.
+                    (ly:grob-property left-text 'after-line-breaking)
+                    (ly:grob-extent left-text common X)))
+                 ;; `delta` is the gap width between two syllables.
+                 (delta (- (interval-start this-x-ext)
+                           (interval-end left-x-ext)))
+                 (details (ly:grob-property grob 'details))
+                 (threshold (assoc-get 'squash-threshold details 0.2)))
+            (when (< delta threshold)
+              (let* (;; We have to manipulate the input text so that
+                     ;; ligatures crossing syllable boundaries are not
+                     ;; disabled.  For languages based on the Latin
+                     ;; script this is essentially a beautification.
+                     ;; However, for non-Western scripts it can be a
+                     ;; necessity.
+                     (lt (ly:grob-property left-text 'text))
+                     (rt (ly:grob-property grob 'text))
+                     ;; Append new syllable.
+                     (ltrt (if (and (string? lt) (string? rt))
+                               (string-append lt rt)
+                               (make-concat-markup (list lt rt))))
+                     ;; Right-align `ltrt` to the right side.
+                     (markup (grob-interpret-markup
+                              grob
+                              (make-translate-markup
+                               (cons (interval-length this-x-ext) 0)
+                               (make-right-align-markup ltrt)))))
+                (begin
+                  ;; Don't print `left-text`.
+                  (ly:grob-set-property! left-text 'stencil #f)
+                  ;; Set text and stencil (which holds all collected
+                  ;; syllables so far) and shift it to the left.
+                  (ly:grob-set-property! grob 'text ltrt)
+                  (ly:grob-set-property! grob 'stencil markup)
+                  (ly:grob-translate-axis! grob (- delta) X))))))))))
+
+(ly:register-translator
+ Left_hyphen_pointer_engraver 'Left_hyphen_pointer_engraver
+ '((grobs-created . ())
+   (events-accepted . ())
+   (properties-read . ())
+   (properties-written . ())
+   (description . "\
+Collect syllable-hyphen-syllable occurrences in lyrics and store them
+in properties.  This engraver only looks to the left.  For example, if
+the lyrics input is @code{foo -- bar}, it does the following.
+
+@itemize @bullet
+@item
+Set the @code{text} property of the @code{LyricHyphen} grob between
+@q{foo} and @q{bar} to @code{foo}.
+
+@item
+Set the @code{left-hyphen} property of the @code{LyricText} grob with
+text @q{foo} to the @code{LyricHyphen} grob between @q{foo} and
+@q{bar}.
+@end itemize
+
+Use this auxiliary engraver in combination with the
+@code{lyric-@/text::@/apply-@/magnetic-@/offset!} hook.")))
+
 ; TODO: yet another engraver for alignment... Ultimately, it would be nice to
 ; merge Dynamic_align_engraver, Piano_pedal_align_engraver and
 ; Centered_bar_number_align_engraver.
\version "2.23.8"

<<
  \new Voice = "foo" \relative c'' {
    \omit Staff.TimeSignature
    \time 6/4
    d4 d d d d d |
  }

  \new Lyrics \lyricsto "foo" {
    ibif -- icif -- if -- if -- ilif -- imif
  }
>>


\paper {
  indent = 0
  ragged-right = ##f
  line-width = 50\mm
}


\layout {
  \context {
    \Lyrics
    \consists Left_hyphen_pointer_engraver
    \override LyricText.after-line-breaking = 
#lyric-text::apply-magnetic-offset!

    \override LyricText.details.squash-threshold = 0.5
    \override LyricHyphen.minimum-length = 0.5

    \override LyricHyphen.minimum-distance = 0
    \override LyricSpace.minimum-distance = 1
  }
}

Attachment: magnetic-lyrics-test.pdf
Description: Adobe PDF document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]