Flams, drags and ruffs

Writing a flam, drag, or ruff is pretty easy, but it's just too much typing for such a common ornament. Because the notation of the ornament depends on the note it is attached to, you can't just write it as a simple variable, you need a function. This snippet provides four functions and an example of using them: \flam, \drag,\ruff and the more generic \graceRepeat, also, a improved version of add-grace-property, thanks to David Kastrup.

Just write \flam, \drag, or \ruff, followed by the note you want to attach it to. If you pass it a chord, then the first note in the chord will get the flam. They are typeset as grace notes internally, so if you want to change their appearance, use the usual grace note tweaks.

The more generic \graceRepeat offers the possibility to get grace chords and to specify which number of grace notes you want.

\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=566

% The new @code{add-grace-property}. Thanks David Kastrup.
% see also : http://lilypond.1069038.n5.nabble.com/flam-snippet-not-working-td149310.html

#(define (add-grace-property context-name grob sym val)
   "Set @var{sym}=@var{val} for @var{grob} in @var{context-name}."
   (define (set-prop context)
    (let* ((current (ly:context-property context 'graceSettings))
            (new-settings (append current 
                                  (list (list context-name grob sym val)))))
      (ly:context-set-property! context 'graceSettings new-settings)))
      
  (make-apply-context set-prop))

%% Return repeated single notes or chords, depending on @var{print-chord?}
%% If @var{print-chord?} is set @code{#f}, the first written note is taken.
%% The Number of repeats is set by @var{lngth}
%% Only notes are returned. Other stuff like @code{Script}, @code{Fingering} 
%% is thrown away.
#(define (grace-from-main-note print-chord? lngth music)
  (let* ((elts (ly:music-property music 'elements))
         (has-duration? 
           (lambda (x) (ly:duration? (ly:music-property x 'duration))))
         ;; If the whole chord should be printed catch Notes only.
         ;; If the first written note should be printed catch it.
         ;; Otherwise, don't touch the music.
         (mus (cond ((and (music-is-of-type? music 'event-chord) print-chord?)
                     (make-event-chord (event-chord-notes music)))
                    ((music-is-of-type? music 'event-chord)
                     (first (event-chord-notes music)))
                    (else music)))
         ;; Set duration of note, clear 'articulations.
         (note (map-some-music
                  (lambda (m)
                    (and (has-duration? m)
                         (begin
                           (set! (ly:music-property m 'duration)
                                 (ly:make-duration (if (> lngth 1) 4 3) 0 1 1))
                           (set! (ly:music-property m 'articulations) '())
                           m)))
                  (ly:music-deep-copy mus)))
         (next-note (ly:music-deep-copy note))
         (last-note (ly:music-deep-copy note))
         ;; Create a list of notes for use with (> lngth 1)
         (m-list 
           (flatten-list 
             (list note 
                   (make-list (max 0 (- lngth 2)) next-note) 
                   last-note))))
  ;; Return a single note if (= lngth 1 ).
  ;; Insert Beam for (> lngth 1) and return the result.
  (cond ((= lngth 1 )
           note)
        ((> lngth 1)
           (list-set!  m-list 0
             (begin
                (ly:music-set-property! 
                    note 
                    'articulations
                    (list (make-music
                           'BeamEvent
                           'span-direction -1)))
                 note))          
           (list-set!  m-list (- lngth 1)
             (begin
                (ly:music-set-property! 
                    last-note 
                    'articulations
                    (list (make-music
                           'BeamEvent
                           'span-direction 1)))
                last-note))
            (make-sequential-music m-list))
         ;; fall back
         (else (make-sequential-music '()))
            )))

graceRepeat =
#(define-music-function (chord-repeat? how-much note) 
  ((boolean? #f) integer? ly:music?)
  "Return @var{note} preceded by repeated and beamed grace-notes. The number of
  grace-notes is specified by @var{how-much}.
  If @var{note} is a chord the first written note of it is used.
  If @var{chord-repeat?} is specified the whole chord is repeated during 
  @code{GraceMusic}"
  #{ 
    \slashedGrace {  $(grace-from-main-note chord-repeat? how-much note) }
    $note 
  #})
  
flam = 
#(define-music-function (music)(ly:music?)
  "Return @var{music} preceded by 1 grace-note"
  #{ \graceRepeat #1 $music #})

drag =
#(define-music-function (music)(ly:music?)
  "Return @var{music} preceded by 2 grace-notes"
  #{ \graceRepeat 2 $music #})

ruff =
#(define-music-function (music)(ly:music?)
  "Return @var{music} preceded by 3 grace-notes"
  #{ \graceRepeat #3 $music #})

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% EXAMPLE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Note: the new coding works now for \notemode too.

#(set-global-staff-size 18)

\paper { indent = 0 }

\layout {
    \context {
      \Score
      \override NonMusicalPaperColumn.line-break-permission = ##f
    }
}

<<
\new DrumStaff {
  \new DrumVoice \drummode {
    r4 \flam sn4 \drag cymr4 \ruff bd4 |
    \flam <sn bd>2 \flam <bd sn>2  |
    \graceRepeat ##t #4 <bd sn>1 |
    \graceRepeat  #1 <bd sn>1 
    \graceRepeat  #2 <bd sn>1 
    \graceRepeat  #3 <bd sn>1 
    \graceRepeat  #1 <bd sn>1 
    \graceRepeat  #2 <bd sn>1 
    \graceRepeat  #3 <bd sn>1 
    \graceRepeat  #4 <bd sn>1 
    \graceRepeat  #5 <bd sn>1 
  }
}

\new Staff 
\new Voice
\relative c' {
	\flam c \drag d 
	\ruff e 
	\graceRepeat #4 f-1\2^"foo"
	\flam <c f>
	% Insert the beginning of a (Phrasing)Slur before the grace-notes.
	<>^\(
	\drag <f c>
	% Change appearance of grace-notes.
	$(add-grace-property 'Voice 'NoteHead 'style 'cross)
	\ruff <c f>~ <c f>
	$(remove-grace-property 'Voice 'NoteHead 'style)
	\graceRepeat  #4 <f c>
	% Insert the beginning of a (Phrasing)Slur before the grace-notes.
	<>(
	\graceRepeat  #5 <c f>
	\graceRepeat ##t #6 <f c-2\3>-"foo"->
	)\)
}
>>