Adding articulations from a template
Appearance
Repeating the same articulations a great number of time can be a bit time-consuming to enter.
The function copyArticulations here, automates the job by copying the articulations from a pattern into your music.
As the music is rarely always the same, a few extra functions can give you some flexibility.
The code of the image below is the following:
\copyArticulations
{ c( c) c-. c-. } %% the pattern
{ %% the music
c16 d e f g a b c b8 a g f
\notCA e1
\nSkipArti #2
r8 d16 e f g a b c8 g e g
\notCA c,1
}
Here, \notCA allows you to keep the music untouched and \nSkipArti #2 skips 2 notes (so 2 articulations) in the pattern.
Download the code of this function here : copyArticulations.ly.
\version "2.24.0"
%% http://lsr.di.unimi.it/LSR/Item?id=769
%% version 2013/04/14 for lilypond 2.16 or higher
%% last changes :
%% - fix a bug for \notCopyArticulations and q chords (has-notes? must
%% be called)
#(use-modules (ice-9 receive)) %% for the use of receive
#(define skipCurrentArticulationTag (gensym))
#(define notCopyArticulationsTag (gensym))
#(define (defined-music? music)
(not (eq? 'Music (ly:music-property music 'name))))
#(define (name-of music)
(ly:music-property music 'name))
#(define (noteEvent? music)
(eq? (name-of music) 'NoteEvent))
#(define (has-notes? music)
"Return true if there is at least one note in `music, false otherwise."
(or (noteEvent? music)
(let ((e (ly:music-property music 'element)))
(and (ly:music? e)
(has-notes? e)))
(let loop ((es (ly:music-property music 'elements)))
(and (pair? es)
(or (has-notes? (car es))
(loop (cdr es)))))))
#(define (make-arti-list pattern)
"Make a list of articulations "
(let ((res '())) ; the list to fill
(for-some-music ; see music-functions.scm
(lambda (evt)
(case (name-of evt)
((EventChord)
(receive (notes others)
(partition noteEvent? (ly:music-property evt 'elements))
(if (pair? notes)
(set! res (cons others res)))))
; keeps only not note events
((NoteEvent)
(set! res (cons (ly:music-property evt 'articulations) res)))
(else #f)))
pattern)
(reverse res)))
%% use (ly:music-deep-copy music) for a direct use of copy-articulations
#(define (copy-articulations pattern music)
"Copy articulations of `pattern recursively in each notes of music."
(if (not (has-notes? pattern)) ; avoid endless loops ...
music
(let* ((new-arti (make-arti-list pattern))
(pointer-list new-arti)
(current-arti (lambda ()
(let ((res (car pointer-list)))
(set! pointer-list (cdr pointer-list))
(if (null? pointer-list)(set! pointer-list new-arti))
res))))
(music-filter
defined-music? ; deletes all (make-music 'Music)
(map-some-music ; see music-functions.scm
(lambda(evt)
(let ((tags (ly:music-property evt 'tags)))
(cond
((memq skipCurrentArticulationTag tags); yes => evt = <>
(current-arti) ; ignores return
(make-music 'Music)) ; will be deleted...
((memq notCopyArticulationsTag tags)
(ly:music-set-property! evt 'tags ; just remove the tag
(delq notCopyArticulationsTag tags))
evt)
((noteEvent? evt)
(let ((arti (ly:music-property evt 'articulations)))
(ly:music-set-property! evt 'articulations
(append arti (current-arti)))
evt))
((eq? 'EventChord (name-of evt))
(let ((elts (ly:music-property evt 'elements)))
(and
(pair? (filter noteEvent? elts))
(begin
(ly:music-set-property! evt 'elements
(append elts (current-arti)))
evt))))
(else (and (ly:music-property evt 'duration #f)
evt)))))
(expand-repeat-chords! (list 'rhythmic-event) music))))))
copyArticulations = #(define-music-function (pattern music)
(ly:music? ly:music?)
"Copy articulations of `pattern recursively in each notes of music."
(copy-articulations pattern music))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% enhancement functions, working inside the music parameter
%% of \copyArticulations
%%%%%%%
notCopyArticulations =
#(define-music-function (music)(ly:music?)
"Add a special tag in 'tags of all notes and chords, that will forbid
articulations to be copied to these events."
(map-some-music
(lambda(evt)
(cond ((memq (name-of evt) '(NoteEvent EventChord))
(ly:music-set-property! evt 'tags (cons
notCopyArticulationsTag (ly:music-property evt 'tags)))
evt)
(else #f))) ; go deeper
music))
skipArti = \tag #skipCurrentArticulationTag <>
nSkipArti = #(define-music-function (n)(integer?)
"Return \\skipArti \\skipArti \\skipArti ... n times."
(if (< n 2)
skipArti
(make-sequential-music (make-list n skipArti))))
skipTiedNotes = #(define-music-function (music)(ly:music?)
"Add a special tag in 'tags of second tied notes to forbid articulations to be
copied."
(let ((prev-was-tied #f))
(map-some-music
(lambda(evt)
(let ((name (name-of evt)))
(cond
((or (eq? name 'NoteEvent)
(and (eq? name 'EventChord)
(has-notes? evt)))
(if prev-was-tied (ly:music-set-property! evt 'tags
(cons notCopyArticulationsTag (ly:music-property evt 'tags))))
(map-some-music
(lambda(x)
(set! prev-was-tied (and (eq? (name-of x) 'TieEvent) x))
prev-was-tied) ; stop if true
evt))
(else #f))))
music)))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% shortcuts %%
artiI = c-. % default values for artiI and artiII, if the user does
artiII = {c( c) c-. c-.} % not define them, before using \cAI and \cAII
cAI = #(define-music-function (music) (ly:music?)
#{ \copyArticulations \artiI $music #})
cAII = #(define-music-function (music) (ly:music?)
#{ \copyArticulations \artiII $music #})
#(define cA copyArticulations)
#(define notCA notCopyArticulations)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\new Voice \relative c' {
\copyArticulations { c( c) c-. c-. }
{
c16 d e f g a b c b8 a g f
\notCA e1
\nSkipArti #2
r8 d16 e f g a b c8 g e g
\notCA c,1
}
}