Jump to content

Easy Gregorian notation

From LilyPond wiki
Revision as of 22:50, 26 October 2025 by Jean Abou Samra (talk | contribs) (Import snippet from LSR)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This snippet shows a special notation for easy Gregorian music.

Definitions can be saved as "modernGregorian.ily" in order to be used as \include "modernGregorian.ily"

Syntax is:

\include "modernGregorian.ily"

...

\cadenzaOn \omit Stem 'note'... \melisma { \lst 'note' \mli 'note' \sli 'note' \tli 'note' }

where:

  • \lst goes for long stem
  • \mli goes for medium ligature
  • \sli goes for short ligature
  • \tli goes for teeny ligature

It also includes a simple ornament: 'note' -\tweak extra-offset #'(X . Y) \orn

Known issues:

  • "modernGregorian.ily" does not support midi output.
  • \melisma does not follow key signatures.

\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=973
% => http://lilypond.1069038.n5.nabble.com/kind-of-gregorian-moving-noteheads-tc170995.html
% => http://lilypond.1069038.n5.nabble.com/Hungarian-Gregorian-tc171130.html

%% Works with other sizes:
%#(set-global-staff-size 25)
%#(set-global-staff-size 16)

%%%%% Defs to be saved as "modernGregorian.ily" %%%%%%%%%

%%%% Defining new stem/ligatures:
% long stem
lst = #(define-music-function (mus)
     (ly:music?)
   #{
     \stemDown
     \undo\omit Stem
     \once\override Stem.length = #7
     \once\override Stem.X-extent = #'(.1 . 0)
     \once\override NoteHead.stem-attachment = #'(-1.5 . -.1)
     $mus
     \omit Stem
   #})

%long curved ligature
#(define (long-curved-ligature grob)
   (if (ly:stencil? (ly:stem::print grob))
     (let* ((stencil (ly:stem::print grob))
            (X-ext (ly:stencil-extent stencil X))
            (Y-ext (ly:stencil-extent stencil Y))
            (width (interval-length X-ext))
            (len (interval-length Y-ext)))
       (ly:stencil-translate
         (grob-interpret-markup grob
           (markup
             (#:path width
               (list (list (quote moveto) -0.7 -0.65)
                   (list (quote curveto) -1.2 -0.4 -1.1 -0.2 -0.9 0.5)
                   (list (quote curveto) -0.9 0.5 -0.4 2 -0.8 2.2)))))
         (cons 0 (interval-start Y-ext))))
     #f))

lli = #(define-music-function (mus)
     (ly:music?)
        #{
          \stemUp
          \undo\omit Stem
          \override Stem.stencil = #long-curved-ligature
          $mus
          \omit Stem
        #})

%medium curved ligature
#(define (medium-curved-ligature grob)
   (if (ly:stencil? (ly:stem::print grob))
     (let* ((stencil (ly:stem::print grob))
            (X-ext (ly:stencil-extent stencil X))
            (Y-ext (ly:stencil-extent stencil Y))
            (width (interval-length X-ext))
            (len (interval-length Y-ext)))
       (ly:stencil-translate
         (grob-interpret-markup grob
           (markup
             (#:path width
               (list (list (quote moveto) -0.7 -0.65)
                   (list (quote curveto) -1.2 -0.4 -1.1 -0.2 -0.9 0.5)
                   (list (quote curveto) -0.9 0.5 -0.4 1.9 -1.4 1.8)))))
         (cons 0 (interval-start Y-ext))))
     #f))

mli = #(define-music-function (mus)
     (ly:music?)
        #{
          \stemUp
          \undo\omit Stem
          \override Stem.stencil = #medium-curved-ligature
          $mus
          \omit Stem
        #})

%short curved ligature
#(define (short-curved-ligature grob)
   (if (ly:stencil? (ly:stem::print grob))
     (let* ((stencil (ly:stem::print grob))
            (X-ext (ly:stencil-extent stencil X))
            (Y-ext (ly:stencil-extent stencil Y))
            (width (interval-length X-ext))
            (len (interval-length Y-ext)))
       (ly:stencil-translate
         (grob-interpret-markup grob
           (markup
             (#:path width
               (list (list (quote moveto) -0.7 -0.65)
                   (list (quote curveto) -1.2 -0.4 -1.1 -0.2 -1 0.4)
                   (list (quote curveto) -1 0.4 -0.8 1.5 -1.4 1.3)))))
         (cons 0 (interval-start Y-ext))))
     #f))

sli = #(define-music-function (mus)
     (ly:music?)
        #{
          \stemUp
          \undo\omit Stem
          \override Stem.stencil = #short-curved-ligature
          $mus
          \omit Stem
        #})

%tiny curved ligature
#(define (tiny-curved-ligature grob)
   (if (ly:stencil? (ly:stem::print grob))
     (let* ((stencil (ly:stem::print grob))
            (X-ext (ly:stencil-extent stencil X))
            (Y-ext (ly:stencil-extent stencil Y))
            (width (interval-length X-ext))
            (len (interval-length Y-ext)))
       (ly:stencil-translate
         (grob-interpret-markup grob
           (markup
             (#:path width
               (list (list (quote moveto) -0.7 -0.65)
                   (list (quote curveto) -1.2 -0.4 -1.1 -0.1 -1 0.2)
                   (list (quote curveto) -1 0.2 -0.8 0.7 -1.4 0.6)))))
         (cons 0 (interval-start Y-ext))))
     #f))

tli = #(define-music-function (mus)
     (ly:music?)
        #{
          \stemUp
          \undo\omit Stem
          \override Stem.stencil = #tiny-curved-ligature
          $mus
          \omit Stem
        #})

%% Ornament function
orn = 
  -\tweak self-alignment-X #LEFT
  -\tweak Y-offset #0.5
  -\tweak X-offset #1
  -\tweak outside-staff-priority ##f
  -\markup
      \raise #-.3
      \scale #'(1 . .85)
      \rotate #90 
      \musicglyph "ties.lyric.short"

%% Left aligning lyric :
lal = \once\override LyricText.self-alignment-X = #LEFT

%% horizontal inside staff spacer 
space =
#(define-music-function
     (anzahl)
     (number?)
   #{
     \grace { \repeat unfold #anzahl s }
   #})

% Given some music that represents lyrics, add a prefix to the first
% lyric event.
% syntax is \versus { some lyrics }
% resp. \responsum { some lyrics }
#(define (add-prefix-to-lyrics prefix music)
   (let ((found? #f))
     (map-some-music
      (lambda (m)
	(if found? m
	    (and (music-is-of-type? m 'lyric-event)
		 (begin
		   (set! (ly:music-property m 'text)
			 (string-append prefix (ly:music-property m 'text)))
		   (set! found? #t)
		   m))))
      music)))
% Add unicode 2123 (versicle) as prefix to lyrics.
versus =
#(define-music-function (music) (ly:music?)
   (add-prefix-to-lyrics "℣. " music))
% Add unicode 211F (response) as prefix to lyrics.
responsum =
#(define-music-function (music) (ly:music?)
   (add-prefix-to-lyrics "℟. " music))

%% Defining notelaces (neume, melisma) and dedicated context:
gregorianContext = { 
  \cadenzaOn 
  \omit Clef
  \omit TimeSignature
  \omit StaffSymbol
  \omit Rest
  \omit Flag
  \omit Beam
  \override SpacingSpanner.packed-spacing = ##t
  \override NoteHead.stencil = 
    #(lambda (grob)
       (let ((pos (ly:grob-property grob 'staff-position)))
         (cond ((= pos -6)
             (grob-interpret-markup grob 
               #{
                  \markup
                  \concat { 
                    \with-dimensions #'(0 . 0) #'(0 . 0)
                    \translate-scaled #'(-.45 . 0)
                    \override #'(thickness . 2)
                    \draw-line #'(1.78 . 0)
                    \hspace #-.21 
                    \musicglyph "noteheads.s2" 
                    \hspace #-.25 
                  }
               #}))
           ((= pos -7)
               (grob-interpret-markup grob 
                 #{
                    \markup
                    \concat { 
                      \with-dimensions #'(0 . 0) #'(0 . 0) 
                      \override #'(thickness . 2) 
                      \translate-scaled #'(-.45 . .5)
                      \draw-line #'(1.78 . 0)
                      \hspace #-.21 
                      \musicglyph "noteheads.s2" 
                      \hspace #-.25 
                    }
                 #}))
           ((= pos -8)
               (grob-interpret-markup grob 
                 #{
                    \markup
                    \concat { 
                      \with-dimensions #'(0 . 0) #'(0 . 0) 
                      \override #'(thickness . 2) 
                      \translate-scaled #'(-.45 . 1)
                      \draw-line #'(1.78 . 0)
                      \with-dimensions #'(0 . 0) #'(0 . 0) 
                      \override #'(thickness . 2) 
                      \translate-scaled #'(-.45 . 0)
                      \draw-line #'(1.78 . 0)
                      \hspace #-.21 
                      \musicglyph "noteheads.s2" 
                      \hspace #-.25 
                    }
                  #}))
           (else
              (grob-interpret-markup grob 
                     #{
                        \markup
                        \concat { 
                          \hspace #-.21 
                          \musicglyph "noteheads.s2" 
                          \hspace #-.25 
                        }
                      #})))))
  \override Accidental.extra-offset = #'(-.2 . 0)
  %%% TODO: find a fixed ledger line with no dimension
  %% see: http://lilypond.1069038.n5.nabble.com/Fixed-ledger-line-width-with-no-dimension-tc172180.html 
  %\override LedgerLineSpanner.length-fraction = #'() %%% ???
  %\override LedgerLineSpanner.minimum-length-fraction = #'() %%% ???
}

neume = #(define-music-function (mus)
     (ly:music?)
   #{
     \once\override NoteHead.stencil = #(lambda (grob)
         (grob-interpret-markup grob 
           #{
              \markup\concat {
                \hspace #-2
                \score {
                  \transpose c c' { \omit Stem $mus } 
                  \layout {
                    indent = 0
                    ragged-right = ##t
                    \context {
                      \Score
                      \gregorianContext
                    }
                  }
                }
              }
           #}))
   #})

melisma = #(define-music-function (mus)
     (ly:music?)
     #{
        { 
          \once\override Lyrics.LyricText.self-alignment-X = #LEFT
          \neume { $mus } 
          \omit Accidental 
          \omit Dots
          #(make-music
            'NoteEvent
            'pitch
            (ly:make-pitch -1 6 0)
            'duration
            (ly:make-duration 2 0 1))
        }
     #})

% Declare default layout
\layout {
  \context {
    \Score
    \omit TimeSignature
  }
}

%%%%%%%%%%%% end of "modernGregorian.ily" %%%%%%%%%

%%%%%%%%%%% Example %%%%%%%%%%%%%%

%\include "modernGregorian.ily"

\header { tagline = ##f }

allelujaStandard = \transpose c c' {
  \clef G
  \key f\major
  \stemDown
  \omit Stem
  \repeat volta 2 {
    f f \undo\omit Stem <g a> a
    \once\override Staff.BarLine.bar-extent = #'(0 . 2) \bar "|"
    \omit Stem a g \undo\omit Stem <a \tweak extra-offset #'(2.3 . 0) g> 
    \once\override Stem.extra-offset = #'(-1.3 . -.5) <e f>
    \omit Stem g \undo\omit Stem 
    <f \tweak extra-offset #'(2.3 . 0) e> \omit Stem d d 
  }
}

allelujaModern = \transpose c c' {
  \clef G
  \key f\major
  \omit Stem
  \repeat volta 2 {
    f f \melisma {  g \lst a } a 
    \once\override Staff.BarLine.bar-extent = #'(0 . 2) \bar "|"
    a g \melisma { \lst a \tli g } \melisma { \lst e f }
    g \melisma { \lst f \tli e } d d
  }
}

allelujaLyrics = \lyricmode {
  \override LyricHyphen.minimum-distance = #5
  \override LyricSpace.minimum-distance = #5
  A -- le -- lu -- ja.
  \repeat unfold 2 { a -- le -- lu -- ja. }
}

\markuplist {
  \line { \italic "Some simple modern style Gregorian scores can be achieved using the standard" }
  \line { \italic "LilyPond notation although it uses a number of tweaks." }
  \vspace #1
}
\score {
  <<
    \cadenzaOn
    \new Voice = Alleluja \allelujaStandard
    \new Lyrics \lyricsto Alleluja \allelujaLyrics
  >>
  \layout {
    system-count = 1
    ragged-right = ##f
    \context {
      \Lyrics
      \override VerticalAxisGroup.staff-affinity = ##f
    }
  }
  \header {
     piece = \markup { 
      \lower #2.4 \fontsize #8 \bold "551" 
      \column {
        \bold "Alleluja"
        "(ÉE 432)"
      }
    }
  }
}

\markuplist {
  \italic "... but are much easier to code with 'modernGregorian.ily':"
  \vspace #1
}
\score {
  <<
    \cadenzaOn
    \new Voice = Alleluja \allelujaModern
    \new Lyrics \lyricsto Alleluja \allelujaLyrics
  >>
  \layout {
    system-count = 1
    ragged-right = ##f
    \context {
      \Lyrics
      \override VerticalAxisGroup.staff-affinity = ##f
    }
  }
  \header {
   piece = \markup { 
      \lower #2.4 \fontsize #8 \bold "551" 
      \column {
        \bold "Alleluja"
        "(ÉE 432)"
      }
    }
  }
}

zslotar = \transpose c c' {
  \clef G
  \omit Stem
  d d d \melisma { f g \lst a } g -\tweak extra-offset #'(1 . -1) \orn g \melisma { g a \lst c' } 
  a \melisma { \lst a \tli g a \lst c' \mli g \lst a \tli g \tli f }  
  \bar "'" 
  a c' \melisma { \lst c' \tli b \tli a } 
  \bar ""
}

zslotarLyrics = \lyricmode {
  \set stanza = \markup\box\pad-markup #.5 \bold "4b"
  Meg -- is -- mer -- tet -- ted
  vé -- lem, U -- ram az é -- let
}

\markuplist {
  \line { \italic "Now comes a heavier score with some complex neumes..." }
  \line { \italic "Not a problem at all for 'modernGregorian.ily':" }
  \vspace #1
}
\score {
  <<
    \cadenzaOn
    \new Voice = Zslotar \zslotar
    \new Lyrics \lyricsto Zslotar \zslotarLyrics
  >>
  \layout {
    ragged-right = ##f
    \context {
      \Lyrics
      \override VerticalAxisGroup.staff-affinity = ##f
    }
  }
  \header {
    piece = \markup\fontsize #4 { \bold "4b." \normal-text "XV. zsoltár" }
  }
}

sanctus = \transpose c c' {
  \clef G
  \key a\major
  \omit Stem
  \melisma { d \lst e } e 
  \bar "|"
  \melisma { 
    \lst e \sli c \lst d \tli c \tli b, r d \lst f \tli e 
  }
  \melisma { d \lst e } e
  \once\override Staff.BarLine.bar-extent = #'(0 . 2) \bar "|"
  \melisma { e \lst g r a \lst b } \melisma { \lst a \tli g \tli f \tli e }
  \melisma { 
    f \lst a \mli e \sli c \lst d \tli c \tli
    b, -\tweak extra-offset #'(1 . -2.5) \orn 
    r r \lst f \tli e f \lst g 
  } \melisma { \lst f \tli e }
  \bar "||"
}

sanctusLyrics = \lyricmode {
  mi -- ni.
  Ho -- sán -- na in ex -- cél -- sis.
}

\markuplist {
  \line { \italic "... even with ledger lines and neumes' ornament:" }
  \vspace #1
}
\score {
  <<
    \cadenzaOn
    \new Voice = Sanctus \sanctus
    \new Lyrics \lyricsto Sanctus \sanctusLyrics
  >>
  \layout {
    ragged-right = ##f
    \context {
      \Lyrics
      \override VerticalAxisGroup.staff-affinity = ##f
    }
  }
  \header {
    piece = \markup { 
      \fontsize #8 \bold "601" 
      \fontsize #2 
      \raise #2.1 {
        \bold "Sanctus"
        \italic "(GrR VI. mise)"
      }
    }
  }
}

\markup\vspace #2