Hi,
Le 17/04/2021 à 14:32, Lukas-Fabian Moser a écrit :
After posting my engraver yesterday, I noticed some unforeseen
behaviour that gave me an idea for a possible addition to your
excellent tutorial on https://extending-lilypond.readthedocs.io/
(which I unfortunately only today had time to skim through). Namely:
The engraver I posted yesterday collects notes across all voices or
staves, for instance in situations like
<<
\new Staff { c' }
\new Staff { cis' }
>>
While this might actually be desirable (at least I tell my students
never ever to produce
[image]
since nobody knows if the clash is intended or not), I was surprised
that it did so. That's how I found out that if I wrap the engraver in
a (lambda (ctx) .... ) construct, then it seems to work independently
for each voice context, even if it's \consist'ed to all Voices or
Staves in the \layout {} block.
Maybe that would be an interesting addition to your engraver tutorial?
Well, blow me down! I never realized that you could use an engraver
alist directly instead of a function returning the alist, with the
effect you observed.
Thanks! I'll add some words about this.
As a side note, all engravers defined by LilyPond are like the ones made
with (lambda (context) ...) (the majority is defined in C++ classes). I
don't know of a use case where the form without the lambda is necessary
-- I guess you'd rather consist your engraver in Score, so process-music
and stop-translation-timestep are run just once for example.
And while we're at it, here's another question: It turns out it's
possible to add note-event properties like force-accidental inside the
process-music hook. But when I tried to change the _pitch_ of a note
at this stage, there was no effect. I _can_ change the pitch of a
note-event in the note-head listener, but that's too early in my use
case (since I need to know all simultaneous pitches).
So, in which parts of an engraver do I still have the opportunity to
change pitches?
That's the problem with engravers. They are a modular system, which
implies strong constraints in order to stay insensitive to the order of
engravers as well as the order of events. What is happening here is that
the Note_heads_engraver is reading the pitch in process-music before
your engraver has had a chance to change it.
The best you can do is set the pitches on all events every time you get
one. For an example in a very similar situation, take a look at the code
here:
https://lists.gnu.org/archive/html/lilypond-user/2021-04/msg00025.html
This stores all note events with their original pitches, and naturalizes
them; when a new key arrives, they would be all re-naturalized using the
original pitches. ("Would" because I couldn't actually find a case where
the key comes after the notes.) This is not very pretty, but I don't
know a better solution.
And if you were implementing something in LilyPond directly (not as a
user extension), you'd probably go change the Note_heads_engraver itself.
Cheers,
Jean