Two useful Scheme functions: music-find and music-flatten

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!