lilypond-devel
[Top][All Lists]
Advanced

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

Re: Scheme engraver structure questions


From: Carl Sorensen
Subject: Re: Scheme engraver structure questions
Date: Wed, 3 Feb 2010 20:36:30 -0700



On 2/3/10 7:50 PM, "Eric Knapp" <address@hidden> wrote:

> Hello,
> 
> I'm learning more Scheme. (I think I'll be learning Scheme for a
> while.) I'm looking at the sample file scheme-engraver.ly and I have a
> few questions. I think I'm understanding the structure of the Scheme,
> it appears to be a list of Scheme pairs. Each pair (cons) has a symbol
> that starts with an apostrophe and a lambda function or a list of more
> pairs of lambda functions.

The example shows lambda functions, but they don't need to be written as
lambda functions.  They can be created as named functions, and then the name
of the function can be put in the list instead of the lambda function.  The
functions (either lambda or named) should be functions of one variable, the
event to which the listener will respond.

If I were writing a Scheme engraver, I wouldn't use lambda functions.  I'd
use named functions because it's easier for me to understand them.

> I'm familiar with symbols in Ruby and I'm
> assuming they are similar in Scheme. The pairs correspond to a method
> or macro in a C++ engraver class. Examples would be:
> 
> C++: virtual void initialize ()
> Scheme: (cons 'initialize (lambda (trans)...))
> 
> C++: IMPLEMENT_TRANSLATOR_LISTENER (Engraver_name, event_name)
> Scheme: (cons 'listeners (list (cons 'rest-event ...)))

There can be more than one listener, so it should be something like this, I
think...

(cons 'listeners (list (cons 'rest-event ...)
                       (cons 'note-event ...)
                       (cons 'string-number-event ...)))

> 
> C++: DECLARE_ACKNOWLEDGER (note_head)
> Scheme: (cons 'acknowledgers (list  (cons 'note-head-interface ...)))

Similarly with the acknowledgers.

> 
> Am I on the right track up to this point?
> 

Yes, you are.


> Next, we have many event points where we have different objects
> available and where we can do work. The  question I have is where do I
> do what I want to do? Where can I get some documentation about what is
> the appropriate for each section?

So this is the very hardest part of understanding the LilyPond architecture.
I will do my best to give you an answer, but it may not be clear.  Keep
trying if it's not.

Originally, the parser reads through the input music stream and translates
everything into a Scheme structure which is a music expression for each
score.  The music expression can contain lots of music events.

Iterators then work their way through the music tree, sending music events
off to translators, which will be responsible for printed and midi output.
The iterators send the events off one music-moment at a time; all events
that happen at one moment will be translated before any events at the next
moment.

The job of the engravers (or to be more general, I should say translators;
translator is the base class for both performers [which generate midi] and
engravers [which create printed output]) is to receive the events, and,
based upon the events, create the appropriate grobs (or midi output, in the
case of performers).  However -- and this is important -- the grobs that are
created by engravers are not yet turned into printed output; the conversion
to printed output is handled by the backend.

So, engravers create grobs and set the necessary grob properties, but they
don't actually handle the layout.  The backend takes care of the layout.

So in the case of a StaffTab, you need to have avnote engraver, a
string-indicator engraver, and a fingering engraver.  These engravers should
be different than either the standard engravers or the tabStaff engravers.
So you'd probably want something like Staff-tab-note-engraver,
Staff-tab-string-engraver, and Staff-tab-fingering-engraver.

To take as a simple example the Staff-tab-string-engraver, this engraver
will listen to note-events and string-number-events.  It needs to listen to
both, because if notes are not inside a chord, string numbers are separate
events.  On the other hand, if the notes are inside a chord, string numbers
are part of the articulation property of the note event.  (See
Tab-note-heads-engraver.cc for code that shows how this works).

Anyway, once the engraver receives the events, it will read the string
number from the appropriate event.  Then the engraver will create a
TabStaffString grob, with a staff-position property based on the string
number.  And that will be the end of the engraver's work.

Now, there also needs to be a backend function that is used to print the
TabStaffString grob (a pointer to this function is stored in the 'stencil
property of the grob).  This function will be called with the grob as its
argument.  (I haven't yet worked out exactly what code calls the function
stored in the 'stencil property -- that's part of the "magic" of LilyPond
for me right now).  Based on the properties of the grob, the stencil will be
created and turn into output.  All of the drawing routines are relative to
the origin of the grob; the origin is determined by the layout routines.
The grob drawing routines never know where on the page they go; they just
create the grob around the home point, and the layout engine makes sure they
fit on the page just so.

> 
> I also have the example for the ez-numbers-engraver where numbers are
> put in notehead. All that code is being done in the "(cons
> 'acknowledgers...)" section. I'm trying that and first task is the
> custom noteheads. I'm getting this to work, but I'm having trouble
> with the next piece of my puzzle.
> 
> Here are some more basic questions.
> 
> How do I detect the direction of the stem? Is it up or down?

The ez-numbers-engraver should in general not detect the direction of the
stem, I think.  That's more likely to be done in the backend.  But I'm less
confident about this answer than about most.

> 
> How do I get the string number?

If the note is not in a chord construct, the string number will be in a
string-number-event.  If the note is in a chord construct, the string number
will be in a string-number articulation.

You can find this kind of information out with the \displayMusic function.
See Extending LilyPond, section 1.3.1 of the 2.13 documentation for
information on how to use \displayMusic.

> 
> How do I get the duration of the note?

>From the 'duration property of the note-event.

> 
> Thanks for all the help.
> 
> -Eric
> 
> 
> _______________________________________________
> lilypond-devel mailing list
> address@hidden
> http://lists.gnu.org/mailman/listinfo/lilypond-devel





reply via email to

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