Hello Lilypond team and users,

I'm engraving songs that need long stanza for 1st lyric lines and short
stanza with repetition from 2nd lines downward.
Is there any way to archive this in Lilypond 2.24?

Below is my workaround but I'm not able to align long stanza for 1st lines:

\version "2.24.3"

#(define (add-grob-definition grob-name grob-entry)
     (set! all-grob-descriptions
           (cons ((@@ (lily) completize-grob-entry)
                  (cons grob-name grob-entry))
                 all-grob-descriptions)))

#(add-grob-definition
    'StanzaNumberSpanner
    `((direction . ,LEFT)
      (font-series . bold)
      (padding . 1.0)
      (side-axis . ,X)
      (stencil . ,ly:text-interface::print)
      (X-offset . ,ly:side-position-interface::x-aligned-side)
      (Y-extent . ,grob::always-Y-extent-from-stencil)
      (meta . ((class . Spanner)
               (interfaces . (font-interface
                              side-position-interface
                              stanza-number-interface
                              text-interface))))))

\layout {
    \context {
      \Global
      \grobdescriptions #all-grob-descriptions
    }
    \context {
      \Score
      \remove Stanza_number_align_engraver
      \consists
        #(lambda (context)
           (let ((texts '())
                 (syllables '()))
             (make-engraver
              (acknowledgers
               ((stanza-number-interface engraver grob source-engraver)
                  (set! texts (cons grob texts)))
               ((lyric-syllable-interface engraver grob source-engraver)
                  (set! syllables (cons grob syllables))))
              ((stop-translation-timestep engraver)
                 (for-each
                  (lambda (text)
                    (for-each
                     (lambda (syllable)
                       (ly:pointer-group-interface::add-grob
                        text
                        'side-support-elements
                        syllable))
                     syllables))
                  texts)
                 (set! syllables '())))))
    }
    \context {
      \Lyrics
      \remove Stanza_number_engraver
      \consists
        #(lambda (context)
           (let ((text #f)
                 (last-stanza #f))
             (make-engraver
              ((process-music engraver)
                 (let ((stanza (ly:context-property context 'stanza #f)))
                   (if (and stanza (not (equal? stanza last-stanza)))
                       (let ((column (ly:context-property context
'currentCommandColumn)))
                         (set! last-stanza stanza)
                         (if text
                             (ly:spanner-set-bound! text RIGHT column))
                         (set! text (ly:engraver-make-grob engraver
'StanzaNumberSpanner '()))
                         (ly:grob-set-property! text 'text stanza)
                         (ly:spanner-set-bound! text LEFT column)))))
              ((finalize engraver)
                 (if text
                     (let ((column (ly:context-property context
'currentCommandColumn)))
                       (ly:spanner-set-bound! text RIGHT column)))))))
      \override StanzaNumberSpanner.horizon-padding = 10000
    }
}

stanzaReminderOff =
\temporary \override StanzaNumberSpanner.after-line-breaking =
   #(lambda (grob)
      ;; Can be replaced with (not (first-broken-spanner? grob)) in 2.23.
      (if (let ((siblings (ly:spanner-broken-into (ly:grob-original grob))))
            (and (pair? siblings)
                 (not (eq? grob (car siblings)))))
          (ly:grob-suicide! grob)))

stanzaReminderOn =
\undo \stanzaReminderOff


sopranoMusic = \relative c'' {
    \key f \major \time 2/4
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c }
}

sopranoLyrics = \lyrics {
    \stanzaReminderOn
    <<
      {
        \set stanza = "1. (First)"
        \repeat unfold 10 { aa }
        \set stanza = "1."
        \stanzaReminderOn
        \repeat unfold 10 { aa }
        \repeat unfold 10 { aa }
        \repeat unfold 10 { aa }
      }
      \new Lyrics {
        \set stanza = "2.(Second)"
        \repeat unfold 10 { bb }
        \set stanza = "2."
        \stanzaReminderOn
        \repeat unfold 10 { bb }
        \repeat unfold 10 { bb }
        \repeat unfold 10 { bb }
      }
    >>
}

\score {
  \new ChoirStaff <<
    \new Staff <<
      \new Voice = soprano \sopranoMusic
      \new Lyrics \lyricsto soprano \sopranoLyrics
      >>
  >>
  \layout {
    indent = 0
  }
}

Thank you for any help,
Tu

On Wed, 6 Apr 2022 at 10:40, Dinh Hoang Tu <dhoan...@gmail.com> wrote:

> It works amazingly!
> Thanks a lot for your expertise!!!
>
> Best,
> Tu
>
> Vào 22:50, T.6, 1 Th4, 2022 Jean Abou Samra <j...@abou-samra.fr> đã viết:
>
>>
>>
>> Le 31/03/2022 à 17:26, Dinh Hoang Tu a écrit :
>> > Hi Jean and all,
>> >
>> > I ran into cases when chorus and first verse are continued on first
>> line.
>> > Then with this solution, stanza cannot be changed from chorus to verse
>> > 1, or vice versa.
>> > I would appreciate it if it can be archived somehow.
>>
>> Here's an updated snippet.
>>
>> Best,
>> Jean
>>
>>
>>
>> \version "2.22.2"
>>
>> sopranoMusic = \relative c'' {
>>    \time 2/4
>>    % verse music
>>    \repeat unfold 10 { c } \break
>>    % chorus music
>>    \repeat unfold 10 { c } \break
>>    \repeat unfold 10 { c }
>> }
>>
>> sopranoLyrics = \lyrics {
>>    \set stanza = "CH:"
>>    \repeat unfold 9 { aaaaa }
>>    <<
>>      {
>>        \set stanza = "1." % cannot reset stanza to new value
>>        \repeat unfold 21 { aaa }
>>      }
>>      \new Lyrics = "lyr2" {
>>        \set stanza = "2."
>>        \repeat unfold 20 { aaaa }
>>      }
>>    >>
>> }
>>
>> #(define (add-grob-definition grob-name grob-entry)
>>     (set! all-grob-descriptions
>>           (cons ((@@ (lily) completize-grob-entry)
>>                  (cons grob-name grob-entry))
>>                 all-grob-descriptions)))
>>
>> #(add-grob-definition
>>    'StanzaNumberSpanner
>>    `((direction . ,LEFT)
>>      (font-series . bold)
>>      (padding . 1.0)
>>      (side-axis . ,X)
>>      (stencil . ,ly:text-interface::print)
>>      (X-offset . ,ly:side-position-interface::x-aligned-side)
>>      (Y-extent . ,grob::always-Y-extent-from-stencil)
>>      (meta . ((class . Spanner)
>>               (interfaces . (font-interface
>>                              side-position-interface
>>                              stanza-number-interface
>>                              text-interface))))))
>>
>> \layout {
>>    \context {
>>      \Global
>>      \grobdescriptions #all-grob-descriptions
>>    }
>>    \context {
>>      \Score
>>      \remove Stanza_number_align_engraver
>>      \consists
>>        #(lambda (context)
>>           (let ((texts '())
>>                 (syllables '()))
>>             (make-engraver
>>              (acknowledgers
>>               ((stanza-number-interface engraver grob source-engraver)
>>                  (set! texts (cons grob texts)))
>>               ((lyric-syllable-interface engraver grob source-engraver)
>>                  (set! syllables (cons grob syllables))))
>>              ((stop-translation-timestep engraver)
>>                 (for-each
>>                  (lambda (text)
>>                    (for-each
>>                     (lambda (syllable)
>>                       (ly:pointer-group-interface::add-grob text
>> 'side-support-elements syllable))
>>                     syllables))
>>                  texts)
>>                 (set! syllables '())))))
>>    }
>>    \context {
>>      \Lyrics
>>      \remove Stanza_number_engraver
>>      \consists
>>        #(lambda (context)
>>           (let ((text #f)
>>                 (last-stanza #f))
>>             (make-engraver
>>              ((process-music engraver)
>>                 (let ((stanza (ly:context-property context 'stanza #f)))
>>                   (if (and stanza (not (equal? stanza last-stanza)))
>>                       (let ((column (ly:context-property context
>> 'currentCommandColumn)))
>>                         (set! last-stanza stanza)
>>                         (if text
>>                             (ly:spanner-set-bound! text RIGHT column))
>>                         (set! text (ly:engraver-make-grob engraver
>> 'StanzaNumberSpanner '()))
>>                         (ly:grob-set-property! text 'text stanza)
>>                         (ly:spanner-set-bound! text LEFT column)))))
>>              ((finalize engraver)
>>                 (if text
>>                     (let ((column (ly:context-property context
>> 'currentCommandColumn)))
>>                       (ly:spanner-set-bound! text RIGHT column)))))))
>>      \override StanzaNumberSpanner.horizon-padding = 10000
>>    }
>> }
>>
>> \score {
>>    \new ChoirStaff <<
>>      \new Staff <<
>>        \new Voice = soprano \sopranoMusic
>>        \new Lyrics \lyricsto soprano \sopranoLyrics
>>        >>
>>    >>
>>    \layout {
>>      indent = 0
>>    }
>> }
>>
>>
>>
\version "2.24.3"


#(define (add-grob-definition grob-name grob-entry)
     (set! all-grob-descriptions
           (cons ((@@ (lily) completize-grob-entry)
                  (cons grob-name grob-entry))
                 all-grob-descriptions)))

#(add-grob-definition
    'StanzaNumberSpanner
    `((direction . ,LEFT)
      (font-series . bold)
      (padding . 1.0)
      (side-axis . ,X)
      (stencil . ,ly:text-interface::print)
      (X-offset . ,ly:side-position-interface::x-aligned-side)
      (Y-extent . ,grob::always-Y-extent-from-stencil)
      (meta . ((class . Spanner)
               (interfaces . (font-interface
                              side-position-interface
                              stanza-number-interface
                              text-interface))))))

\layout {
    \context {
      \Global
      \grobdescriptions #all-grob-descriptions
    }
    \context {
      \Score
      \remove Stanza_number_align_engraver
      \consists
        #(lambda (context)
           (let ((texts '())
                 (syllables '()))
             (make-engraver
              (acknowledgers
               ((stanza-number-interface engraver grob source-engraver)
                  (set! texts (cons grob texts)))
               ((lyric-syllable-interface engraver grob source-engraver)
                  (set! syllables (cons grob syllables))))
              ((stop-translation-timestep engraver)
                 (for-each
                  (lambda (text)
                    (for-each
                     (lambda (syllable)
                       (ly:pointer-group-interface::add-grob
                        text
                        'side-support-elements
                        syllable))
                     syllables))
                  texts)
                 (set! syllables '())))))
    }
    \context {
      \Lyrics
      \remove Stanza_number_engraver
      \consists
        #(lambda (context)
           (let ((text #f)
                 (last-stanza #f))
             (make-engraver
              ((process-music engraver)
                 (let ((stanza (ly:context-property context 'stanza #f)))
                   (if (and stanza (not (equal? stanza last-stanza)))
                       (let ((column (ly:context-property context
'currentCommandColumn)))
                         (set! last-stanza stanza)
                         (if text
                             (ly:spanner-set-bound! text RIGHT column))
                         (set! text (ly:engraver-make-grob engraver
'StanzaNumberSpanner '()))
                         (ly:grob-set-property! text 'text stanza)
                         (ly:spanner-set-bound! text LEFT column)))))
              ((finalize engraver)
                 (if text
                     (let ((column (ly:context-property context
'currentCommandColumn)))
                       (ly:spanner-set-bound! text RIGHT column)))))))
      \override StanzaNumberSpanner.horizon-padding = 10000
    }
}

stanzaReminderOff =
\temporary \override StanzaNumberSpanner.after-line-breaking =
   #(lambda (grob)
      ;; Can be replaced with (not (first-broken-spanner? grob)) in 2.23.
      (if (let ((siblings (ly:spanner-broken-into (ly:grob-original grob))))
            (and (pair? siblings)
                 (not (eq? grob (car siblings)))))
          (ly:grob-suicide! grob)))

stanzaReminderOn =
\undo \stanzaReminderOff


sopranoMusic = \relative c'' {
    \key f \major \time 2/4
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c } \break
    \repeat unfold 10 { c }
}

sopranoLyrics = \lyrics {
    \stanzaReminderOn
    <<
      {
        \set stanza = "1. (First)"
        \repeat unfold 10 { aa }
        \set stanza = "1."
        \stanzaReminderOn
        \repeat unfold 10 { aa }
        \repeat unfold 10 { aa }
        \repeat unfold 10 { aa }
      }
      \new Lyrics {
        \set stanza = "2.(Second)"
        \repeat unfold 10 { bb }
        \set stanza = "2."
        \stanzaReminderOn
        \repeat unfold 10 { bb }
        \repeat unfold 10 { bb }
        \repeat unfold 10 { bb }
      }
    >>
}

\score {
  \new ChoirStaff <<
    \new Staff <<
      \new Voice = soprano \sopranoMusic
      \new Lyrics \lyricsto soprano \sopranoLyrics
      >>
  >>
  \layout {
    indent = 0
  }
}

Attachment: longStanza-shortStanza.pdf
Description: Adobe PDF document

Reply via email to