During my continuing and frustrating quest to simplify my edition–making process, I have been constructing a large number of extensions and macros. So many in fact that I’ve had to start portioning them off into appropriate files. The header of my code has gone from:
\include "extensions.ly"
To:
\include "extension_stanza.ly"
\include "extension_timeshift.ly"
\include "extension_taggedengravers.ly"
\include "extension_simpleligature.ly"
\include "extension_mensurstriche.ly"
\include "extension_linesandclefs.ly"
\include "extension_plica.ly"
\include "extension_barline.ly"
\include "extension_divisiones.ly"
\include "extension_dynamicrest.ly"
In the “simple ligatures” extension, I have a function, \peflex
which maps through the music given to it, starting it all with an open ligature and then turning each notehead to a pes for ligatures (n.b. if you look in the “gregorian.ly” source, you'll find that \pes
and \flexa
are actually aliased). It finishes off with a close ligature, creating a full ligature from a simple set of notes. Instead of laboriously typing:
\relative c' { \[ \pes a4 \pes b \pes c \pes d \pes e1 \] }
I can simply do:
\relative c' { \peflex { a4 b c d e1 } }
I have another extension, “dynamic rest” that has a function \takerest
when given a note and a duration smaller than the duration of the note can automatically replace the note with another note such that new note = note - rest
and append the rest. This can be programmed to only act when enabled in the main configuration. However these two extensions conflict. Consider this:
\relative c' { \peflex { a4 b c d \takerest e1 4 } }
This expands to:
\relative c' { \[ \pes a4 \pes b \pes c \pes d \pes e1 \pes r4 \] }
Which causes the ligature bracket to expand over the rest which is not correct. I really want:
\relative c' { \[ \pes a4 \pes b \pes c \pes d \pes e1 \] r4 }
To do this I need to find when mapping through the music whether there is a rest, and if so, put the ligature bracket just before it. This is where music-find
comes in:
(define music-find
(lambda (pred mus)
(let*
(
(e (if (ly:music? mus) (ly:music-property mus 'element '()) '()))
(es (if (ly:music? mus) (ly:music-property mus 'elements '()) '()))
(ls (if (list? mus) mus '()))
(tls (if (not (null? e)) (cons e '()) '()))
(tls (if (not (null? es)) (append es tls) tls))
(tls (if (not (null? ls)) (append ls tls) tls))
)
(or
(if
(and
(ly:music? mus)
(pred mus)
)
mus
#f
)
(if
(and
(not (null? tls))
(not (null? (car tls)))
(ly:music? (car tls))
(pred (car tls))
)
(car tls)
#f
)
(and
(not (null? tls))
(music-find pred (cdr tls))
)
)
)
)
)
This function replicates the Scheme function (find pred lst)
on music instead of lists and returns the first element that satisfies pred
or false. Now I can find whether there is a rest. Unfortunately, with all my functions, I use Lilypond code blocks quite considerably (#{
and #}
) which generates a lot of nested (make-music 'SequentialMusic 'elements (list …))
. This causes the Lilypond compiler to fail to find my closing ligature bracket as it’s on a completely different level of nested music statements. It also looks ugly when I’m examining the internal Scheme code. music-flatten
folds through the music and recursively flattens any SequentialMusic
elements that have direct SequentialMusic
children:
(define music-flatten
(lambda (mus)
"Convert nested sequential musics into single sequential musics"
(fold
(lambda (e prv)
(if
(not (music-is-of-type? e 'sequential-music))
(append prv (list e))
(append prv (music-flatten (ly:music-property e 'elements)))
)
)
'()
mus
)
)
)
Happy Scheming!