lilypond-user
[Top][All Lists]
Advanced

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

Re: Passing \tweak-s to engravers


From: Urs Liska
Subject: Re: Passing \tweak-s to engravers
Date: Thu, 14 Jun 2018 15:01:59 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0


Am 14.06.2018 um 13:32 schrieb David Kastrup:
Urs Liska <address@hidden> writes:

I have been banging my head against the wall for quite some time now,
but finally I'm at least at a point where I can ask a question here.

I am programmatically attaching a custom grob property to some music
and want to later act upon that in an engraver.
"later" is the key.  To do something "later" than something else, that
something else has to happen _earlier_.

That makes sense, but I didn't have a chance to realize this was an issue.
I am exclusively working in a music-function, which is of course way earlier than an engraver's acknowledger.


      
When I tried to switch the attachment process from \once \override to
\tweak the engraver suddenly didn't recognize the property
anymore.
It did.  _After_ you looked.

OK, now I see that.


First I thought I got it wrong with where the property was attached in
the music _expression_, but now I've realized the following behaviour:

When an engraver is consisted to a Voice or Staff or similar context
only properties created through overrides are visible to the
acknowledger while tweaks seem to be hidden. However, if I consist the
engraver to Score also tweaks are recognized.

The following MWE shows this behaviour with a common grob property,
but it's the same with my custom grob property. For my use case in
scholarLY it's neither an option to switch back to \once \override
(because also \tweak-able post-events have to be supported) nor to
consist the engraver to Score (because I need to know from which
context the annotations come).

So what do I have to do to make a Voice/Staff-consisted engraver aware
of \tweak-s and not only of \override-s?
And why is that behaviour as it is?

%%%
\version "2.19.80"

testEngr =
#(lambda (context)
   (make-engraver
    (acknowledgers
     ((note-head-interface engraver grob source-engraver)
      (ly:message "Notehead color: ~a" (ly:grob-property grob 'color))
      ))))

\layout {
  \context {
% uncomment *one* of the following two lines
    \Staff
    %\Score
    \consists #testEngr
  }
}

\relative {
  \once \override NoteHead.color = #red c'
  \tweak color #red c'
}
%%%
>From the Engraver tutorial in the Contributor's Guide (Acknowledging grobs):

       Acknowledge functions are called in the order engravers are
    ‘\consist’-ed (the only exception is if you set ‘must-be-last’ to ‘#t’).

       There will always be a call to ‘process-acknowledged ()’ whenever
    grobs have been created, and _reading_ stuff from grobs should be
    delayed until then since other acknowledgers might _write_ stuff into a
    grob even after your acknowledger has been called.  So the basic
    workflow is to use the various acknowledgers to _record_ the grobs you
    are interested in and _write_ stuff into them (or do read/write stuff
    that more or less is accumulative and/or really unrelated to other
    engravers), and then use the ‘process-acknowledged ()’ hook for
    processing (including _reading_) the grobs you had recorded.

       You can create new grobs in ‘process-acknowledged ()’.  That will
    lead to a new cycle of ‘acknowledger ()’ calls followed by a new cycle
    of ‘process-acknowledged ()’ calls.

Note that tweaks are applied by the acknowledger in the Tweak_engraver.

OK, this seems to be the culprit. Do I get this right that the tweaks are applied to a grob only *after* my grob acknowledger sees the grob? Then it is relevant that ...


I repeat my advice to read the Engraver tutorial.  Really.  In this
case, the central paragraph I quoted is very, very relevant.

... I did read that but it didn't help me. Nowhere did *I* write into grobs or even created new ones, so I couldn't actually know these paragraphs are relevant to my case.
This is just another point for the case I'm often making that much of our documentation on that level is too complicated insofar as you're only getting to the point of understanding it when you don't really need it anymore.

However, I've now changed the example to record the note-heads (as per an example in scm/music-functions.scm):
\version "2.19.80"

testEngr =
#(lambda (context)
   (let ((note-heads '()))
     (make-engraver
      (acknowledgers
       ((note-head-interface engraver grob source-engraver)
        (set! note-heads (cons grob note-heads))
        ))
      ((process-acknowledged translator)
       (for-each
        (lambda (nh)
          (ly:message "NoteHead color: ~a"
            (ly:grob-property nh 'color)))
        note-heads))
      )))

\layout {
  \context {
    % uncomment *one* of the following two lines
    \Voice
    %\Staff
    %\Score
    \consists #testEngr
  }
}

\relative {
  %\once \override NoteHead.color = #red c'
  \tweak color #blue c'
}

=>
Interpreting music...
NoteHead color: ()
NoteHead color: ()
NoteHead color: (0.0 0.0 1.0)
NoteHead color: (0.0 0.0 1.0)
This shows that process-acknowledged is called four times and the color information is only available at a certain time. Depending on where the engraver is consistet this "certain time" differs.

I get better and reliable results when looking for the property in (stop-translation-timestep), which should be OK since I'm not in any way dealing with the grobs themselves at that point. I'll fetch the data from the custom property, need to determine the ly:moment and then store the information away in some Scheme variables (for use in finalize).

However, since this will acknowledge grob-interface this means that I'll have to record and process *all* grobs in my score then? In the earlier approach (with \once \override) I could just check for the presence of the custom property and simply skip any grob that doesn't have one.

Still surprsising all this ...

Best
Urs


    


reply via email to

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