Flaming Hakama Design Consultancy

Dressed to Kill: Attire for Martial Arts

Lilypond Object Model

Contexts and Objects

## Contexts and objects

Contexts are different from graphical objects and their properties (prop) are changed differently.

Here is a summary (val means value):

Where contexts (Staff, Voice, etc.) Ctx Graphical objects (Clef, etc.) obj
music { \set Ctx.prop = val } { \override Ctx.obj.prop = val }
with block \with { prop = val } \with { \override Ctx.obj.prop = val }
layout block (variant 1) \layout { \context { \Ctx prop = val } \layout { \context { \Ctx \override obj.prop = val }
layout block (variant 2) \layout { \set Ctx.prop = val } \layout{\override Ctx.obj.prop = val }
  1. be careful with {}
  2. read the input as functions with some optional arguments
  3. context properties and object properties are different

About Lilypond Contexts

What is a context?  When I run LilyPond, when does a context “enter” and what is its purpose?

What is an engraver?  When reading this word I think of a human with a certain profession.  When I try to translate this to LilyPond I think of some module that “prints” items.

But as far as I’ve learned recently an engraver is first an entity that waits for items to be passed to it from the “context” and that can then do something with this item, e.g. printing it, modifying it before printing, writing the event to a logfile or sending an email on its behalf.

 

Does anyone really understand what a Voice is?

I think there are two levels at which object models need to be understood: the user level and the developer level.  Users only need to know *what* the object is; developers need to know *how* the object is implemented as well.

There is a description of contexts and engravers in the Learning Manual (Section 3.3), another one in the Notation Reference (Section 5.1), and a third in the Contributor’s Guide (Section 10.1).  Rather than try to edit any of those, I’d like to propose my mental model.   Maybe we can get to something simpler that will help explain things (but maybe not).

So here we go — comments and suggestions are welcome.

%%% Start of model

Contexts are LilyPond objects that contain properties, music expressions,
and translators.  Some contexts, like Score and Staff, can contain other
contexts as well.  Other contexts, like Voice, are bottom contexts and
cannot contain other
contexts.

Contexts are responsible for controlling the output (printed or midi) of
the music they contain.  They do this by calling translators in the
environment of the context properties.

Translators are program elements that convert music expressions to output.
Engravers are translators that create printed output.  Performers are
translators that create midi output.

Translators examine the music expressions that are contained in the
context, and create output elements.  For the case of engravers (which
create graphical output), the output elements are grobs.  The grobs have
properties that are used to create their appearance on the page.

After all the grobs are created, the spacing engine takes over and tries
to make an esthetically pleasing layout that fits in all the grobs.  These
are then committed to the page.

If we want to change the layout, we need to change the properties of
either grobs or contexts.  Changing these properties affects how the
layout engine tries to pack the grobs together.

%%%%  End of model

In my mind, this model explains how LilyPond works well enough that I can
make happen what I need to make happen.

Carl

 

<h3>The Voice Construct</h3>

Logically, a LilyPond voice matches almost perfectly with my conception of a musical voice.

A Voice context is a context, which means it can contain engravers, performers, and music expressions.

It is a bottom context, which means it cannot contain other contexts.

By default, it contains engravers that create the following graphical layout (as described in the Internals Reference):

This context creates the following layout object(s):
Arpeggio, Beam , BendAfter , BreathingSign , ClusterSpanner ,
ClusterSpannerBeacon , CombineTextScript , Dots ,DoublePercentRepeat ,
DoublePercentRepeatCounter , DoubleRepeatSlash , DynamicLineSpanner ,
DynamicText ,DynamicTextSpanner , Fingering , Flag , Glissando , Hairpin ,
InstrumentSwitch , LaissezVibrerTie , LaissezVibrerTieColumn
,LigatureBracket , MultiMeasureRest , MultiMeasureRestNumber ,
MultiMeasureRestText , NoteColumn , NoteHead , NoteSpacing ,PercentRepeat
, PercentRepeatCounter , PhrasingSlur , RepeatSlash , RepeatTie ,
RepeatTieColumn , Rest , Script , ScriptColumn , Slur ,Stem , StemStub ,
StemTremolo , StringNumber , StrokeFinger , TextScript , TextSpanner , Tie
, TieColumn , TrillPitchAccidental ,TrillPitchGroup , TrillPitchHead ,
TrillSpanner , TupletBracket , TupletNumber  and VoiceFollower.

If I want to change the appearance of any of the layout objects (grobs) specified above *for only this voice* I must change either the grob properties associated with the grob or the context properties that affect the grob in the Voice context.

If I want to change the appearance of the grobs for multiple Voices, I must change the grob properties associated with the grob or the context properties that affect the grob in a context that contains all the Voices I wish to affect, e.g. a Staff, a StaffGroup, or a Score.

There are some specialized Voice contexts that are used for specialized notation, e.g. TabVoice, MensuralVoice.

Carl

<h3>What is a performer</h3>
<h3>What is a music expression</h3>

This is quite clear and sufficiently explained.

<h3>The difference between listeners and acknowledgers</h3>
Listeners respond to particular stream events:
http://lilypond.org/doc/v2.18/Documentation/internals/music-classes

Acknowledgers respond to particular grobs that have been announced by other engravers (that created the grobs based on the stream events that they listened to).  This process of acknowledging grobs happens through grob interfaces:
http://lilypond.org/doc/v2.18/Documentation/internals/graphical-object-interfaces

Basically like this:

[stream event] ?> [engraver A with listener] ?> [grob]

[grob] ?> [engraver B with acknowledger] ?> [?]

but engravers can have both listeners and acknowledgers, and more than one of each.  Here?s an example:

%%%%%%%%%%%%%%%%%%
\version “2.18.2”

#(define Some_custom_engraver
(make-engraver
(listeners
((key-change-event engraver event)
(display event)(newline)
;; do something with key-change-event events
)
((note-event engraver event)
(display event)(newline)
;; do something with note-event events
))
(acknowledgers
((key-signature-interface engraver grob source-engraver)
(display grob)(newline)
;; do something with key-signature grobs
)
((note-head-interface engraver grob source-engraver)
(display grob)(newline)
;; do something with note-head grobs
))))

\new Staff \with {
\consists \Some_custom_engraver
}{
\key c \major
c’1
}
%%%%%%%%%%%%%%%%%%

As far as I can tell the order in which engravers are ?consisted? in their given context determines the order in which they receive the incoming events and grobs.

It?s probably *very* rare that a user would ever need to create an engraver and need to know about listeners and acknowledgers.

For anyone wanting to go further there?s more that I don?t understand (initialize, start-translation-timestep, process-music, etc.), to quote from the doc string of the make-engraver macro at the bottom of scm/output-lib.scm:

Symbols mapping to a function would be @code{initialize},
@code{start-translation-

timestep}, @code{process-music},
@code{process-acknowledged}, @code{stop-translation-timestep}, and
@code{finalize}.  Symbols mapping to another alist specified in the
same manner are @code{listeners} with the subordinate symbols being
event classes, and @code{acknowledgers} and @code{end-acknowledgers}
with the subordinate symbols being interfaces.?Let me know if I?ve misrepresented anything.Thanks again,
-Paul 

 

This list you link to above not what is produced by iterators.  It represents what is *fed* to the iterators, which convert music events, like NoteEvent, DynamicEvent, etc., into stream events.  Stream events are what is sent along to the translators, as you describe,
The list at http://lilypond.org/doc/v2.18/Documentation/internals/music-classeslists the various sorts of stream events which are input for translators.There is a (admirably well-hidden)  section of the Contributor’s Guide which touches on this.  See http://lilypond.org/doc/v2.19/Documentation/contributor/articulations-on-eventchordIf you look at the output of
\displayMusic { c’ }
or
#(display #{ { c’ } #})you will see (as I understand it) the output of the parser.  In it you will
see NoteEvent.  It is this sort of expression which forms the input at the
iteration stage, which will derive stream-events which will be sent to
relevant contexts (created at this stage, if necessary).Caveat: This all is mostly of interest from a developer’s perspective!  It is not something which a user need know to use LilyPond effectively.

 

 

There is some material about these “methods” from a C++ standpoint in the Contributor’s Guide:
http://lilypond.org/doc/v2.19/Documentation/contributor/engraver-tutorial

 

 

 

Score, Staff and Voice were musically clear to me right from the start.  Then I read the learning manual and didn’t find it hard to understand how this is represented in LilyPond after reading this: http://lilypond.org/doc/v2.18/Documentation/learning/contexts-and-engravers

 

 

I infer that he (correctly) means how

\version “2.19.18”
\score { \new Voice c’ }
\score { \new Staff c? }

creates two identical scores, even though one is apparently missing a Staff context, and the other is apparently missing a Voice context.  =)

> have an instrument be a collection of settings that would be applied to a
> context (perhaps a Staff, as in the case of violin, or perhaps a
> StaffGroup, as in the case of piano).

That, of course, is the [only?] real difficulty: there are ?instruments? that will always fit in a single Voice, and some that require at least 2 (piano), 3 (organ), or more (percussion) Voice or even Staff contexts.

> Are there any other music objects (not LilyPond music objects, but music
> objects in your world) that are missing from LilyPond?

It?s a good question. However, I would suggest calling ?Instrument? something other than a ?music object?, if ?Clef? is a ?music object?. They do very different things, and should be treated as such. Perhaps ?engraving object? and ?performing object? (or similar) might be better?

 

 

 

Without getting too technical, objects are things that you can create,
>have properties and relationships with other well-defined objects.
>
>This is true for things like staves, staff groups, scores, books, etc.
>You can say:  \new Staff = { … } to create a new staff because there is
>an object class called Staff that is well-defined.
>
>It has known properties like Staff.TimeSignature, Staff.extraNatural, etc.
>
>Other objects (Staff Groups, Books, etc.) know how to handle this Staff
>object, or several Staff objects.

As far as I know, all the above are contexts.  Except for /book and
/bookpart.  I’m not sure that they are contexts.  They aren’t listed in
the Internals Reference.