Thanks Aaron, great example! JM
> Le 4 févr. 2020 à 06:05, Aaron Hill <lilyp...@hillvisions.com> a écrit : > > On 2020-02-03 1:54 pm, Rutger Hofman wrote: >> I would also welcome this feature. How difficult is it to write a >> [Scheme] engraver? > > The mechanics of defining and using a Scheme engraver are relatively simple: > > %%%% > \version "2.19.83" > > Custom_engraver = #(lambda (context) > ;; The let block can define variables to track > ;; the state of an instance of the engraver. > (let ((some-condition? #f) > (some-counter 0) > (some-list '())) > > ;; An engraver is an association list (alist) with > ;; specific symbols mapping to procedures or alists > ;; of their own. The make-engraver utility macro > ;; can simplify defining the alist for an engraver. > (make-engraver > > ;; Procedures for one-time setup and cleanup. > ((initialize engraver) > (format #t "\n initialize: ~a" engraver)) > ((finalize engraver) > (format #t "\n finalize: ~a" engraver)) > > ;; Procedures for each processing stage in the music. > ((start-translation-timestep engraver) > (format #t "\n start-translation-timestep: ~a ~a" engraver > (ly:context-now context))) > ((stop-translation-timestep engraver) > (format #t "\n stop-translation-timestep: ~a ~a" engraver > (ly:context-now context))) > ((process-music engraver) > (format #t "\n process-music: ~a" engraver)) > ((process-acknowledged engraver) > (format #t "\n process-acknowledged: ~a" engraver)) > > ;; Procedures for handling events. > (listeners > ((time-signature-event engraver event) > (format #t "\n time-signature-event: ~a ~a" engraver > (ly:event-property event 'origin))) > ((note-event engraver event) > (format #t "\n note-event: ~a ~a" engraver > (ly:event-property event 'origin)))) > > ;; Procedures for handling grobs. > (acknowledgers > ((note-head-interface engraver grob source-engraver) > (format #t "\n note-head-interface: ~a ~a ~a" > engraver grob source-engraver)) > ((accidental-interface engraver grob source-engraver) > (format #t "\n accidental-interface: ~a ~a ~a" > engraver grob source-engraver))) > (end-acknowledgers > ((beam-interface engraver grob source-engraver) > (format #t "\n beam-interface (end): ~a ~a ~a" > engraver grob source-engraver)) > ((slur-interface engraver grob source-engraver) > (format #t "\n slur-interface (end): ~a ~a ~a" > engraver grob source-engraver))) > ))) > > \new Staff \with { \consists \Custom_engraver } > \fixed c' { \time 3/4 a8 b( cis'2) } > %%%% > > The above snippet shows examples of all possible handlers. In practice, an > engraver would define only the procedures, listeners, and acknowledgers that > are relevant. > > While most of the engravers in LilyPond are implemented in C++, there are a > few to be found in scheme-engravers.scm. However, the C++ engravers can > still be useful for figuring out how things should work in an engraver, > providing you have rudimentary knowledge of the language. Many of the C++ > functions are exported to or have equivalents in Scheme; so an interesting > learning exercise would be to take one of the simpler C++ engravers and > reimplement it within Scheme. > > > -- Aaron Hill >