]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue 3799: New satb.ly built-in template and template framework
authorTrevor Daniels <t.daniels@treda.co.uk>
Sat, 18 Apr 2015 15:28:55 +0000 (16:28 +0100)
committerTrevor Daniels <t.daniels@treda.co.uk>
Fri, 24 Apr 2015 10:25:23 +0000 (11:25 +0100)
  Add kits as aids for providing built-in templates ("tkits")

  Replace the satb.ly template with one built from the tkits, which
  corrects some errors and extends the facilities:
    - fixes issue 4192
    - \lyricsmode should be used; never \lyricsto
    - Women and Men one-voice staves added
    - Two-voice staves called MenDivided, WomenDivided
    - Soprano and Tenor music may now be omitted without error
    - midi instruments may be specified
    - midi channel mapping is by instrument
    - midi instruments are by voice, not staff
    - regression tests added
    - documentation minimally updated

12 files changed:
Documentation/learning/templates.itely
input/regression/satb-template-on-two-staves-with-verses.ly [new file with mode: 0644]
input/regression/satb-template-soprano-and-tenor-may-be-omitted.ly [new file with mode: 0644]
input/regression/satb-template-with-changed-instrument-names.ly [new file with mode: 0644]
input/regression/satb-template-with-men-women-and-descant.ly [new file with mode: 0644]
ly/base-tkit.ly [new file with mode: 0644]
ly/lyrics-tkit.ly [new file with mode: 0644]
ly/piano-tkit.ly [new file with mode: 0644]
ly/satb.ly
ly/staff-tkit.ly [new file with mode: 0644]
ly/vocal-tkit.ly [new file with mode: 0644]
ly/voice-tkit.ly [new file with mode: 0644]

index cc35e50da7c4c7827b407d35f1e5b621df466b71..1fd7b7b4666dafc7834e626f22ffc42debe490e3 100644 (file)
@@ -106,11 +106,11 @@ parts:
 
 @lilypond[verbatim, quote]
   SopranoMusic = \relative { a'4 a a a }
-  SopranoLyricsOne = \lyricsto "Soprano" {
+  SopranoLyricsOne = \lyricmode {
     \set stanza = "1."
     Words to verse one
   }
-  SopranoLyricsTwo = \lyricsto "Soprano" {
+  SopranoLyricsTwo = \lyricmode {
     \set stanza = "2."
     Words to verse two
   }
diff --git a/input/regression/satb-template-on-two-staves-with-verses.ly b/input/regression/satb-template-on-two-staves-with-verses.ly
new file mode 100644 (file)
index 0000000..43055b7
--- /dev/null
@@ -0,0 +1,28 @@
+\version "2.19.19"
+
+\header {
+  texidoc ="This should produce an SATB score on two staves
+with 5 verses and piano accompaniment."
+
+}
+
+TwoVoicesPerStaff = ##t
+
+SopranoMusic = \relative { c''4 c c c }
+AltoMusic = \relative { g'4 g g g }
+VerseOne = \lyricmode { \set stanza = "1." First _ stan -- za }
+VerseTwo = \lyricmode { \set stanza = "2." Se -- cond stan -- za }
+VerseThree = \lyricmode { \set stanza = "3." Third _ stan -- za }
+VerseFour = \lyricmode { \set stanza = "4." Fourth _ stan -- za }
+VerseFive = \lyricmode { \set stanza = "5." Fifth _ stan -- za }
+TenorMusic = \relative { c'4 c c c }
+BassMusic = \relative { g2 g4 g }
+
+PianoRHMusic = \relative { c''4 c c c  }
+PianoLHMusic = \relative { c2 c }
+
+\layout {
+  ragged-right = ##t
+}
+
+\include "satb.ly"
diff --git a/input/regression/satb-template-soprano-and-tenor-may-be-omitted.ly b/input/regression/satb-template-soprano-and-tenor-may-be-omitted.ly
new file mode 100644 (file)
index 0000000..cfce5ee
--- /dev/null
@@ -0,0 +1,19 @@
+\version "2.19.19"
+
+\header {
+  texidoc ="Soprano and tenor voices may be omitted without
+error, even when TwoVoicesPerStaff is specified and Alto
+and Bass lyrics are provided."
+}
+TwoVoicesPerStaff = ##t
+
+AltoMusic = \relative { g'4 g g g }
+AltoLyrics = \lyricmode { Al -- to ly -- rics }
+BassMusic = \relative { g2 g4 g }
+BassLyrics = \lyricmode { Bass ly -- rics }
+
+\layout {
+  ragged-right = ##t
+}
+
+\include "satb.ly"
diff --git a/input/regression/satb-template-with-changed-instrument-names.ly b/input/regression/satb-template-with-changed-instrument-names.ly
new file mode 100644 (file)
index 0000000..cea70c0
--- /dev/null
@@ -0,0 +1,38 @@
+\version "2.19.19"
+
+\header {
+  texidoc ="Instrument names and short instrument names
+can be changed when using the satb built-in template."
+}
+
+Time = { s1 \break s1 }
+TwoVoicesPerStaff = ##t
+
+SopranoInstrumentName = "Soprani"
+SopranoShortInstrumentName = "Sop"
+AltoInstrumentName = "Contralti"
+AltoShortInstrumentName = "Con"
+MenDividedInstrumentName = "Men Div"
+MenDividedShortInstrumentName = "M Div"
+MenInstrumentName = "Men Uni"
+MenShortInstrumentName = "M Uni"
+TenorInstrumentName = "Tenori"
+BassInstrumentName = "Bassi"
+PianoInstrumentName = "Organ"
+
+MenMusic = \relative { s1 | c4 c c c }
+SopranoMusic = \relative { c''4 c c c | c c c c }
+AltoMusic = \relative { g'4 g g g | g g g g }
+TenorMusic = \relative { c'4 c c c | s1 }
+BassMusic = \relative { g2 g4 g | s1 }
+
+PianoRHMusic = \relative { c''4 c c c | c c c c }
+PianoLHMusic = \relative { c2 c c c }
+
+\layout {
+  ragged-right = ##t
+}
+
+\paper { left-margin = 15 }
+
+\include "satb.ly"
diff --git a/input/regression/satb-template-with-men-women-and-descant.ly b/input/regression/satb-template-with-men-women-and-descant.ly
new file mode 100644 (file)
index 0000000..c8ff7d3
--- /dev/null
@@ -0,0 +1,34 @@
+\version "2.19.19"
+
+\header {
+  texidoc ="This should produce an SATB score with piano
+accompaniment, with four voices in the first system, unison
+women voices with descant in the second system and unison
+women and unison men voices in the third system. "
+}
+
+Time = { s1 \break s1 \break }
+
+DescantMusic = \relative { s1 | e''4 e e e | s1 }
+DescantLyrics = \lyricmode { Des -- cant ly -- rics }
+SopranoMusic = \relative { c''8 c c4 c c | s1*2 | }
+SopranoLyrics = \lyricmode { So -- pra -- no ly -- rics }
+AltoMusic = \relative { g'4 g g g | s1*2 | }
+AltoLyrics = \lyricmode { Al -- to ly -- rics }
+WomenMusic = \relative { s1 | g'4 g g g | g g g g | }
+WomenLyrics = \lyricmode { Wo -- men ly -- rics Wo -- men ly -- rics }
+MenMusic = \relative { s1*2 | e2 e4 e | }
+MenLyrics = \lyricmode { Men ly -- rics }
+TenorMusic = \relative { c'4 c c c | s1*2 | }
+TenorLyrics = \lyricmode { Te -- nor ly -- rics }
+BassMusic = \relative { g2 g4 g | s1*2 }
+BassLyrics = \lyricmode { Bass ly -- rics }
+
+PianoRHMusic = \relative { c''4 c c c | c c c c | c c c c | }
+PianoLHMusic = \relative { c2 c | c c | c c | }
+
+\layout {
+  ragged-right = ##t
+}
+
+\include "satb.ly"
diff --git a/ly/base-tkit.ly b/ly/base-tkit.ly
new file mode 100644 (file)
index 0000000..6061475
--- /dev/null
@@ -0,0 +1,117 @@
+%\version "2.19.19"
+
+%%% These are the general utility functions and storage
+%   used by the built-in templates and the template kits
+%   (tkits) supporting them.
+
+% TODO: these may be more sensibly (re)defined as a scm file
+
+#(define (get-id str)
+   "Return the identifier with the value str"
+   (ly:parser-lookup parser (string->symbol str)))
+
+#(define (make-id a b)
+  "Return the identifier formed from concatenating the
+   two strings provided as arguments."
+   (get-id (string-append a b)))
+
+#(define (cartesian a b)
+  "Return a list formed from concatenating every element
+   of list a with every element of list b (the cartesian
+   product a X b)."
+   (append-map
+    (lambda (x)
+      (map
+       (lambda (y)
+         (string-append x y))
+       b))
+    a))
+
+#(define (define-missing-variables! ids)
+  "Check if each of the identifiers listed in the argument is
+   known to the parser.  If any are not, define them and set
+   their value to #f"
+   (for-each
+      (lambda (id)
+        (define sym (string->symbol id))
+          (if (null? (ly:parser-lookup parser sym))
+            (ly:parser-define! parser sym #f)))
+      ids))
+
+% Define the lists used to hold the names and
+% component names which form the variable names
+% used in the templates.  These are populated by the
+% set-music-definitions! procedure
+% The variables defined here as empty lists will be provided
+% by the template, and may be set to any values there.
+#(define voice-prefixes '())   % eg "Soprano"
+#(define all-music-names '())  % eg "SopranoMusic"
+#(define lyrics-postfixes '()) % eg "Lyrics"
+#(define lyrics-names '())     % eg "VerseOne"
+
+% Define the derived variables to be populated
+#(define all-music-lyrics-names '())  % eg "SopranoLyrics"
+#(define AllMusic (make-music 'SequentialMusic 'void #t))
+#(define KeepAlive AllMusic)   % used to ensure voices don't terminate
+#(define have-music #f)        % -> #t when at least one music name
+                                %    contains music
+#(define voice-postfixes
+   ;; These names are used verbatim in code, so may not be changed
+   '("InstrumentName"
+     "MidiInstrument"
+     "Music"
+     "ShortInstrumentName"))
+
+#(define variable-names
+   ;; These names are used verbatim in code, so may not be changed
+   '("Key"
+     "Layout"
+     "PianoDynamics"
+     "Time"
+     "TwoVoicesPerStaff"))
+
+% Define the predicates used in the tkits and templates
+#(define (above-or-below? x)
+  (member x '("Above" "Below")))
+
+#(define (up-or-down? x)
+   (member x '("Down" "Up" "")))
+
+#(define (voice-prefix? x)
+   (member x voice-prefixes))
+
+#(define (vocal-lyrics-or-verses? x)
+  (or (member x lyrics-postfixes)
+      (member x lyrics-names)))
+
+
+#(define (set-music-definitions! prefixes lyr-postfixes lyr-names)
+  "Populate the name definitions and their derivatives
+   with the values provided by the calling template"
+   (set! voice-prefixes prefixes)
+   (append! variable-names lyr-names)
+   (set! all-music-names
+         (cartesian voice-prefixes '("Music")))
+   (set! lyrics-postfixes lyr-postfixes)
+   (set! lyrics-names lyr-names)
+   (set! all-music-lyrics-names
+     (cartesian voice-prefixes (append
+                                voice-postfixes
+                                lyrics-postfixes)))
+   (define-missing-variables! (append
+                                  all-music-lyrics-names
+                                  variable-names))
+   (set! AllMusic
+     (make-simultaneous-music
+      (filter ly:music?
+              (map
+               (lambda (x)
+                 (get-id x))
+               all-music-names))))
+   (set! KeepAlive
+         (skip-of-length AllMusic))
+   (set! have-music
+         (ly:moment<?
+          (ly:make-moment 0)
+          (ly:music-length KeepAlive))))
+
diff --git a/ly/lyrics-tkit.ly b/ly/lyrics-tkit.ly
new file mode 100644 (file)
index 0000000..91a19cd
--- /dev/null
@@ -0,0 +1,50 @@
+%\version "2.19.19"
+
+%%% The function used by the built-in templates to
+%   build a lyrics context and associate it with a voice.
+
+\include "voice-tkit.ly"
+
+make-one-stanza =
+#(define-music-function
+  (parser location pos staffPrefix voicePrefix altVoicePrefix lyrics)
+  ((above-or-below? #f)
+   voice-prefix?
+   voice-prefix?
+   (voice-prefix?)
+   vocal-lyrics-or-verses?)
+
+   "Make a single stanza
+           (pos: positioned Above or Below the named staff)
+    staffPrefix: voice prefix for the staff to be positioned against
+    voicePrefix: voice prefix for the associated voice
+(altVoicePrefix: voice prefix for the associated voice
+                 if the first is not present)
+         lyrics: the words"
+
+   (let* ((lyrics-name (string-append voicePrefix lyrics))
+          (staff-name (string-append staffPrefix "Staff"))
+          (music-name (make-id voicePrefix "Music"))
+          (assoc-voice-name (if music-name
+                               voicePrefix
+                               altVoicePrefix))
+          (with-clause
+           (if pos
+               #{ \with {
+                    #(string-append "align" pos "Context") = #staff-name
+                  }
+               #}
+               (make-music 'SequentialMusic 'void #t)))
+          (stanza (if (member lyrics lyrics-postfixes)
+                        (make-id voicePrefix lyrics)
+                        (get-id lyrics))))
+   (if (and stanza  ;we need lyrics and at least one associated voice
+            (or music-name
+                (make-id altVoicePrefix "Music")))
+        #{
+          \new Lyrics = #lyrics-name
+          \with { #with-clause }
+          \lyricsto #(string-append assoc-voice-name "Voice")
+          { #stanza }
+        #}
+        (make-music 'SequentialMusic 'void #t))))
diff --git a/ly/piano-tkit.ly b/ly/piano-tkit.ly
new file mode 100644 (file)
index 0000000..e7d9744
--- /dev/null
@@ -0,0 +1,45 @@
+%\version "2.19.19"
+
+\include "staff-tkit.ly"
+
+make-pianostaff =
+#(define-music-function (parser location) ()
+
+(if (not PianoRHMidiInstrument)
+       (set! PianoRHMidiInstrument
+             (if PianoMidiInstrument
+                 PianoMidiInstrument
+                 "acoustic grand")))
+
+(if (not PianoLHMidiInstrument)
+       (set! PianoLHMidiInstrument
+             (if PianoMidiInstrument
+                 PianoMidiInstrument
+                 "acoustic grand")))
+
+  (if (or
+        PianoRHMusic
+        PianoLHMusic)
+       #{
+
+\new PianoStaff = "PianoStaff"
+  \with {
+    instrumentName = \markup \smallCaps
+      #(if PianoInstrumentName
+           PianoInstrumentName
+           "Piano" )
+    shortInstrumentName = \markup \smallCaps
+      #(if PianoShortInstrumentName
+           PianoShortInstrumentName
+           "")
+    \override VerticalAxisGroup.remove-empty = ##t
+    \override VerticalAxisGroup.remove-first = ##t
+  }
+  <<
+    \make-one-voice-staff ##f "PianoRH" "treble" ""
+    #(if PianoDynamics
+         #{ \new Dynamics = "PianoDynamics" { #PianoDynamics } #} )
+    \make-one-voice-staff ##f "PianoLH" "bass" ""
+  >>
+       #}
+     (make-music 'SequentialMusic 'void #t)))
index a8ae1347acdb6706b54ab9997ebf677da057a5a6..df57811e4856a62d4fa0a0371ce9ccb7e6fd98ad 100644 (file)
@@ -1,4 +1,4 @@
-%\version "2.19.17"
+%\version "2.19.19"
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%                                                %%
   of the following staves:
 
   Descant Staff
-  Soprano and Alto (optionally on two Staves or one Staff)
+  Women Staff (single voice on one staff)
+  Soprano and Alto (optionally on two Staves or one Staff each)
   Multiple verses (up to 9)
-  Tenor and Bass (optionally on two Staves or one Staff)
+  Tenor and Bass (optionally on two Staves or one Staff each)
+  Men Staff (single voice on one staff)
   Piano Staff
 
   It is intended primarily to hide the complexity of the context
 
   \paper { ... }
   \header { ... }
-  TwoVoicesPerStaff = ##f or ##t
   Key = { ... }
   Time = { ... }
-  Layout = \layout { ... }
   DescantMusic = \relative { ... }
   DescantLyrics = \lyricmode { ... }
+  WomenMusic = \relative { ... }
+  WomenLyrics = \lyricmode { ... }
   SopranoMusic = \relative { ... }
   SopranoLyrics = \lyricmode { ... }
   AltoMusic = \relative { ... }
   TenorLyrics = \lyricmode { ... }
   BassMusic = \relative { ... }
   BassLyrics = \lyricmode { ... }
+  MenMusic = \relative { ... }
+  MenLyrics = \lyricmode { ... }
   PianoRHMusic = \relative { ... }
   PianoDynamics = { ... }
   PianoLHMusic = \relative { ... }
+  TwoVoicesPerStaff = ##f
   \include "satb.ly"
 
   All of the definitions are optional. Staves with no music will be
   omitted from the output.
 
-  Other variables, such as the instrumentName, can also be changed by
-  defining variables like AltoInstrumentName.  The key is defined in
-  the variable Key, and the structure of time and repeats in the
-  variable Time, using spacer rests.  A \layout block may be defined in
-  the variable Layout.  There is no default \header block and no default
-  \paper block.
+  Other variables, such as the instrumentName, shortInstrumentName
+  and MidiInstrument can also be changed by defining variables like
+  AltoInstrumentName, BassMidiInstrument, etc.  The prefixes for staves
+  containing two divided voices are WomenDivided and MenDivided, hence
+  the corresponding variables would be WomenDividedInstrumentName, etc.
+  The key is defined in the variable Key, and the structure of time
+  and repeats in the variable Time, using spacer rests.
+
+  A \layout block may be defined in the variable Layout.  There is
+  no default \header block and no default \paper block.
 
   Music may be tagged with #'print or #'play to be included only in
   the printed score or in the MIDI file respectively.
 
 %}
 
-#(defmacro satb-defaulting (name . default)
-  (if (defined? name) name (if (pair? default) (car default) *unspecified*)))
-
-#(define (satb-sym . strings) (string->symbol (apply string-append strings)))
-
-#(defmacro satb-short-name (part)
-  "Use PartShortInstrumentName, or the first letter of
-PartInstrumentName or its default."
-  (if (defined? (satb-sym part "Music"))
-    (let ((sname (satb-sym part "ShortInstrumentName")))
-      (if (defined? sname)
-        sname
-        `(substring (satb-defaulting ,(satb-sym part "InstrumentName") ,part)
-                    0 1)))
-    ""))
-
-#(defmacro satb-lyrics-if-defined (name voice . optionals)
-  (let ((above (and (pair? optionals) (car optionals))))
-    (if (defined? name)
-      `(make-music 'ContextSpeccedMusic
-         'create-new #t
-         'context-type 'Lyrics
-         'property-operations ',(if above `((assign alignAboveContext ,above)) '())
-         'element (make-music 'LyricCombineMusic
-                   'associated-context ,voice
-                   'element ,name))
-      *unspecified*)))
-
-#(defmacro satb-one-voice-staff (name clef)
-  `#{ <<
-     \new Staff = #,name \with {
-       instrumentName = \markup \smallCaps
-         #(satb-defaulting ,(satb-sym name "InstrumentName") ,name)
-       shortInstrumentName = \markup \smallCaps #(satb-short-name ,name)
-       midiInstrument = "clarinet"
-     } {
-       #(satb-defaulting Key)
-       \clef #,clef
-       \new Voice = #,name <<
-         \satb-spacers
-         #(satb-defaulting Time)
-         \dynamicUp
-         #(satb-defaulting ,(satb-sym name "Music"))
-       >>
-     }
-     #(satb-lyrics-if-defined ,(satb-sym name "Lyrics") ,name)
-     #(satb-lyrics-if-defined ,(satb-sym name "LyricsOne") ,name)
-     #(satb-lyrics-if-defined ,(satb-sym name "LyricsTwo") ,name)
-     #(satb-lyrics-if-defined ,(satb-sym name "LyricsThree") ,name)
-   >> #})
-
-#(defmacro satb-two-voice-staff (name clef v1name v2name)
-  `#{ <<
-    \new Staff = #,name \with {
-      instrumentName = \markup \right-column \smallCaps {
-        #(satb-defaulting ,(satb-sym v1name "InstrumentName") ,v1name)
-        #(satb-defaulting ,(satb-sym v2name "InstrumentName") ,v2name)
-      }
-      shortInstrumentName = \markup \right-column \smallCaps {
-        #(satb-short-name ,v1name)
-        #(satb-short-name ,v2name)
-      }
-      midiInstrument = "clarinet"
-    } <<
-      #(satb-defaulting Key)
-      \clef #,clef
-      \new Voice = #,v1name <<
-        \satb-spacers
-        #(satb-defaulting Time)
-        \voiceOne
-        \dynamicUp
-        #(satb-defaulting ,(satb-sym v1name "Music"))
-      >>
-      \new Voice = #,v2name <<
-        \satb-spacers
-        #(satb-defaulting Time)
-        \voiceTwo
-        #(satb-defaulting ,(satb-sym v2name "Music"))
-      >>
-    >>
-    #(satb-lyrics-if-defined ,(satb-sym v1name "Lyrics") ,v1name ,name)
-    #(satb-lyrics-if-defined ,(satb-sym v1name "LyricsOne") ,v1name ,name)
-    #(satb-lyrics-if-defined ,(satb-sym v1name "LyricsTwo") ,v1name ,name)
-    #(satb-lyrics-if-defined ,(satb-sym v1name "LyricsThree") ,v1name ,name)
-    #(satb-lyrics-if-defined ,(satb-sym v2name "Lyrics") ,v2name)
-    #(satb-lyrics-if-defined ,(satb-sym v2name "LyricsOne") ,v2name)
-    #(satb-lyrics-if-defined ,(satb-sym v2name "LyricsTwo") ,v2name)
-    #(satb-lyrics-if-defined ,(satb-sym v2name "LyricsThree") ,v2name)
-  >> #})
-
-satb-define-if-unused =
-#(define-void-function (parser location syms) (symbol-list?)
-   (for-each
-      (lambda (sym)
-        (if (null? (ly:parser-lookup parser sym))
-            (ly:parser-define! parser sym *unspecified*)))
-      syms))
-
-\satb-define-if-unused
-  #'(
-    DescantMusic
-    SopranoMusic
-    AltoMusic
-    TenorMusic
-    BassMusic
-  )
-
-satb-AllChoirMusic = <<
-  \DescantMusic
-  \SopranoMusic
-  \AltoMusic
-  \TenorMusic
-  \BassMusic
->>
-
-#(define satb-spacers (skip-of-length satb-AllChoirMusic))
-
-SATB = <<
+\include "vocal-tkit.ly"
+\include "piano-tkit.ly"
+
+#(define satb-voice-prefixes
+   ;; These define the permitted prefixes to various names.
+   ;; They are combined with a fixed set of postfixes to form
+   ;; names such as AltoMusic, BassInstrumentName, etc.
+   ;; These names may be redefined.
+   '("Alto"
+     "Bass"
+     "Descant"
+     "Men"
+     "MenDivided"
+     "Piano"
+     "PianoLH"
+     "PianoRH"
+     "Soprano"
+     "Tenor"
+     "Women"
+     "WomenDivided"))
+
+#(define satb-lyrics-postfixes
+   ;; These define the permitted postfixes to the names of lyrics.
+   ;; They are combined with the prefixes to form names like
+   ;; AltoLyrics, etc.
+   ;; These names may be redefined or extended.
+  '("Lyrics"
+    "LyricsOne"
+    "LyricsTwo"
+    "LyricsThree"
+    "LyricsFour"))
+
+#(define satb-lyrics-variable-names
+   ;; These define the names which may be used to specify stanzas
+   ;; which go between the two two-voice staves when TwoVoicesPerStaff
+   ;; is set to #t.  They may be redefined or extended.
+  '("VerseOne"
+    "VerseTwo"
+    "VerseThree"
+    "VerseFour"
+    "VerseFive"
+    "VerseSix"
+    "VerseSeven"
+    "VerseEight"
+    "VerseNine"))
+
+%% make the above definitions available
+#(set-music-definitions!
+  satb-voice-prefixes
+  satb-lyrics-postfixes
+  satb-lyrics-variable-names)
+
+
+SATB =
+{
   \new ChoirStaff
   \with {
     \override VerticalAxisGroup.remove-empty = ##t
     \override VerticalAxisGroup.remove-first = ##t
   }
   <<
-    #(satb-one-voice-staff "Descant" "treble")
-
-    #(if (satb-defaulting TwoVoicesPerStaff #f)
-      (satb-two-voice-staff "Women" "treble" "Soprano" "Alto")
-      (make-simultaneous-music (list (satb-one-voice-staff "Soprano" "treble")
-                                     (satb-one-voice-staff "Alto" "treble"))))
-
-    #(satb-lyrics-if-defined VerseOne "Soprano")
-    #(satb-lyrics-if-defined VerseTwo "Soprano")
-    #(satb-lyrics-if-defined VerseThree "Soprano")
-    #(satb-lyrics-if-defined VerseFour "Soprano")
-    #(satb-lyrics-if-defined VerseFive "Soprano")
-    #(satb-lyrics-if-defined VerseSix "Soprano")
-    #(satb-lyrics-if-defined VerseSeven "Soprano")
-    #(satb-lyrics-if-defined VerseEight "Soprano")
-    #(satb-lyrics-if-defined VerseNine "Soprano")
-
-    #(if (satb-defaulting TwoVoicesPerStaff #f)
-      (satb-two-voice-staff "Men" "bass" "Tenor" "Bass")
-      (make-simultaneous-music (list (satb-one-voice-staff "Tenor" "treble_8")
-                                     (satb-one-voice-staff "Bass" "bass"))))
-  >>  % End ChoirStaff
-
-  \new PianoStaff
-  \with {
-    instrumentName = \markup \smallCaps
-                       #(satb-defaulting PianoInstrumentName "Piano" )
-    shortInstrumentName = \markup \smallCaps #(satb-short-name "Piano" )
-    \override VerticalAxisGroup.remove-empty = ##t
-    \override VerticalAxisGroup.remove-first = ##t
-  }
-  <<
-    \new Staff {
-      \clef "treble"
-      #(satb-defaulting Key)
-      \new Voice <<
-        \satb-spacers
-        #(satb-defaulting Time)
-        #(satb-defaulting PianoRHMusic)
-      >>
-    }
-    \new Dynamics {
-      #(satb-defaulting PianoDynamics)
-    }
-    \new Staff {
-      \clef "bass"
-      #(satb-defaulting Key)
-      \new Voice <<
-        \satb-spacers
-        #(satb-defaulting Time)
-        #(satb-defaulting PianoLHMusic)
-      >>
-    }
+    \make-one-voice-vocal-staff "Descant" "treble"
+    \make-one-voice-vocal-staff "Women" "treble"
+    #(if TwoVoicesPerStaff
+      #{
+        \make-two-vocal-staves-with-stanzas
+          "WomenDivided" "treble" "MenDivided" "bass"
+          "Soprano" "Alto" "Tenor" "Bass"
+          #satb-lyrics-variable-names
+      #}
+      #{
+        <<
+          \make-one-voice-vocal-staff "Soprano" "treble"
+          \make-one-voice-vocal-staff "Alto" "treble"
+          \make-one-voice-vocal-staff "Tenor" "treble_8"
+          \make-one-voice-vocal-staff "Bass" "bass"
+        >>
+      #} )
+    \make-one-voice-vocal-staff "Men" "bass"
   >>
->>
+}
+
+Piano = \make-pianostaff
 
 \tagGroup #'(print play)
 
 \score {
-  \keepWithTag #'print \SATB
-  \layout { $(satb-defaulting Layout) }
+  \keepWithTag #'print
+  #(if have-music
+       #{ << \SATB \Piano >> #}
+       #{ { } #} )
+  \layout { $(if Layout #{ \Layout #} ) }
 }
 
+
 \score {
-  \keepWithTag #'play \SATB
-  \midi { }
+  \keepWithTag #'play
+  #(if have-music
+       #{ << \SATB \Piano >> #}
+       #{ { } #} )
+  \midi {
+    \context {
+      \Score
+      midiChannelMapping = #'instrument
+    }
+  }
 }
diff --git a/ly/staff-tkit.ly b/ly/staff-tkit.ly
new file mode 100644 (file)
index 0000000..a0f827a
--- /dev/null
@@ -0,0 +1,178 @@
+%\version "2.19.19"
+
+\include "voice-tkit.ly"
+
+
+%% Staff-oriented functions
+
+% These assume the following lists have been defined:
+%   voice-prefixes  eg "Soprano"
+%   voice-postfixes  eg "Music"
+%   lyrics-postfixes  eg "Lyrics"
+%   lyrics-names  eg "VerseOne"
+%   variable-names  eg "Time"
+%
+% The first three lists are used to generate compound
+% names such as "SopranoLyrics" and "SopranoInstrumentName"
+% The last two lists of names are used as-is.
+
+
+make-one-voice-staff =
+#(define-music-function (parser location show-instrName name clef dynamic-direction)
+   ((boolean? #t) voice-prefix? string? (up-or-down? ""))
+
+   "Make a staff with one voice (no lyrics)
+    show-instrName: show instrument and short instrument names?
+              name: the default prefix for instrument name and music
+              clef: the clef for this staff
+ dynamic-direction: dynamics are up, down or neither"
+
+   (define music (make-id name "Music"))
+   (define instrName (make-id name "InstrumentName"))
+   (define shortInstrName (make-id name "ShortInstrumentName"))
+   (define midiName (make-id name "MidiInstrument"))
+   (define dynUp (equal? dynamic-direction "Up"))
+   (define dynDown (equal? dynamic-direction "Down"))
+   (if music
+     #{
+       \new Staff = #(string-append name "Staff")
+       \with {
+         instrumentName = \markup \smallCaps {
+           #(if show-instrName
+                (if instrName
+                     #{ #instrName #}
+                     #{ #name #} )
+                #{ "" #} )
+         }
+         shortInstrumentName = \markup \smallCaps {
+           #(if show-instrName
+                (if shortInstrName
+                     #{ #shortInstrName #}
+                     (if instrName
+                         #{ #(substring instrName 0 1) #}
+                         #{ #(substring name 0 1) #} ))
+                     #{ "" #} )
+         }
+         midiInstrument =
+           #(if midiName
+                #{ #midiName #}
+                #{ "clarinet" #} )
+         #(if dynUp
+              #{ \dynamicUp #}
+              (if dynDown
+                  #{ \dynamicDown #}
+                  #{ \dynamicNeutral #} ))
+       }
+       {
+         #(if Key #{ \Key #} )
+         \clef #clef
+         \make-voice #name
+       }
+     #}
+     (make-music 'SequentialMusic 'void #t)))
+
+
+make-two-voice-staff =
+#(define-music-function (parser location name clef v1name v2name)
+   (voice-prefix? string? voice-prefix? voice-prefix?)
+
+   "Make a vocal staff with two voices
+      name: the prefix to the staff name
+      clef: the clef to use
+    v1name: the prefix to the name of voice one
+    v2name: the prefix to the name of voice two "
+
+   (define v1music (make-id v1name "Music"))
+   (define v2music (make-id v2name "Music"))
+   (define instrName (make-id name "InstrumentName"))
+   (define v1InstrName (make-id v1name "InstrumentName"))
+   (define v2InstrName (make-id v2name "InstrumentName"))
+   (define shortInstrName (make-id name "ShortInstrumentName"))
+   (define v1ShortInstrName (make-id v1name "ShortInstrumentName"))
+   (define v2ShortInstrName (make-id v2name "ShortInstrumentName"))
+   (define v1midiName (make-id v1name "MidiInstrument"))
+   (define v2midiName (make-id v2name "MidiInstrument"))
+   (if (or v1music v2music)
+       #{
+         <<
+           \new Staff = #(string-append name "Staff")
+           \with {
+             \remove "Staff_performer"
+             instrumentName =
+               #(if instrName
+                 #{ \markup \smallCaps #instrName #}
+                 #{ \markup \right-column \smallCaps {
+                  #(if v1music
+                       (if v1InstrName
+                           v1InstrName
+                           v1name)
+                       "")
+                  #(if v2music
+                       (if v2InstrName
+                           v2InstrName
+                           v2name)
+                       "") } #} )
+             shortInstrumentName =
+               #(if shortInstrName
+                  #{ \markup \smallCaps #shortInstrName #}
+                  #{ \markup \right-column \smallCaps {
+                    #(if v1music
+                         (if v1ShortInstrName
+                             v1ShortInstrName
+                             (if v1InstrName
+                                 (substring v1InstrName 0 1)
+                                 (substring v1name 0 1)))
+                         "")
+                    #(if v2music
+                         (if v2ShortInstrName
+                             v2ShortInstrName
+                             (if v2InstrName
+                                 (substring v2InstrName 0 1)
+                                 (substring v2name 0 1)))
+                         "") } #} )
+           }
+           <<
+             #(if Key #{ \Key #} )
+             \clef #clef
+
+             #(if v1music
+               #{
+                 \new Voice = #(string-append v1name "Voice")
+                 \with {
+                   \consists "Staff_performer"
+                   \dynamicUp
+                   midiInstrument =
+                     #(if v1midiName
+                          #{ #v1midiName #}
+                          #{ "clarinet" #})
+                 }
+                 <<
+                   #(if KeepAlive #{ \KeepAlive #} )
+                   #(if Time #{ \Time #} )
+                   #(if v2music #{ \voiceOne #} #{ \oneVoice #} )
+                   #v1music
+                 >>
+               #} )
+
+             #(if v2music
+               #{
+                 \new Voice = #(string-append v2name "Voice")
+                 \with {
+                   \consists "Staff_performer"
+                   \dynamicDown
+                   midiInstrument =
+                     #(if v2midiName
+                          #{ #v2midiName #}
+                          #{ "clarinet" #})
+                 }
+                 <<
+                   #(if KeepAlive #{ \KeepAlive #} )
+                   #(if Time #{ \Time #} )
+                   #(if v1music #{ \voiceTwo #} #{ \oneVoice #} )
+                   #v2music
+                 >>
+               #} )
+           >>
+         >>
+       #}
+        (make-music 'SequentialMusic 'void #t)))
diff --git a/ly/vocal-tkit.ly b/ly/vocal-tkit.ly
new file mode 100644 (file)
index 0000000..cad4ea4
--- /dev/null
@@ -0,0 +1,90 @@
+%\version "2.19.19"
+
+\include "lyrics-tkit.ly"
+\include "staff-tkit.ly"
+
+make-one-voice-vocal-staff =
+#(define-music-function (parser location name clef)
+   (voice-prefix? string?)
+
+   "Make a staff with one voice and lyrics beneath
+     name: the default prefix for instrument name and music
+     clef: the clef for this staff "
+
+   (if (make-id name "Music")
+     #{
+       <<
+         \make-one-voice-staff #name #clef "Up"
+         #(make-simultaneous-music
+           (reverse (map
+             (lambda (lyrics-postfix)
+               #{ \make-one-stanza "Below" #name #name #lyrics-postfix #} )
+               lyrics-postfixes)))
+       >>
+     #}
+     (make-music 'SequentialMusic 'void #t)))
+
+make-two-voice-vocal-staff =
+#(define-music-function (parser location name clef v1name v2name)
+   (voice-prefix? string? voice-prefix? voice-prefix?)
+
+   "Make a vocal staff with two voices and lyrics above and below
+      name: the prefix to the staff name
+      clef: the clef to use
+    v1name: the prefix to the name of voice one
+    v2name: the prefix to the name of voice two "
+
+   (define v1music (make-id v1name "Music"))
+   (define v2music (make-id v2name "Music"))
+
+   #{
+     <<
+       \make-two-voice-staff #name #clef #v1name #v2name
+       #(if v1music
+           (make-simultaneous-music
+              (map
+               (lambda (lyrics-postfix)
+                 #{ \make-one-stanza "Above" #name #v1name #lyrics-postfix #} )
+               lyrics-postfixes)))
+
+       #(if v2music
+            (make-simultaneous-music
+             (reverse (map
+              (lambda (lyrics-postfix)
+                 #{ \make-one-stanza "Below" #name #v2name #lyrics-postfix #} )
+               lyrics-postfixes))))
+     >>
+   #} )
+
+make-two-vocal-staves-with-stanzas =
+#(define-music-function
+  (parser location
+    upperName upperClef lowerName lowerClef
+    v1name v2name v3name v4name verses)
+  (voice-prefix? string? voice-prefix? string?
+    voice-prefix? voice-prefix? voice-prefix? voice-prefix? list?)
+
+  "Make two two-voice vocal staves with several stanzas between them.
+The number of stanzas is determined by the number of populated verse names.
+  upperName: the prefix to the upper staff name
+  upperClef: the clef to use on the upper staff
+  lowerName: the prefix to the lower staff name
+  lowerClef: the clef to use on the lower staff
+     vxname: the prefix to the name of voice x, x = 1..4
+     verses: the list of verse names containing the stanzas"
+
+    #{
+        <<
+          \make-two-voice-vocal-staff
+            #upperName #upperClef #v1name #v2name
+          #(make-simultaneous-music
+            (map
+             (lambda (verse-name)
+              #{ \make-one-stanza
+                   #upperName #v1name #v2name #verse-name #} )
+            verses))
+          \make-two-voice-vocal-staff
+            #lowerName #lowerClef #v3name #v4name
+        >>
+      #} )
+
diff --git a/ly/voice-tkit.ly b/ly/voice-tkit.ly
new file mode 100644 (file)
index 0000000..daeaae4
--- /dev/null
@@ -0,0 +1,16 @@
+%\version "2.19.19"
+
+\include "base-tkit.ly"
+
+make-voice =
+#(define-music-function (parser location name) (voice-prefix?)
+   (define music (make-id name "Music"))
+   (if music
+       #{
+         \new Voice = #(string-append name "Voice") <<
+           #(if KeepAlive KeepAlive)
+           #(if Time Time )
+           #music
+         >>
+       #} ))
+