lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Create custom arpeggio-like engraver


From: Dimitris Marinakis
Subject: Re: Create custom arpeggio-like engraver
Date: Sun, 21 Nov 2021 15:48:21 +0200

Wow thanks Jean!
This is really helpful. I'll study the code. A lot of useful stuff in it.

I noticed the interesting squiggle-line-markup. I hope we eventually see more advanced options for spanners in the future. e.g. patterns of dots and dashes or segmented lines that can have angles between the segments. Really excited with the more active development of Lilypond this past year.

Best,
Dimitris

On Sun, Nov 21, 2021 at 1:37 PM Jean Abou Samra <jean@abou-samra.fr> wrote:


Le 17/11/2021 à 20:50, Dimitris Marinakis a écrit :
> I need a generic engraver that works similar to the default arpeggio
> one but I don't want to override the arpeggio engraver or any other
> default ones in case I need to have multiple events simultaneously.
>
> I saw a similar thread with a custom arpeggio stencil that had both up
> and down arrows but I need to keep this engraver its own thing in this
> case.
>
> I thought about searching inside the lilypond internal files to see
> how the default arpeggio spanner works but if someone else can help me
> through this I'd really appreciate it.
>
> Essentially, I'm interested in the ability of the arpeggio spanner to
> calculate its length based on the distance of the outer notes. I will
> replace the line stencil with something that will scale up/stretch
> depending on the vertical length of that spanner.
>
> Sorry if my terminology is wrong (engraver, spanner etc.)


How about this?

\version "2.22.1"

#(define-event-class 'custom-arpeggio-event 'music-event)

#(define (define-event! type properties)
    (set-object-property! type
                          'music-description
                          (cdr (assq 'description properties)))
    (set! properties (assoc-set! properties 'name type))
    (set! properties (assq-remove! properties 'description))
    (hashq-set! music-name-to-property-table type properties)
    (set! music-descriptions
          (sort (cons (cons type properties)
                      music-descriptions)
                alist<?)))

#(define-event!
   'CustomArpeggioEvent
   '((types . (custom-arpeggio-event post-event event))
     (description . "")))

#(set-object-property! 'CustomArpeggio 'is-grob? #t)
#(set-object-property! 'CustomArpeggio 'translation-type?
ly:grob-properties?)

\layout {
   \context {
     \Global
     \grobdescriptions #(acons 'CustomArpeggio
                               (assq-ref all-grob-descriptions 'Arpeggio)
                               all-grob-descriptions)
   }
}

#(ly:register-translator
   (lambda (context)
     (let ((arpeggio-event #f)
           (arpeggio #f))
       (make-engraver
         (listeners
           ((custom-arpeggio-event engraver event)
              (set! arpeggio-event event)))
         ((process-music engraver)
            (if arpeggio-event
                (set! arpeggio
                      (ly:engraver-make-grob engraver 'CustomArpeggio
arpeggio-event))))
         (acknowledgers
           ((rhythmic-head-interface engraver grob source-engraver)
              (if arpeggio
                  (ly:pointer-group-interface::add-grob arpeggio
'side-support-elements grob)))
           ((stem-interface engraver grob source-engraver)
              (if arpeggio
                  (begin
                    (ly:grob-set-parent! arpeggio Y grob)
                    (ly:pointer-group-interface::add-grob arpeggio
'stems grob))))
           ((note-column-interface engraver grob source-engraver)
              (if arpeggio
                  (ly:pointer-group-interface::add-grob grob
'conditional-elements arpeggio)))
           ((arpeggio-interface engraver grob source-engraver)
              ; NB ==============================================
              ; Place custom arpeggios on the left of normal ones.
              ; If this is not what you want, flip 'arpeggio' and
              ; 'grob' below.
              ; =================================================
              (ly:pointer-group-interface::add-grob arpeggio
'side-support-elements grob)))
         ((stop-translation-timestep engraver)
            (set! arpeggio-event #f)
            (set! arpeggio #f)))))
   'Custom_arpeggio_engraver
   '())

\layout {
   \context {
     \Voice
     \consists Custom_arpeggio_engraver
   }
}

customArpeggio = #(make-music 'CustomArpeggioEvent)

{
   <c' c''>\customArpeggio
   \override CustomArpeggio.color = red
   <c' c''>\arpeggio\customArpeggio
}


The engraver is adapted from the default Arpeggio_engraver,
of which the C++ code can be found at
https://gitlab.com/lilypond/lilypond/-/blob/master/lily/arpeggio-engraver.cc
For information on Scheme engravers, see
https://extending-lilypond.readthedocs.io/en/latest/translation.html

To get the vertical extent of the CustomArpeggio in
a stencil callback, read the 'positions property. For
example:

\score {
   \layout {
     #(layout-set-staff-size 30)
   }
   {
     \override CustomArpeggio.stencil =
       #(lambda (grob)
          (let ((positions (interval-scale (ly:grob-property grob
'positions)
(ly:staff-symbol-staff-space grob))))
            (ly:stencil-translate-axis
             (grob-interpret-markup
              grob
              (make-draw-squiggle-line-markup
               0.5
               (cons 0 (interval-length positions))
               #t))
             (car positions)
             Y)))
     <c c''>\arpeggio\customArpeggio
   }
}

Best,
Jean

reply via email to

[Prev in Thread] Current Thread [Next in Thread]