Nov 5, 2014

Vertically Centering Lyrics

Recently, I had to create one with a couple of verses with lyrics. Creating the lyrics is easy enough, but I quickly ran into a speed-bump when I wanted to make the chorus show up vertically centered in the same system as the verses. One way around this is to simply start a new system before the chorus lyrics show up, but I didn't want to do that. Doing a quick search through the LSR under the search term "lyrics" showed me that I could set up a series of temporary overrides and offset the vertical position of the lyrics:
dropLyrics = {
  \override LyricText.extra-offset = #'(0 . -4.5)
  \override LyricHyphen.extra-offset = #'(0 . -4.5)
  \override LyricExtender.extra-offset = #'(0 . -4.5)
  \override StanzaNumber.extra-offset = #'(0 . -4.5)
}

raiseLyrics = {
  \revert LyricText.extra-offset
  \revert LyricHyphen.extra-offset
  \revert LyricExtender.extra-offset
  \revert StanzaNumber.extra-offset
}
These two macros would then be used like this (in the first of the four verses):
lyricsA = \lyricmode {
  The first verse has
  \dropLyrics
  \set stanza = #"   All:"
  the com -- mon __ words
  \raiseLyrics
  used in all four.
}

This was exactly what I was looking for, but I felt like it needed to be a little more robust and customizable. So, with my limited knowledge of Scheme, I proceeded to make a function out of it:

dropLyrics =
  #(define-music-function (parser location x music)
     (number? ly:music?)
    #{
      \override LyricText.extra-offset = #(cons 0 x)
      \override LyricHyphen.extra-offset = #(cons 0 x)
      \override LyricExtender.extra-offset = #(cons 0 x)
      \override StanzaNumber.extra-offset = #(cons 0 x)
      $music
      \revert LyricText.extra-offset
      \revert LyricHyphen.extra-offset
      \revert LyricExtender.extra-offset
      \revert StanzaNumber.extra-offset
    #}
  )
Putting it in a function allows me to control the vertical alignment at the same location where I'm typing the text. Now, whenever I need to center a section of lyrics, all I need to do is something like this, adjusting for the proper height:
lyricsA = \lyricmode {
  The first verse has
  \dropLyrics #-4.5 {
    \set stanza = #"   All:"
    the com -- mon __ words
  }
  used in all four.
}
One thing I've learned is that centering lyrics between an odd-number of verses is as easy as including the single line of words in the middle verse while putting "\skip"s in all the others (only necessary if they pick up after the centered text like the example here). So, the above function is really only required for an even-number of verses, and only in the system where they appear together. If I put the centered text in the verse just above where I want to center it (i.e., the second verse if there are four), then I don't need to be explicit about the offset and it can be hard-coded:
dropLyrics =
  #(define-music-function (parser location music)
     (ly:music?)
    #{
      \override LyricText.extra-offset = #'(0 . -1.5)
      \override LyricHyphen.extra-offset = #'(0 . -1.5)
      \override LyricExtender.extra-offset = #'(0 . -1.5)
      \override StanzaNumber.extra-offset = #'(0 . -1.5)
      $music
      \revert LyricText.extra-offset
      \revert LyricHyphen.extra-offset
      \revert LyricExtender.extra-offset
      \revert StanzaNumber.extra-offset
    #}
  )
And to use it now, we move the centered text to the second verse and add \skipFour to the first one:
lyricsA = \lyricmode {
  The first verse has
  \skipFour
  used in all four.
}

lyricsB = \lyricmode { 
  In stan -- za two,  
  \dropLyrics {
    \set stanza = #"   All:"
    the com -- mon __ "words  "
  }
  al -- so ap -- pear. 
}
The only catch to this is that the text will only look for collisions between surrounding characters, so it may be necessary to add additional spaces to the first/last words (as I've done with "   All:" and "words  "). Maybe it would be more useful now to call the function "centerLyrics" instead, but whatever.

No comments:

Post a Comment