Jump to content

Persistent accidentals

From LilyPond wiki

Tired of having to remember where flats and sharps are supposed to go in your scores? Here's a solution: all accidentals are remembered and applied to subsequent natural pitches, until a natural gets forced.

This snippet shows two methods of achieving that: by using a music function, or with a Scheme engraver.

\version "2.24.0"

%% Contributed by V.V. on
%% https://lists.gnu.org/archive/html/lilypond-user/2020-05/msg00125.html

someMusic = \relative c' {
  c des e fis g f e f! e d' g, d
}

%% Method 0: using a music function

persistentAccidentals =
#(define-music-function (music) (ly:music?)
   (let ((alt-alist '())
         (m (ly:music-deep-copy music)))
     (music-map
      (lambda (note)
        (let ((pitch (ly:music-property note 'pitch))
              (force? (ly:music-property note 'force-accidental)))
          (if (ly:pitch? pitch)
              (let* ((alt (ly:pitch-alteration pitch))
                     (n (ly:pitch-notename pitch))
                     (o (ly:pitch-octave pitch))
                     (mem-alt (assoc-get n alt-alist)))
                (if (eq? force? #t)
                    (set! alt-alist
                          (assoc-remove! alt-alist n))

                    (if (= alt 0)
                        (if mem-alt
                            (ly:music-set-property!
                             note 'pitch
                             (ly:make-pitch o n mem-alt)))
                        (set! alt-alist
                              (assoc-set! alt-alist n alt))))))
          note))
      m)
     m))

\persistentAccidentals \someMusic

%% Method 1: using a Scheme engraver.

#(define Persistent_accidentals_translator
   (lambda (context)
     (let ((alt-alist '()))
       (make-engraver
        (listeners
         ((note-event engraver event)
          (let ((note (ly:prob-property event 'music-cause)))
            (if (ly:music? note)
                (let ((pitch (ly:music-property note 'pitch))
                      (force? (ly:music-property note 'force-accidental)))
                  (if (ly:pitch? pitch)
                      (let* ((alt (ly:pitch-alteration pitch))
                             (n (ly:pitch-notename pitch))
                             (o (ly:pitch-octave pitch))
                             (mem-alt (assoc-get n alt-alist)))
                        (if (eq? force? #t)
                            (set! alt-alist
                                  (assoc-remove! alt-alist n))
                            (if (= alt 0)
                                (if mem-alt
                                    (ly:music-set-property!
                                     note 'pitch
                                     (ly:make-pitch o n mem-alt)))
                                (set! alt-alist
                                      (assoc-set! alt-alist n alt))))))
                  note)))))))))

\score {
  \new Staff \someMusic
  \layout {
    \context {
      \Voice
      \consists #Persistent_accidentals_translator
    }
  }
}

%%%%