Hello Kieren,

first of all: Looks like a nice piece!
Second: offtopic nitpicks. There are some superfluous LyricExtenders there – I’d rather leave them out if they are very short. (<http://sourceforge.net/p/testlilyissues/issues/4509/> …) And note the mid-air bar-numbers, where they are aligned with ScoreMarks. I’d move Bar_number_engraver to the topmost staff. And I like for long syllables to be increasingly left-aligned, for which I wrote a custom grob callback. And finally on your actual point, an answer which is probably not the one you wanted to hear: :-)

I’d vote to keep with four staves, at least in this example. My model for engraving choral scores is the respective volume in the 1926 Breitkopf & Härtel Brahms complete edition. It’s beautiful and excellent to read. It always uses a consistent number of staves for the music (which might also be due to the music), which I think gives more consistent looks and takes some difficulty (in finding the staff he should be singing from) from the singer. The other major point is that it doesn’t print ‘redundant’ lyrics, i.e. passages with equal rhythm and wording in multiple voices have the lyrics printed only once, mostly below the topmost of the staves. This is certainly a controversial feature, but IMO the clarity it adds to the score and the nudge to not only read one’s own voice are valuable, alongside with the gain on vertical space. For this I also wrote a nice, easy-to-use solution, which you find applied to the version in the attachment. Of course there are cases where one needs to go e.g. to eight staves, or have other changes in staff number – the best of orchestral score engravings show it. It _would_ of course be great to have a good mechanism for that in LilyPond, but it looks like a really involved task.

Other measures to obtain closer vertical spacing are shifting dynamics (a task for which I haven’t yet found a definite, if only personal solution yet – very complicated) – and narrower hairpins (My default stylesheet has \override Hairpin.height = 0.45).

I hope there is something useful for you amongst these ideas…

Yours, Simon

On 24.11.2015 16:14, Kieren MacMillan wrote:
Hello list,

I’ve posted this question several times before, but the discussion always got 
truncated or derailed… I’m hoping this time we can work this through to a 
solution.

Choral pieces tend to have both sections of polyphony (requiring 4 or more 
staves) and sections of homophony (requiring as few as 1 staff). I want to be 
able to arbitrarily break systems and have Lilypond Do The Right Thing™, by 
which I mean use the maximum number of systems when necessary, but combine 
voices and lyrics to 3 or 2 staves or even 1 staff where possible.

Bonus points if we can convince Lily to automagically [e.g., via an engraver?] 
put a user-definable markup indicating who is singing at a given moment, add 
splitting-or-combining arrows at the end(s) of systems, etc.

I’ve attached the first 17 measures of one of my original carols as an example 
we can work with/through. Is anyone out there willing to work with me to find 
the Best Practice here? I’m happy to do this on-list or off-, as appropriate.

Thanks,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: i...@kierenmacmillan.info



_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

\version "2.19.31"
\language "english"
\include "interpolate.ily"
\include "switch-lyrics.ily"

#(set-global-staff-size 15.5)

\paper {
  page-count = 2
  system-count = 5
  ragged-bottom = ##t
  ragged-last-bottom = ##t
  system-system-spacing = #'((minimum-distance . 18) (padding . 8))
}

\layout {
  \context {
    \Voice
    \consists "Melody_engraver"
    \override Stem #'neutral-direction = #'()
  }
  \context {
    \Staff
    \name ChoralStaff
    \alias Staff
    \override DynamicLineSpanner.direction = #UP
    \override Script.direction = #UP
    \override TextScript.direction = #UP
    \override TupletBracket.direction = #UP
    \override TupletNumber.direction = #UP
  }
  \context {
    \ChoirStaff
    \accepts ChoralStaff
  }
  \context {
    \type "Engraver_group"
    \name ScoreMarks
    \consists "Staff_collecting_engraver"
    \consists "Axis_group_engraver"
    \override VerticalAxisGroup.staff-affinity = #DOWN
    \override VerticalAxisGroup.nonstaff-relatedstaff-spacing =
        #'((basic-distance . 1) (minimum-distance . 1) (padding . 2) (stretchability . 0))
    \override VerticalAxisGroup.nonstaff-unrelatedstaff-spacing =
        #'((basic-distance . 6) (minimum-distance . 6) (padding . 4) (stretchability . 0))
    \override VerticalAxisGroup.nonstaff-nonstaff-spacing =
        #'((basic-distance . 1) (minimum-distance . 1) (padding . 1) (stretchability . 0))
    \consists "Metronome_mark_engraver"
    \override MetronomeMark.font-size = #2
    \override MetronomeMark.font-series = #'normal
    \override MetronomeMark.Y-offset = ##f
    \override MetronomeMark.padding = #2
    \override MetronomeMark.break-align-symbols = #'(time-signature key-signature)
    \override MetronomeMark.non-break-align-symbols = #'(paper-column-interface)
    \consists "Text_spanner_engraver"
    \override TextSpanner.font-size = #2
    \consists "Mark_engraver"
    \override RehearsalMark.Y-offset = ##f
    \override RehearsalMark.outside-staff-priority = #75
    \override RehearsalMark.font-size = #2
    \override RehearsalMark.break-align-symbols = #'(time-signature key-signature)
    \consists "Time_signature_engraver"
    \override TimeSignature.stencil = #point-stencil
  }
  \context {
    \Score
    \remove "Metronome_mark_engraver"
    \remove "Mark_engraver"
    \remove "Bar_number_engraver"
    \accepts ScoreMarks
    \override TimeSignature.style = #'()
    \override BarNumber.font-size = #2.5
    \override BarNumber.padding = #2
  }
}

%%%%  GLOBAL  %%%%

\header {
  title = "Wither’s Carol"
}

WithersCarol_global = {
  %%  v. 1
    \key d \major
    \tempo "Brightly" 4=108
    \time 2/4
    \omitLyrics #'(alt ten bass)
    \partial 8 s8
    s4*2
    \time 4/4
    s4*4
    \time 2/4
    s4*2*3
    \time 4/4
    s4*4
    \time 2/4
    s4*2*2
    \time 7/8
    \showLyrics #'(bass) % () to prevent interpretation as a drum note…
    s8*7
    \time 2/4
    s4*2
    \time 4/4
    \tempo \markup "Relaxing slightly"
    s1*2
    \tempo "Like a madrigal" 4=80
    \showLyrics #'(alt ten)
    s1
    \time 9/8
    s8*9
    \time 4/4
    s2
    \tempo \markup "poco rit."
    s1
    \tempo \markup "regain tempo"
    s4 \omitLyrics #'(alt ten bass) s4
    s1
    \bar "||"
}


%%%%  VOICES  %%%%

WithersCarol_soprano_notes = {
  %%  v. 1
      a8\mf   | % sop 0
    d'8 d' d'16( e') fs'( g')   | % sop 1
    a'8 a' b'2\tenuto r8 a'   | % sop 2
    fs'8 d' e' cs'   | % sop 3
    d'4 d'8 a   | % sop 4
    d'8 d' d'16( e') fs'( g')   | % sop 5
    a'8 a' b'2\tenuto r8 r16 a'   | % sop 6
    fs'8 d' e'16( d') cs'8   | % sop 7
    d'4 d'   | % sop 8
    r8 d''4\f-> b'8 b'4-> a'16 d''   | % sop 9
    b'8 b' a'4   | % sop 10
    r8 a'4 fs'8 fs'4 e'   | % sop 11
    d'4 b'8 b'8\> ~ 2   | % sop 12
    r2\! r4 fs'8(\p gs')   | % sop 13
    a'2.\< e''4.\!   | % sop 14
    d''8 fs'' e''-! r cs'' d''\tenuto ~ 4 ~   | % sop 15
    d''2 ~ 4\> r8\! r16 g'\pp  | % sop 16
    fs'8 d' e'16( d') cs'8 d'4 d'   | % sop 17
}

WithersCarol_soprano_lyrics = \lyricmode {
  %%  v. 1
    So now is come our joy -- ful’st feast,
    Let ev’ -- ry one be jol -- ly.
    Each room with i -- vy __ leaves is drest,
    And ev’ -- ry post with hol -- ly.
    Though some churls at our mirth re -- pine.
    Round your fore -- heads gar -- lands twine.
    Drown sor -- row in a cup of wine. __
    And let us all __ be mer -- ry.
}

WithersCarol_alto_notes = {
  %%  v. 1
      a8\mf   | % alto 0
    d'8 d' d'16( e') fs'( g')   | % alto 1
    a'8 a' b'2\tenuto r8 a'   | % alto 2
    fs'8 d' e' cs'   | % alto 3
    d'4 d'8 a   | % alto 4
    d'8 d' d'16( e') fs'( g')   | % alto 5
    a'8 a' b'2\tenuto r8 r16 a'   | % alto 6
    fs'8 d' e'16( d') cs'8   | % alto 7
    d'4 d'   | % alto 8
    r8 fs'4\f-> a'8 g'4-> e'16 fs'   | % 9
    g'16( fs') e'8 fs'4   | % 10
    r8 e'4 cs'8 b4 cs'   | % 11
    b4 a8 a\> ~ 2   | % 12
    r2\! d'2\p   | % 13
    cs'4.(\< e'4 fs'8) g'4.\!   | % 14
    fs'4 g' g'8-! r g' a'\tenuto ~   | % 15
    a'2 ~ 4\> r8\! r16 g'\pp   | % 16
    fs'8 d' e'16( d') cs'8 d'4 d'   | % alto 17
}

WithersCarol_alto_lyrics = \lyricmode {
  %%  v. 1
    So now is come our joy -- ful’st feast,
    Let ev’ -- ry one be jol -- ly.
    Each room with i -- vy __ leaves is drest,
    And ev’ -- ry post with hol -- ly.
    Though some churls at our mirth re -- pine.
    Round your fore -- heads gar -- lands twine.
    Drown sor -- row in a cup of wine. __
    And let us all __ be mer -- ry.
}

WithersCarol_tenor_notes = {
  \clef "treble_8"
  %%  v. 1
      a,8\mf   | % ten 0
    d8 d d16( e) fs( g)   | % ten 1
    a8 a b2\tenuto r8 a   | % ten 2
    fs8 d e cs   | % ten 3
    d4 d8 a,   | % ten 4
    d8 d d16( e) fs( g)   | % ten 5
    a8 a b2\tenuto r8 r16 a   | % ten 6
    fs8 d e16( d) cs8   | % ten 7
    d4 d   | % ten 8
    r8 d'4\f-> b8 b4-> a16 d'   | % ten 9
    b8 b a4   | % ten 10
    r8 a4 fs8 fs4 e   | % ten 11
    e4 d8 d\> ~ 2   | % ten 12
    r4\! e\p fs2 ~   | % ten 13
    << { fs4. cs'2. } { s4.\< s s\! } >>   | % ten 14
    b16 cs' d'8-! r cs' d'2\tenuto ~   | % ten 15
    d'2 ~ 4\> r8\! r16 g\pp   | % ten 16
    fs8 d e16( d) cs8 d4 d   | % ten 17
}

WithersCarol_tenor_lyrics = \lyricmode {
  %%  v. 1
    So now is come our joy -- ful’st feast,
    Let ev’ -- ry one be jol -- ly.
    Each room with i -- vy __ leaves is drest,
    And ev’ -- ry post with hol -- ly.
    Though some churls at our mirth re -- pine.
    Round your fore -- heads gar -- lands twine.
    Drown sor -- row in a cup of wine. __
    And let us all __ be mer -- ry.
}

WithersCarol_bass_notes = {
  \clef bass
  %%  v. 1
      a,8\mf   | % bass 0
    d8 d d16( e) fs( g)   | % bass 1
    a8 a b2\tenuto r8 a   | % bass 2
    fs8 d e cs   | % bass 3
    d4 d8 a,   | % bass 4
    d8 d d16( e) fs( g)   | % bass 5
    a8 a b2\tenuto r8 r16 a   | % bass 6
    fs8 d e16( d) cs8   | % bass 7
    d4 d   | % bass 8
    d4.->\f d8 d4-> d8   | % bass 9
    d2   | % bass 10
    fs4. e8 d4 d   | % bass 11
    g,4 g,8 g,\> ~ 8 r a,4   | % bass 12
    b,1\p ~   | % bass 13
    b,2. ~ 8.\< d16 e fs   | % bass 14
    a8-!\! r a b\tenuto ~ 2 ~   | % bass 15
    b2 ~ 4\> r8\! r16 g\pp   | % bass 16
    fs8 d e16( d) cs8 d4 d   | % bass 17
}

WithersCarol_bass_lyrics = \lyricmode {
  %%  v. 1
    So now is come our joy -- ful’st feast,
    Let ev’ -- ry one be jol -- ly.
    Each room with i -- vy __ leaves is drest,
    And ev’ -- ry post with hol -- ly.
    Though some churls re -- pine.
    Round your fore -- heads gar -- lands twine. __
    Drown sor -- row in a cup of wine. __
    And let us all __ be mer -- ry.
}

\score {
  <<
    \new ScoreMarks \WithersCarol_global
    \new ChoirStaff <<
      \new ChoralStaff = "Staff_soprano" \with { \consists "Bar_number_engraver" }
      \new Voice = "Voice_soprano" << \WithersCarol_global \WithersCarol_soprano_notes >>
      \new Lyrics = sopLyrics \lyricsto "Voice_soprano" \WithersCarol_soprano_lyrics
      \new ChoralStaff = "Staff_alto"
      \new Voice = "Voice_alto" << \WithersCarol_global \WithersCarol_alto_notes >>
      \new Lyrics = altLyrics \lyricsto "Voice_alto" \WithersCarol_alto_lyrics
      \new ChoralStaff = "Staff_tenor"
      \new Voice = "Voice_tenor" << \WithersCarol_global \WithersCarol_tenor_notes >>
      \new Lyrics = tenLyrics \lyricsto "Voice_tenor" \WithersCarol_tenor_lyrics
      \new ChoralStaff = "Staff_bass"
      \new Voice = "Voice_bass" << \WithersCarol_global \WithersCarol_bass_notes >>
      \new Lyrics = bassLyrics \lyricsto "Voice_bass" \WithersCarol_bass_lyrics
    >>
  >>
}
\version "2.19.25"

#(define (lyric-text::interpolate-alignment grob)
   (let*
    ((width (cdr (ly:grob-property grob 'X-extent)))

     (lower-threshold 3)
     (upper-threshold 11)
     (maximum (- 4/5))
     
     ;; calculate parameters for use in the ‘sigmoid’ cubic function with
     ;; (sigmoid lower-threshold) --> 0
     ;; (sigmoid upper-threshold) --> maximum
     ;; and zero ‘slope’ in both these points, i.e. a smooth transition between
     ;; constants and interpolation
     
     (a (/ (* 2 maximum)
          (+ (- (expt upper-threshold 3))
            (* 3 upper-threshold upper-threshold lower-threshold)
            (* -3 upper-threshold lower-threshold lower-threshold)
            (expt lower-threshold 3))))
     (b (/ (- maximum (* a (+ (expt upper-threshold 3)
                             (* 2 (expt lower-threshold 3))
                             (* -3 upper-threshold (expt lower-threshold 2)))))
          (expt (- upper-threshold lower-threshold) 2)))
     (c (/ (- maximum
              (* b (- (expt upper-threshold 2) (expt lower-threshold 2)))
              (* a (- (expt upper-threshold 3) (expt lower-threshold 3))))
           (- upper-threshold lower-threshold)))
     (d (- maximum
          (* upper-threshold c)
          (* (expt upper-threshold 2) b)
          (* (expt upper-threshold 3) a)))

     (sigmoid (lambda (x) (+ (* a x x x) (* b x x) (* c x) d))))

    ;(format #t "The four parameters have been determined as: \n a ~a \n b ~a 
\n c ~a \n d ~a\n" a b c d)

    (cond
     ((<= width lower-threshold) 0)
     ((< lower-threshold width upper-threshold)
      (sigmoid width))
     ((>= width upper-threshold) maximum))))

\layout {
  \context {
    \Lyrics
    \override LyricText.self-alignment-X = #lyric-text::interpolate-alignment
  }
}
\version "2.19.25"

%%%%%%%%%%%%%%%%%%% switch lyrics on and off %%%%%%%%%%%%%%%%%%%%%%%%%%%

switchLyrics =
#(define-music-function (fn voices) (procedure? list?)
   "
@code{fn} must take a single symbol.
"
   (let*
    ((unfold-voices (lambda (sym) (case sym
                                    ((soprano sop) 'sopLyrics)
                                    ((sopOne) 'sopOneLyrics)
                                    ((sopTwo) 'sopTwoLyrics)
                                    ((mezzo mez) 'mezLyrics)
                                    ((mezOne) 'mezOneLyrics)
                                    ((mezTwo) 'mezTwoLyrics)
                                    ((alto alt) 'altLyrics)
                                    ((altOne) 'altOneLyrics)
                                    ((altTwo) 'altTwoLyrics)
                                    ((tenor ten) 'tenLyrics)
                                    ((tenOne) 'tenOneLyrics)
                                    ((tenTwo) 'tenTwoLyrics)
                                    ((baritone bar) 'barLyrics)
                                    ((barOne) 'barOneLyrics)
                                    ((barTwo) 'barTwoLyrics)
                                    ((bass bas) 'bassLyrics)
                                    ((bassOne basOne) 'bassOneLyrics)
                                    ((bassTwo basTwo) 'bassTwoLyrics))))
     (voices (map unfold-voices voices))
     (all-lyrics-grobs '(LyricText LyricSpace LyricHyphen LyricExtender))
     (tweaks (make-sequential-music (map fn all-lyrics-grobs)))
     (direct (lambda (ctx) #{ \context Lyrics = $(symbol->string ctx) $tweaks 
#}))
     )
    (make-sequential-music (map direct voices))))

omitLyrics =
#(define-music-function (voices) (list?)
   (let
    ((omit-single (lambda (grob) (omit (list grob)))))
    (switchLyrics omit-single voices)))
hideLyrics = #omitLyrics

showLyrics =
#(define-music-function (voices) (list?)
   (let
    ((show-single (lambda (grob) (undo (omit (list grob))))))
    (switchLyrics show-single voices)))
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to