\version "2.19.13" % work on v2.19.12 but failes with v2.19.13 \language "english" \header { title = "快樂頌" subtitle = "Joyful, Joyful, We Adore Three" % Remove default LilyPond tagline %tagline = ##f } \paper { #(set-paper-size "letter") } #(set-global-staff-size 22) global = { \key g \major \time 4/4 \tempo 4=120 } %\include "include_solfege-engraver.ly" #(define syllables '("do" "re" "mi" "fa" "so" "la" "ti")) #(define sylsⓓ '("ⓓ" "ⓡ" "ⓜ" "ⓕ" "ⓢ" "ⓛ" "ⓣ")) #(define numR➀ '("➀" "➁" "➂" "➃" "➄" "➅" "➆")) #(define number '("1" "2" "3" "4" "5" "6" "7")) #(define numR➑ '("➊" "➋" "➌" "➍" "➎" "➏" "➐")) #(define (solfege-engraver lst dir) (make-engraver (acknowledgers ((note-head-interface engraver grob source) (let* ( (context (ly:translator-context engraver)) (tonic-pitch (ly:context-property context 'tonic)) (tonic-index (ly:pitch-notename tonic-pitch)) (event (ly:grob-property grob 'cause)) (event-copy (ly:event-deep-copy event)) (grob-pitch (ly:event-property event 'pitch)) (grob-index (ly:pitch-notename grob-pitch)) (delta (modulo (- grob-index tonic-index) 7)) (name (list-ref lst delta)) (newgrob (ly:engraver-make-grob engraver 'TextScript event-copy))) ;; clear 'tweaks for newgrob ;; (ly:event-set-property! event-copy 'tweaks '()) (if (string= name "Hb") (set! name "B")) ;; Give newgrob 'outside-staff-priority depending on ;; grob 'staff-position (set! (ly:grob-property newgrob 'outside-staff-priority) (+ (ly:grob-property newgrob 'outside-staff-priority) (* dir (ly:grob-property grob 'staff-position)))) (set! (ly:grob-property newgrob 'text) name) (set! (ly:grob-property newgrob 'direction) dir) ))))) xup = \with { \consists #(solfege-engraver syllables UP) } xdown = \with { \consists #(solfege-engraver syllables DOWN) } zup= \with { \consists #(solfege-engraver sylsⓓ UP) } zdown= \with { \consists #(solfege-engraver sylsⓓ DOWN) } nup= \with { \consists #(solfege-engraver number UP) } ndown= \with { \consists #(solfege-engraver number DOWN) } rup= \with { \consists #(solfege-engraver numR➀ UP) } rdown= \with { \consists #(solfege-engraver numR➀ DOWN) } sup= \with { \consists #(solfege-engraver numR➑ UP) } sdown= \with { \consists #(solfege-engraver numR➑ DOWN) } %end of \include "include_solfege-engraver.ly" verse = \lyricmode { 哈 利 路 亞! 哈 利 路 亞! 哈 利 路 亞! 喜 樂 源 頭, 賜 人 安 息 最 佳 美. 哈 哈 利 路 亞! 哈 利 路 亞! 求 教 我 們, 相 愛 相 親, 同 享 屬 神 大 歡 欣. } %\include "include_extract-music.ly" %% LSR = http://lsr.dsi.unimi.it/LSR/Item?u=1&id=761 %% LSR = http://lsr.dsi.unimi.it/LSR/Item?u=1&id=545 %% for Lilypond 2.18 or higher. %% version 2013/04/16 : last change = replace chord-elts->note %% by chord->note. You can now specified several numbers, to %% extract several notes at one time #(define (noteEvent? music) (eq? (ly:music-property music 'name) 'NoteEvent)) #(define (no-duration? music) (not (ly:duration? (ly:music-property music 'duration)))) #(define (expand-q-chords music); for q chords : see chord-repetition-init.ly (expand-repeat-chords! (list 'rhythmic-event) music)) %%%%%%%%%%%%%%%%%%%%%%%%%% extractNote %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #(define tagNotExtractNote (gensym)) #(use-modules (ice-9 receive)) %% for the use of receive #(define (chord->note chord n . args) "Return the note n of one chord, keeping articulations. Other numbers can be specified in args" (receive (notes others) (partition noteEvent? (ly:music-property chord 'elements)) (if (null? notes) chord (let* ((len (length notes)) (res (filter-map (lambda(i) (and (integer? i) (<= i len) (> i 0) (list-ref notes (1- i)))) ; list-ref is zero-based (cons n args))) (one-note (cond ((null? res) (list-ref notes (1- len))) ((null? (cdr res))(car res)) (else #f)))) (if one-note (begin (ly:music-set-property! one-note 'articulations (append (ly:music-property one-note 'articulations) others)) one-note) (make-event-chord (append res others))))))) #(define (extract-note music n . args) "Extract the note n of each chords in music, keeping articulations. If other numbers are given in args, the function returns a chord build with all matching notes. If no note matches, returns the last note of the chord." (map-some-music (lambda (evt) (cond ((eq? 'EventChord (ly:music-property evt 'name)) (let ((tags (ly:music-property evt 'tags))) (if (memq tagNotExtractNote tags) (ly:music-set-property! evt 'tags ; only remove the tag (delq tagNotExtractNote tags)) (set! evt (apply chord->note evt n args))) evt)) (else (and (ly:music-property evt 'duration #f) evt)))) (expand-q-chords music))) %% TO DO : add a parameter optional pred? extractNote = #(define-music-function (parser location n music ) (number? ly:music?) (extract-note music n)) % usefull for notExtractNote tagify = #(define-music-function (parser location tag music)(symbol? ly:music?) "Add `tag in the tags property of all chords" (music-map (lambda (evt) (if (eq? 'EventChord (ly:music-property evt 'name)) (ly:music-set-property! evt 'tags (cons tag (ly:music-property evt 'tags)))) evt) music)) notExtractNote = #(define-music-function (parser location music)(ly:music?) "Avoids music to be extracted by \\extractNote." #{ \tagify #tagNotExtractNote $music #}) %%%%%%%%%%%%%%%%%%%%%%%%%% extractVoice %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #(define tagNotExtractVoice (gensym)) #(define (get-voice voices n) (let ((len (length voices))) (list-ref voices (1- ; list-ref is zero-based ! (if (and (<= n len)(> n 0)) n len))))) #(define (extract-voice music n) (let loop ((evt music)) (if (no-duration? evt) ; see chord.ly ; notes, rests multi-rests (let ((e (ly:music-property evt 'element)) (es (ly:music-property evt 'elements))) (if (ly:music? e)(ly:music-set-property! evt 'element (loop e))) (if (pair? es) (case (ly:music-property evt 'name) ((EventChord) evt) ((SimultaneousMusic) (let ((tags (ly:music-property evt 'tags))) (if (memq tagNotExtractVoice tags) (ly:music-set-property! evt 'tags ; only remove the tag (delq tagNotExtractVoice tags)) (let ((res (map loop (filter (lambda(x) (not (eq? (ly:music-property x 'name) 'VoiceSeparator))) es)))) (if (pair? res)(set! evt (music-filter (lambda (x) (let((name (ly:music-property x 'name))) (or (not (memq name '(OverrideProperty PropertySet))) (begin (if (eq? name 'ContextSpeccedMusic) (set! x (ly:music-property x 'element))) x)))) (get-voice res n)))))))) (else (ly:music-set-property! evt 'elements (map loop es))))))) evt)) extractVoice = #(define-music-function (parser location n music ) (integer? ly:music?) (extract-voice music n)) notExtractVoice = #(define-music-function (parser location music)(ly:music?) "Inside an \\extractVoice section, avoids that a part of this section (called here `music) to be extracted." #{ \tag #tagNotExtractVoice $music #}) %%%%%%%%%%%%%%%%%%%%%%%%%%%%% derivated functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% If you have enter << \\ >>, the first function will %% give you c, the second fis extractPartUpper = #(define-music-function (parser location music )(ly:music?) #{ \extractNote #1000 \extractVoice #1 $music #}) extractPartLower = #(define-music-function (parser location music )(ly:music?) #{ \extractNote #1 \extractVoice #1000 $music #}) %%%%%% shortcuts %%%%%%% #(define ePU extractPartUpper) #(define ePL extractPartLower) %%%%%%%%%%%%%%%%%%%%% addNote #(define (add-note music notes-to-add) ; notes-to-add as music (define (note->chords-arti note) ; note as a NoteEvent (receive (note-arti chord-arti) (partition ; separates arti for NoteEvent from arti for EventChord (lambda (evt)(memq (ly:music-property evt 'name) (list 'StringNumberEvent 'StrokeFingerEvent 'FingeringEvent))) (ly:music-property note 'articulations)) (ly:music-set-property! note 'articulations note-arti) chord-arti)) (let* ((alist ; a list of pairs of 2 lists : '(notes . articulations) (reverse (let loop ((m (expand-q-chords notes-to-add)) ; q to chords (p '())) ; m = music, p previous value of the list (case (ly:music-property m 'name) ((or SkipEvent SkipMusic) ; a skip in notes-to-add means : add nothing (cons #f p)) ; add #f to the list ((NoteEvent) (acons (list m) (note->chords-arti m) p)) ((EventChord) (receive (notes arti) ; separates notes from scripts, dynamics etc (partition noteEvent? (ly:music-property m 'elements)) (if (pair? notes)(acons notes arti p) p))) (else (let ((e (ly:music-property m 'element))) (fold loop (if (ly:music? e)(loop e p) p) (ly:music-property m 'elements)))))))) (entry #f) ; will be (car alist) (entry? (lambda() (and (pair? alist) (begin (set! entry (car alist)) (set! alist (cdr alist)) entry)))) (do-add (lambda (notes arti) (let* ((dur (ly:music-property (car notes) 'duration)) (new-notes (map ; fix all durations to dur (lambda(evt)(ly:music-set-property! evt 'duration dur) evt) (car entry))) ; the list of new notes (new-arti (cdr entry))) ; the articulations (append new-notes notes new-arti arti))))) ;; combine in chords, each element of alist with notes of music (map-some-music (lambda(x) (case (ly:music-property x 'name) ((NoteEvent)(if (entry?) (make-event-chord (do-add (list x) (note->chords-arti x))) x)) ((EventChord) (if (entry?)(receive (notes arti) ; separates notes from scripts, dynamics etc (partition noteEvent? (ly:music-property x 'elements)) (if (pair? notes)(ly:music-set-property! x 'elements (do-add notes arti))))) x) (else (and (ly:music-property x 'duration #f) x)))) ; #f means : go deeper (expand-q-chords music)))) addNote = #(define-music-function (parser location music notes) (ly:music? ly:music?) (add-note #{\relative c' $music #} ; the 2 music-parameters will #{\relative c' $notes #})) % be seen in \relative mode %%%%%%%%%%%%%%%%%%%% addVoice addVoice = #(define-music-function (parser location music newVoice) (ly:music? ly:music?) ;; #{ ;; << ;; { \voiceOne $music } ;; \new Voice { \voiceTwo $newVoice } ;; >> ;; \oneVoice ;;#}) #{ << $music \\ $newVoice >> #}) addVoiceReverse = #(define-music-function (parser location music newVoice) (ly:music? ly:music?) #{ << { \voiceOne $newVoice } \new Voice { \voiceTwo $music } >> \oneVoice #}) %%%%%%%%%%%%%%%%%%%% deleteDynamics = #(define-music-function (parser location music) (ly:music?) (music-filter (lambda (evt) (not (memq (ly:music-property evt 'name) (list 'AbsoluteDynamicEvent 'CrescendoEvent 'DecrescendoEvent)))) music)) %%%%%%%%%%%%%%%%%%%%%%%% absolute = #(define-music-function (parser location music) (ly:music?) "A \\relative command will have no effect in the resulting music." (make-music 'UnrelativableMusic 'element music)) doubleNote = #(define-music-function (parser location music) (ly:music?) "Double each note with the note an octave higher." #{ \addNote \transpose c c' \relative c' { $music } $music #}) %%%%%%%%%%%%%%%%%%%%%%%% doubleDur = #(define-music-function (parser location music)(ly:music?) (music-filter (lambda (evt) (let ((dur (ly:music-property evt 'duration))) (if (ly:duration? dur) (ly:music-set-property! evt 'duration (ly:make-duration (1-(ly:duration-log dur)) (ly:duration-dot-count dur)))) #t)) music)) halfDur = #(define-music-function (parser location music)(ly:music?) (music-filter (lambda (evt) (let ((dur (ly:music-property evt 'duration))) (if (ly:duration? dur) (ly:music-set-property! evt 'duration (ly:make-duration (1+ (ly:duration-log dur)) (ly:duration-dot-count dur)))) #t)) music)) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %end of \include "include_extract-music.ly" SA = { \global 4 4 4 4 |%m01 % 4 <<{c''4}\\{e'8 fs'8}>> 4 4 |%m02 % 4 4 4 4 |\break %m03 % 4. 8 2 |%m04 % 4 4 4 4 |%m05 % 4 4 4 4 |\break %06 % 4 4 4 4 |%m07 % 4. g'8 2 |%m08 % 4 4 4 g'4 |\break %m09 % 4 8( 8) 4 g'4 |%m10 % 4 <<{b'8( c''8)}\\{fs'4}>> 4 4 |%m11 % <<{g'4}\\{e'8 d'8}>> 4 d'2 |\break %m12 % 4 4 4 4 |%m13 % 4 4 4 4 |%m14 % 4 4 4 4 |%m15 % 4. g'8 2 |%m16 \bar"|." \label #'lastPage } soprano = { \ePU \SA } alto = { \ePL \SA } verseOne = \lyricmode { \set fontSize = #3.0 \set stanza = "1." 快 樂, 快 樂, 我 們 崇 拜, 榮 耀 慈 愛 大 主 宰; 奉 獻 心 靈 在 主 面 前, 如 同 花 朵 向 日 開. 愁 霧, 疑 雲, 罪 悪, 憂 驚, 懇 求 救 主 消 除 盡, 萬 福 之 源, 永 樂 之 主 賜 下 光 明 滿 我 心. } choirPart = \new ChoirStaff << \new Staff \with { %midiInstrument = "choir aahs" instrumentName = \markup \center-column { "S." "A." } shortInstrumentName = \markup \center-column { "S." "A." } } << %\SA \set Staff.printPartCombineTexts = ##f \partcombine << \soprano>> <<\alto>> \new NullVoice = "soprano" %\rup %comment this line for not using solfege-engravers - works on both version % with the above line, v2.19.12 ok; falis with v2.19.12 { \voiceOne \soprano } \new NullVoice = "alto" { \voiceTwo \alto } %\new Voice = "soprano" { \voiceOne \soprano } %\new Voice = "alto" { \voiceTwo \alto } >> \new Lyrics \with { \override VerticalAxisGroup #'staff-affinity = #CENTER } \lyricsto "soprano" \verseOne >> \score { << \choirPart >> \layout { } \midi { } } %{ convert-ly.py (GNU LilyPond) 2.19.13 convert-ly.py: Processing `'... Applying conversion: The document has not been changed. %}