From 14261eabcc7e9e653ee166b86f0371219fa0c54c Mon Sep 17 00:00:00 2001 From: Trevor Daniels Date: Sat, 18 Apr 2015 16:28:55 +0100 Subject: [PATCH] Issue 3799: New satb.ly built-in template and template framework 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 --- Documentation/learning/templates.itely | 4 +- ...satb-template-on-two-staves-with-verses.ly | 28 ++ ...mplate-soprano-and-tenor-may-be-omitted.ly | 19 ++ ...-template-with-changed-instrument-names.ly | 38 +++ ...atb-template-with-men-women-and-descant.ly | 34 ++ ly/base-tkit.ly | 117 +++++++ ly/lyrics-tkit.ly | 50 +++ ly/piano-tkit.ly | 45 +++ ly/satb.ly | 299 +++++++----------- ly/staff-tkit.ly | 178 +++++++++++ ly/vocal-tkit.ly | 90 ++++++ ly/voice-tkit.ly | 16 + 12 files changed, 729 insertions(+), 189 deletions(-) create mode 100644 input/regression/satb-template-on-two-staves-with-verses.ly create mode 100644 input/regression/satb-template-soprano-and-tenor-may-be-omitted.ly create mode 100644 input/regression/satb-template-with-changed-instrument-names.ly create mode 100644 input/regression/satb-template-with-men-women-and-descant.ly create mode 100644 ly/base-tkit.ly create mode 100644 ly/lyrics-tkit.ly create mode 100644 ly/piano-tkit.ly create mode 100644 ly/staff-tkit.ly create mode 100644 ly/vocal-tkit.ly create mode 100644 ly/voice-tkit.ly diff --git a/Documentation/learning/templates.itely b/Documentation/learning/templates.itely index cc35e50da7..1fd7b7b466 100644 --- a/Documentation/learning/templates.itely +++ b/Documentation/learning/templates.itely @@ -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 index 0000000000..43055b7d91 --- /dev/null +++ b/input/regression/satb-template-on-two-staves-with-verses.ly @@ -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 index 0000000000..cfce5eeb97 --- /dev/null +++ b/input/regression/satb-template-soprano-and-tenor-may-be-omitted.ly @@ -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 index 0000000000..cea70c0c91 --- /dev/null +++ b/input/regression/satb-template-with-changed-instrument-names.ly @@ -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 index 0000000000..c8ff7d3aef --- /dev/null +++ b/input/regression/satb-template-with-men-women-and-descant.ly @@ -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 index 0000000000..6061475acc --- /dev/null +++ b/ly/base-tkit.ly @@ -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> + #} + (make-music 'SequentialMusic 'void #t))) diff --git a/ly/satb.ly b/ly/satb.ly index a8ae1347ac..df57811e48 100644 --- a/ly/satb.ly +++ b/ly/satb.ly @@ -1,4 +1,4 @@ -%\version "2.19.17" +%\version "2.19.19" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% @@ -12,9 +12,11 @@ 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 @@ -29,12 +31,12 @@ \paper { ... } \header { ... } - TwoVoicesPerStaff = ##f or ##t Key = { ... } Time = { ... } - Layout = \layout { ... } DescantMusic = \relative { ... } DescantLyrics = \lyricmode { ... } + WomenMusic = \relative { ... } + WomenLyrics = \lyricmode { ... } SopranoMusic = \relative { ... } SopranoLyrics = \lyricmode { ... } AltoMusic = \relative { ... } @@ -47,214 +49,137 @@ 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 index 0000000000..a0f827a5c4 --- /dev/null +++ b/ly/staff-tkit.ly @@ -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 index 0000000000..cad4ea4b53 --- /dev/null +++ b/ly/vocal-tkit.ly @@ -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 index 0000000000..daeaae4f69 --- /dev/null +++ b/ly/voice-tkit.ly @@ -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 + >> + #} )) + -- 2.39.2