Hi David,

On Thu, Apr 9, 2015 at 9:32 AM, David B. Stocker <notesetters...@gmail.com>
wrote:

> Hello LilyPonders,
>
> I have a client who is working on a hymnal, and they would like for the
> beginning of the lines of verses to be left justified. The best way I can
> see to do this, from a visual standpoint, is to make the longest syllable
> on the first note of each line centered like it normally is, and then
> left-align all the others to that syllable.
>
> Please see the attached minimal example.
>
> First, I want to know whether it is possible to automate this behavior
> with LilyPond (I think it is).
>
> And next, I'd like it if someone would point me in the direction of how to
> achieve this. My sense is that it is going to require some
> function-writing. I'm not a programmer (at all, really), but I'm not
> opposed to learning how to do this. Actually, I've been meaning to learn
> how to extend and modify some aspects of LilyPond for my own projects and
> doing so for a client-project is the best excuse I might have for jumping
> in.
>
> Also, it's something that may be useful for other users as well, so at the
> very least it should be included in the LSR, and maybe made available for
> everyone in a future release.
>
> I'm also open to collaboration on this, if anyone else is interested.
>
> So, my hunch is that I'm going to write a function that queries the value
> of the left edge of the centered syllable in one verse, and then calculates
> the amount of offset to apply to the syllables at the same point in other
> verses on a case-by-case basis.
>
> 1) where can I start with learning this sort of tinkering, and 2) does
> anyone have other functions that behave in a similar way (fetching a value,
> making a calculation, and then applying it somewhere else) that I could
> study to figure out how I might do this?


You can find a function here which I believe does what you want:

http://www.mail-archive.com/lilypond-user%40gnu.org/msg81870.html

It's been a while, but it looks like you add \tagIt at the line beginning,
to any of the verses,  This will center the lines based on the longest word
and left-justify, regardless of the verse to which you attach the \tagIt.

Attached is the relevant code with your example.

Of course it would be great to automate this so you wouldn't have to worry
about line breaks, and possibly that could be done here.

Hope this helps,
David

P.S.  I see the following message in the above thread:
http://www.mail-archive.com/lilypond-user%40gnu.org/msg81941.html
Possibly you could request the code from the poster.
\version "2.17.17"

%%%%%%%%%%%%%%%%%%%%%%

#(define (define-grob-property symbol type? description)
  (if (not (equal? (object-property symbol 'backend-doc) #f))
      (ly:error (_ "symbol ~S redefined") symbol))

  (set-object-property! symbol 'backend-type? type?)
  (set-object-property! symbol 'backend-doc description)
  symbol)

#(map
  (lambda (x)
    (apply define-grob-property x))

  `(
    (tagged ,boolean? "is this grob marked?")
    (syllables ,array? "the lyric syllables at a timestep")
  ))

%%%%%%%%%%%%%%%%%%%%%%%%

#(define (Lyric_text_align_engraver ctx)
"If the property 'tagged is set, collect all lyric syllables at that
timestep in the grob-array `syllables'"
  (let ((syl '()))
    (make-engraver
     (acknowledgers
      ((lyric-syllable-interface trans grob source)
       (set! syl (cons grob syl))))
     ((stop-translation-timestep trans)
      (if (any (lambda (x) (eq? #t (ly:grob-property x 'tagged)))
               syl)
          (for-each
            (lambda (x)
               (for-each
                 (lambda (y)
                   (ly:pointer-group-interface::add-grob x 'syllables y))
                 syl))
            syl))
      (set! syl '())))))

#(define (X-offset-callback grob)
  (let* ((target (ly:grob-object grob 'syllables))
         (target
           (if (ly:grob-array? target)
               (ly:grob-array->list target)
               '())))
    (if (pair? target)
        (let ((longest
                (car
                  (sort target
                        (lambda (x y)
                          (> (interval-length
                               (ly:stencil-extent
                                 (grob-interpret-markup
                                   grob (ly:grob-property x 'text))
                                 X))
                             (interval-length
                               (ly:stencil-extent
                                 (grob-interpret-markup
                                   grob (ly:grob-property y 'text))
                                 X))))))))
          (if (eq? grob longest)
              ; if our grob has the longest syllable, return its default
              ; value for 'X-offset
              (ly:self-alignment-interface::aligned-on-x-parent grob)
              (ly:grob-property longest 'X-offset)))
        (ly:self-alignment-interface::aligned-on-x-parent grob))))
         
tagIt = \once \override Lyrics.LyricText #'tagged = ##t 

%%%%%%%%%%%%%%%%  EXAMPLE


\layout {
  ragged-right = ##f
  \context {
    \Lyrics
    \override LyricText.X-offset = #X-offset-callback
  }
  \context {
    \Score
    \consists #Lyric_text_align_engraver
  }
}



\score {
  \new Staff <<
    \new Voice = "hymn" {
      \relative c'' {
        \partial 2 a4 a \bar "|"
      }
    }
    \new Lyrics \lyricsto "hymn" {
      \tagIt with my
    }
    \new Lyrics \lyricsto "hymn" { 
      through the
    }
    \new Lyrics \lyricsto "hymn" {
      praise the
    }
    \new Lyrics \lyricsto "hymn" {
      bless -- ed
    }
  >>
}
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to