Many thanks to David for his help, here and in another thread.

This all started with the differing preferences of singers of polyphony,
some preferring scores in original note values, and some wanting reduced
values.  Personally, I'll sing from anything, but I like to enter music
into lilypond using halved note values, for conciseness.

The end result is the code attached to this message[1].  Music entered
in halved note values can be printed in full, halved, or quartered
values by setting the reduction factor at line 6.  The original mensural
clefs, from a somewhat extended repertoire (see the mensSign function),
are printed at each change of mensuration, together with an indication
of the proportional tempo change (which is automatically reflected in
the midi output, thanks to the articulate.ly script of Peter Chubb).

There is no attempt to automate the correlation between the tempo change
and the new mensuration.

I hope the code is of use to others.  It uses a current version of
lilypond so I cannot submit it as a snippet (it's probably too long
anyway).  If you have a play with RF (line 6), TACTUS (line 8), and
\mensuration (lines 181, 186, 188) you'll soon get the idea.

-- Graham King
[1] the entire Credo from the Missa Rapum Meum by Baldrick.
\version "2.16.0"

\include "articulate.ly"

% Reduction Factor from original notation:
#(define RF 2) % 1 for note values of original MS, 2 for halved, 4 for 
quartered, etc.

#(define TACTUS 50) % initial tempo in beats/minute, used by 
tempoWholesPerMinute

% set the initial tempo here so that it has global scope.  
% It is first used in the midi score block:
    % (the first number after ly:make-moment is beats-per-minute,
    % with the tactus on the MS semibreve)
currentTempo = #(ly:make-moment TACTUS RF)
newTempo = #currentTempo % initialise for first call to mensuration function.
        
% define noteName association list (alist):
#(define noteName '((4 . "maxima.")
                    (6 . "maxima")
                    (8 . "longa.")
                    (12 . "longa")
                    (16 . "breve.")
                    (24 . "breve")
                    (32 . "1.")
                    (48 . "1")
                    (64 . "2.")
                    (96 . "2")
                    (128 . "4.")
                    (192 . "4")
                    (256 . "8.")
                    (384 . "8")
                    (512 . "16.")
                    (768 . "16")
                    (1024 . "32.")
                    (1536 . "32")
                    (2048 . "64.")
                    (3072 . "64")
                    (4096 . "128.")
                    (6144 . "128")))
% the list of inverted pairs: (("maxima" . 4) .....) :
#(define invNoteName (map (lambda(s) (cons(cdr s) (car s))) noteName))

#(define-markup-command (mensSign layout props text) (markup?)
  "Create the markup for an extended list of mensuration signs."
  % Grateful acknowledgment to David Kastrup for Scheme help.
  (interpret-markup layout props
    (if (string=? text "C")
      (markup (#:musicglyph "timesig.mensural44"))
    (if (string=? text "cutC")
      (markup (#:musicglyph "timesig.mensural22"))
    (if (string=? text "Cdot")
      (markup (#:musicglyph "timesig.mensural64"))
    (if (string=? text "cutCdot")
      (markup (#:musicglyph "timesig.mensural68"))
    (if (string=? text "O")
      (markup (#:musicglyph "timesig.mensural32"))
    (if (string=? text "cutO")
      (markup (#:musicglyph "timesig.mensural34"))
    (if (string=? text "cutOdot")
      (markup (#:musicglyph "timesig.mensural98"))
    (if (string=? text "revC")
      (markup (#:musicglyph "timesig.mensural24"))
    (if (string=? text "revCdot")
      (markup (#:musicglyph "timesig.mensural68alt"))
    (if (string=? text "C3/2")
      (markup (#:line ((markup (#:musicglyph "timesig.mensural44"))
                       (#:fontsize -4 #:column ("3" "2"))
      )))
    (if (string=? text "cutC3/2")
      (markup (#:line ((markup (#:musicglyph "timesig.mensural22"))
                       (#:fontsize -4 #:column ("3" "2"))
      )))
    (if (string=? text "C3")
      (markup (#:line ((markup (#:musicglyph "timesig.mensural44"))
                       (#:fontsize 0 #:raise -1 "3"))
      ))
    (if (string=? text "C2")
      (markup (#:line ((markup (#:musicglyph "timesig.mensural44"))
                       (#:fontsize 0 #:raise -1 "2"))
      ))
    (if (string=? text "O2")
      (markup (#:line ((markup (#:musicglyph "timesig.mensural32"))
                       (#:fontsize 0 #:raise -1 "2"))
      ))
    (if (string=? text "3")
      (markup (#:fontsize 0 #:raise -1 "3"))
    )))))))))))))))    
  )
)
                           
% Debugging: display a moment plus some text.
% Returns its moment argument so can be used in-line.
#(define (display-moment  text m)
  (display text)
  (display (list (ly:moment-main-numerator m) "/" (ly:moment-main-denominator 
m)))
  m
)

% mensuration function by GK.  Usage:
%    \mensuration "mensuralTimesig" oldNote newNote newTimeNum newTimeDenom
%    produces: X (old = new)
%              T
%    where X is the mensuralTimesig, T is the modern timesig.
%    oldNote and newNote are specified by name with RF==2, e.g. "breve" = "2"
% The current tempo (semibreves/minute) is stored in ac:currentTempo
% ac:tempoChange takes a fraction that evaluates to semibreves per minute.
    
mensuration = #(define-music-function (P L mensuralTimesig oldNote newNote 
                                       newTimeNum newTimeDenom currentTempo) 
                  (string? string? string? number? number? ly:moment?)
    (set! newTempo (ly:moment-mul currentTempo 
                                  (ly:make-moment (cdr (assoc oldNote 
invNoteName)) 
                                                  (cdr (assoc newNote 
invNoteName))
                                  )))

    #{  %#(ly:message mensuralTimesig) % example of debugging output 
        \once \override Score.RehearsalMark #'self-alignment-X = #LEFT
        \mark \markup {
            \concat {
                \mensSign #mensuralTimesig 
                " ("
                \smaller \general-align #Y #DOWN 
                    \note #(cdr (assoc (* (/ RF 2) 
                                          (cdr (assoc oldNote invNoteName))
                                       ) noteName
                                )
                           ) #1
                " = "
                \smaller \general-align #Y #DOWN 
                    \note #(cdr (assoc (* (/ RF 2) 
                                          (cdr (assoc newNote invNoteName))
                                       ) noteName
                                )
                           ) #1
                )
                %#(number->string(ly:moment-main-numerator newTempo)) 
                %"/" 
                %#(number->string(ly:moment-main-denominator newTempo))
            }
        }
        \time #(cons newTimeNum (* newTimeDenom (/ RF 2))) % 2/2
        #(ac:tempoChange newTempo) % requires articulate.ly
    #} 
)

% addtobarnumber function by Jakob Lund:
% (see lilypond-user mailing list 16 Jan 2011)
addtobarnumber = #(define-music-function (P L m) (integer?)
    #{
    \applyContext
    #(lambda (voice)
      (let ((staff (ly:context-property-where-defined voice 'currentBarNumber))
        (n (ly:context-property voice 'currentBarNumber)))
      (ly:context-set-property! staff 'currentBarNumber
      (+ m n)))) 
     #})

global = {
    \key c \major
    % see snippets repository (will be superseded in 2.18 (see mailing list)):
    \set tupletSpannerDuration = #(ly:make-moment 1 (* RF 1)) 
}



cantusMusic = \relative c' {
    % initial tempo is set in the midi block, below.
    \clef "treble"
    \time #(cons 3 (* 1 RF)) % 3/2
    \once \override Score.RehearsalMark #'break-align-symbols = 
#'(time-signature)
    \mark \markup { \mensSign "O" }
    \override DynamicText #'stencil = #point-stencil % Hide midi dynamics
    e2\p %dynamic for midi playback
    d4 c d2 ~ 
    \once \override Staff.TimeSignature #'break-visibility = #'#(#f #f #f)
    \time #(cons 6 (* 1 RF)) %6/2 % invisibly change this to accommodate longa
    d2 \once \override Voice.NoteHead #'style = #'neomensural
    e\longa*5/8 \fermata
    \addtobarnumber #1 % accommodate extra bar in other parts
    \bar "||" 
    \mensuration #"cutCdot" #"2" #"1" #2 #2 #newTempo
    g4 a g c 
    \once \set tupletSpannerDuration = #(ly:make-moment 1 (* RF 1))
    \times 2/3 { b4 a g f e d } c1
    \bar "||"
    \mensuration #"Cdot" #"1" #"2." #6 #4 #newTempo
    c'2 b4 c4. b8 g4 
    \mensuration #"O" #"2." #"2" #3 #2 #newTempo
    a f e g f2  
    \once \override Staff.TimeSignature #'break-visibility = #'#(#f #f #f)
    \time #(cons 6 (* 1 RF)) %6/2 % invisibly change this to accommodate longa
    e4 d4 \once \override Voice.NoteHead #'style = #'neomensural
    e\longa*5/8 \fermata
    \bar "||"
}

structure = {
    \context ChoirStaff
    \shiftDurations #(rationalize (inexact->exact (- (/ (log RF) (log 2)) 1)) 
1/10) #0
    <<
        \context Staff = cantus <<
            \set Staff.midiInstrument = "oboe" %"voice oohs"
            \context Voice = cantus \with {
                \remove "Note_heads_engraver"
                \consists "Completion_heads_engraver"
                \consists "Bar_number_engraver"  % *** Need to add this to top 
part only
            } 
            {   << 
                    \global \cantusMusic 
                >> 
            }
        >>
    >>
}

\score {
    \structure    
    \layout {
        \context {
            \Score
            % Move next two items to Staff context to allow polyrhythmic 
            % setting of maximas:
            \remove "Timing_translator"
            \remove "Default_bar_line_engraver"            
        }
        \context {
            \Staff 
            \consists "Timing_translator"
            \consists "Default_bar_line_engraver"
        }
    }
}

\score { % "midi" score
    \unfoldRepeats \articulate \structure
    \midi {
        \context {
            \Score
            % set the initial tempo:
            % (the first number after ly:make-moment is beats-per-minute,
            % with the tactus on the MS semibreve)
            tempoWholesPerMinute = #currentTempo
        }
    }
} % "midi" \score ends

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

Reply via email to