]> 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 }
 
 @lilypond[verbatim, quote]
   SopranoMusic = \relative { a'4 a a a }
-  SopranoLyricsOne = \lyricsto "Soprano" {
+  SopranoLyricsOne = \lyricmode {
     \set stanza = "1."
     Words to verse one
   }
     \set stanza = "1."
     Words to verse one
   }
-  SopranoLyricsTwo = \lyricsto "Soprano" {
+  SopranoLyricsTwo = \lyricmode {
     \set stanza = "2."
     Words to verse two
   }
     \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
   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)
   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
   Piano Staff
 
   It is intended primarily to hide the complexity of the context
 
   \paper { ... }
   \header { ... }
 
   \paper { ... }
   \header { ... }
-  TwoVoicesPerStaff = ##f or ##t
   Key = { ... }
   Time = { ... }
   Key = { ... }
   Time = { ... }
-  Layout = \layout { ... }
   DescantMusic = \relative { ... }
   DescantLyrics = \lyricmode { ... }
   DescantMusic = \relative { ... }
   DescantLyrics = \lyricmode { ... }
+  WomenMusic = \relative { ... }
+  WomenLyrics = \lyricmode { ... }
   SopranoMusic = \relative { ... }
   SopranoLyrics = \lyricmode { ... }
   AltoMusic = \relative { ... }
   SopranoMusic = \relative { ... }
   SopranoLyrics = \lyricmode { ... }
   AltoMusic = \relative { ... }
   TenorLyrics = \lyricmode { ... }
   BassMusic = \relative { ... }
   BassLyrics = \lyricmode { ... }
   TenorLyrics = \lyricmode { ... }
   BassMusic = \relative { ... }
   BassLyrics = \lyricmode { ... }
+  MenMusic = \relative { ... }
+  MenLyrics = \lyricmode { ... }
   PianoRHMusic = \relative { ... }
   PianoDynamics = { ... }
   PianoLHMusic = \relative { ... }
   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.
 
   \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.
 
 %}
 
 
   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
   }
   <<
   \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 {
 
 \tagGroup #'(print play)
 
 \score {
-  \keepWithTag #'print \SATB
-  \layout { $(satb-defaulting Layout) }
+  \keepWithTag #'print
+  #(if have-music
+       #{ << \SATB \Piano >> #}
+       #{ { } #} )
+  \layout { $(if Layout #{ \Layout #} ) }
 }
 
 }
 
+
 \score {
 \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
+         >>
+       #} ))
+