On Thu, 2005-04-14 at 06:01, Bernard Hurley wrote:
> I have somewhat rashly volunteered to be Implementation documenter.
> Han-Wen informs me that various abortive starts have already been made
> on this. So if you have any material that would be useful, please e-mail
> it to me.
> 

Bernard,

Here are materials I put together in my abortive start.  They were
helpful to me but are by no means complete, especially with the new
backends in 2.5.x.

Thanks for taking on this project.

Carl Sorensen


@c -*- coding: latin-1; mode: texinfo; -*-
@c This file is part of lilypond.tely

@c A menu is needed before every deeper *section nesting of @node's; run
@c     M-x texinfo-all-menus-update
@c to automatically fill in these menus before saving changes

@node Programming Concepts manual
@chapter Programming Concepts manual

This chapter explains some of the concepts related to LilyPond programming.
It is intended as an introductory reference for developers who want to 
make changes to LilyPond.

@menu
* Program Execution Overview::
* Music classes::
* Contexts::
* Engravers::
* Grobs::  
* Stencils::
* Iterators::  
* Keywords and special \\words ::           
@end menu

@node Program Execution Overview
@section Program Execution Overview
@cindex Program Execution Overview

Execution of LilyPond begins with the parser (@file{lily/parser.yy}). 
When the input file is parsed, a Music + Music_output_def object is
created.  This object leads to a Global_context object (see 
@file{lily/global-context.cc}).

The Global_context object creates a Score context to interpret the music.
(@file{lily/score.cc}).  Interpreting proceeds, with context objects being
created as dictated by the Music + Music_output_def object.  When the
interpretation is complete, Score_context::get_output() returns a
Music_output object, which is a Paper_score object for notation or a
Performance object for MIDI.

During the interpretation process, Music_iterators handle
the interpretation of Music objects and synchronize the various Contexts
to ensure that the different Items are tied together appropriately.  This
is accomplished in Global_context::run_iterator_on_me, by a recursive call
to Music_iterator::pending_moment.  The events are delivered to 
Music_iterator::procss(next_moment).  Finally, 
Global_context::one_time_step() is called to create all the grobs for the
current time step.

This Music_output object is the entry point for the backend (see
ly_format_output(), in @file{lily/score.cc}).  The backend is responsible
for putting ink on the page (or notes in the MIDI file).

The main steps of the backend are found in @file{lily/paper-score.cc}
(Paper_score::process) and @file{lily/system.cc} (System::get_lines()).

System::get_line() causes each grob to deliver a Stencil to the outputting
backends (@file{scm/output-tex.scm} and @file{scm/output-ps.scm}) to
produce TeX and Postscript, respectively.



@node Music Classes
@section Music Classes
@cindex Music Classes

@node Contexts
@section Contexts
@cindex Contexts

Contexts are used to process music expressions, generating music events and
passing these events to one or more Engravers.  Engravers handle the events 
and convert them to grobs.

Contexts are created in lilypond input files.  The predefined contexts
are included in @file{ly/engraver-init.ly}.   This file is the appropriate
place to add a new context.

During development, the new context can be created in a lilypond input
file.  Once the context is debugged, it can be added to 
@file{ly/engraver-init.ly}.




@node Engravers
@section Engravers
@cindex Engravers
Engravers are used to handle music events for inclusion on the page.
In most intances, they convert music events to grobs, but there are also 
engravers that don't create grobs, such as swallow-engraver and 
grob-pq-engraver.

Each unique kind of grob should have its own engraver.

Engravers are C++ classes (see @file{lily/note-heads-engraver.cc}).

To add an engraver, simply create a file for the class and add it to
the lily/ directory.  Make will then include the file when LilyPond is 
rebuilt.

In creating the engraver, it is best to use an existing 
engraver as a template, as there is a number of subtleties that must be
done correctly.

The work of adding the class to LilyPond is done in the ENTER_DESCRIPTION
macro.

A list of all engravers is found in @internalsref{engravers}.



@node Grobs
@section Grobs
@cindex Grobs

Grobs (graphic objects) are produced by LilyPond to place graphics on the page.
They are created from within engravers, either as
Spanners (a derived class of objects that span more than one ``column'', such as
slurs, and beams) or Items (a derived class of objects that only occupy a single
column, such as notes, clefs, etc.)

There are two other derived classes: System (derived from Spanner,
contaning a "line of music") and Paper_column (derived from Item, containing
all Items that happen at the same moment). They are separate
classes because they play a special role in the linebreaking process.

The definition of all grobs is found at @internalsref{All layout objects}.

Each grob has an interface, which is not a C++ class per se.  The idea of 
a grob interface hasn't crystallized well. At the moment, an interface is 
a symbol, with a bunch of grob properties. They are not objects that are
created or destroyed. 

Grob interfaces are defined by programmers in 
@file{scm/define-grob-interfaces.scm}.  These definitions are documented in 
@internalsref{Graphical object interfaces}.

Grob properties are used to help the Stencil creators do their job.  
Properties can include constants, functions, or other grobs.  This allows
multi-element grobs such as  Spanner , System, and Paper_column to properly
handle
the individual grobs of which they are comprised.

Grob properties are currently used as elements of an
alist chain that are used in Stencil creation. 
Stencil creators use the props
alist to control the characteristics of the created Stencil.

Grob properties are defined by programmers in 
@file{scm/define-grob-properties.scm}.  These properties are docemented in 
@internalsref{User backend properties}.

>


@node Stencils
@section Stencils
@cindex Stencils

Stencils are the output specifications created by LilyPond grobs. 
They are C++ objects containing a Box, which describes the physical limits
of the ink on the paper, and a Scheme function, which is evaluated by
the backend to create the TeX or Postscript code responsible for
generating the ink.
 
The Box has an X_AXIS extent and a Y_AXIS extent.  The extents are pairs.  The 
first element of the pair 
is the coordinate of the left (for X_AXIS) or bottom (for Y_AXIS) side 
of the stencil's bounding box.  The second element of the pair is the
coordinate of the right or top side of the bounding box. The coordinates
are measured relative to the stencil's reference point.   The first element 
of each extent pair must be less than the second.  In most cases, the first
element of the extent will be negative and the second element will be positive,
which place the reference point for the stencil inside the bounding box.
The reference point for the stencil is in @var{Stencil::origin_}, and can be
accessed in Scheme with @var{ly:stencil-origin}.

The Scheme function contains a specification of how to print the
object, along with the horizontal and vertical extents.
The specification is a scheme expression that is processed by the various
output backends, such as @file{scm/output-tex.scm}.  When a new stencil
specification is added to LilyPond, the appropriate code for handling the 
specification must be added to the relevant backends.


Lilypond routines for defining and adjusting stencils are generally found
in @file{lily/stencil.cc} and @file{lily/stencil-scheme.cc}. 
@file{lily/stencil.cc} implements the Stencil class. 
@file{lily/stencil-scheme.cc} implements scheme accessors to the Stencil class.
Scheme accessors are of the form @code{ly:stencil-*}, and are used to manipulate
stencils in scheme.

Internal documentation of the scheme accessors is found at 
@internalsref{ly:stencil-add}.

Stencils are usually created in @code{Class::print_function()}, which is
exported to Scheme using the macro MAKE_SCHEME_CALLBACK.


@node Smobs
@section Smobs
@cindex Smobs

Smobs are C++ objects in Scheme. Scheme objects (lists, functions) are
manipulated from C++ as well using the GUILE C function interface
(prefix: scm_).

Smobs are the primary interface (sometimes called 'glue' or 'lubrication') 
between the 
guile (Scheme)  part and C++ part of LilyPond.  C++ routines can call Scheme 
routines (using scm_call_0, scm_call_1 as well as the guile C function
interface).

Scheme routines can call C++ routines if the C++ routines have been
exported using LY_DEFINE.  For an example, see @file{scm/stencil-scheme.scm}.

@node Iterators
@section Iterators
@cindex Iterators

Music_iterators are used to walk through different music classes and
deliver events in a synchronized way, so that notes that play together
are processed at the same moment and (as a result) end up at the same
horizontal position.

Music_iterators are created during the interpreting phase, in

@code{Music_iterators::get_static_get_iterator()}

according to the @code{iterator-ctor} property of music types (see
@file{scm/define-music-types.scm}).

Music_iterators are able to read and set Context properties, idem for
Engravers and Contexts.  They can send 'synthetic' music events to a 
context in order to influence the behavior of Engraver.  
part-combine-status is an example of a synthetic event used by
Part_combine_iterator to communicate with (to) Part_combine_engraver.

@node Keywords and special \\words
@section  Keywords and special \\words
@cindex  Keywords and special \\words

LilyPond keywords are defined in defined in @file{lily/my-lily-lexer.cc}.

Most of the words prededed by a backslash are really identifiers, rather
than reserved words, and are defined in @file{ly/*.ly}.



@node Making Additions to LilyPond
@chapter Making Additions to LilyPond

This chapter describes approaches to common additions to LilyPond

@menu
* Adding articulation signs::
* Adding new grobs::
@end menu

@node Adding articulation signs
@section Adding articulation signs
@cindex Adding articulation signs

Articulation signs can easily be added using metafont.
The steps involved are the following
@list
@item
Add the articulation sign to the feta font (see
@file{mf/feta-schrift.mf}).  It is often easy to do this by modifying
an existing character in the font.
@item
Tell LilyPond about your articulation sign by adding it to the file
@file{scm/script.scm}.
@item
Add a handy shortcut to the file @file{ly/script-init.ly}.
@item
For testing, add it to @file{input/test/script.chart.ly}.
@item
For documentation, add it to the Articulations section of the user
manual, found in @file{Documentation/user/notation.itely}.
@end{list}

Whenever changes are made to the font, you must clean the fonts before
rebuilding, or you will not see the changes.  This can be done by
executing @file{buildscripts/out/clean-fonts}.

@node Troubleshooting the build process
@chapter Troubleshooting the build process
@cindex Troubleshooting the build process

In order to make changes in LilyPond, it is necessary to rebuild the
application.  This chapter covers common problems in building both the
application and the documentation.

@node Using gdb with LilyPond
@chapter Using gdb with LilyPond
@cindex Using gdb with LilyPond
@cindex Debugging

To use gdb with lilypond, it is necessary to first compile it with debugging 
symbols.

./configure --prefix=$(pwd) --enable-debugging
make

Do not use make install, as that will strip out the debugging symbols.

Start LilyPond under gdb with the following

gdb ./lily/out/lilypond

@node Debugging LilyPond in guile
@cindex Debugging

You can debug in guile by using #(top-repl).
-----
toto=\notes { c'' }
#(top-repl)
-----

nicolas:/tmp> lilypond toto.ly 
lilypond (GNU LilyPond) 2.1.28
Exécution de usr...
Maintenant en traitement: « toto.ly »
Analyse...
guile> (define-module (*anonymous-ly-1*))
guile> toto
#<Music SequentialMusic>
guile> (use-modules (lilypond music-expressions))
guile> (mus:display toto)
<SequentialMusic
  :elements (
             <EventChord
               :elements (
                          <NoteEvent
                            :duration #<Duration 4 >
                            :pitch #<Pitch c'' > >) >) >
guile> (quit)

Thanks for that precious tip, Han-Wen.

_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to