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