@end example
-Building the website requires some additional tools:
+Building the website requires some additional tools:
@itemize @bullet
@item xpmtoppm (from the netpbm package: the Portable Bitmap Utilities).
The website will build without bib converter utility, but you will not
see our hypertextified bibliography.
+@item texinfo (a development release)
+The documentation will build with texinfo-4.0, but if you want split
+html pages, you're best off using the lates pretest version from
+@uref{ftp://texinfo.org/texinfo/pretests/texinfo-4.0b.tar.gz,
+texinfo-4.0b} or
+@uref{ftp://alpha.gnu.org/gnu/texinfo-4.0b.tar.gz,texinfo-4.0b}
@end itemize
@section Building LilyPond
# The new pretest version of makeinfo, 4.0a splits html files into their own
# directory. Available from
# ftp://texinfo.org/texinfo/pretests/texinfo-4.0a.tar.gz
-SPLITTING_MAKEINFO = $(shell makeinfo --version | egrep '4.0((.jcn[2,3])|a)')
+SPLITTING_MAKEINFO = $(shell makeinfo --version | egrep '4.0((.jcn[2,3])|a|b)')
# Generic rule using % twice not possible?
@c TODO: LilyPond Lilypond lilypond
-
@node Tutorial
@chapter Tutorial
You have to give that specification using a textual @emph{language}.
This chapter is a gentle introduction to that language.
+[rewrite]
+@c gentle?
+@c the first section is gentle
+@c the later sections get rather high-brow, deep, detailed, thorough
+
+
This tutorial will demonstrate how to use Lilypond by presenting
examples of input along with resulting output. We will use English
terms for notation. In case you are not familiar with those, you may
consult the glossary that is distributed with LilyPond.
-@cindex examples, tutorial
-
-The examples discussed are included in the distribution, in the
-subdirectory @file{input/tutorial/}@footnote{When we refer
-to filenames, they are relative to the top directory of the source
-package. In binary installations you should look in your doc section,
-eg, @code{/usr/share/doc/lilypond1.3/examples/input/tutorial}
-@cindex file names
-}. We recommend that you experiment with writing Lilypond input
-yourself, to get a feel for how the program behaves.
-
@menu
+* Music language of LilyPond::
* Running LilyPond:: Getting started
* The first tune:: The first tune
* Lyrics and chords:: Lyrics and chords
* end of tutorial:: The end
@end menu
+@node Music language of LilyPond
+@section Music language of LilyPond
+
+
+simple notes
+@lilypond[verbatim, relative 1]
+a b c
+@end lilypond
+
+alterations
+@lilypond[verbatim, relative 0]
+fis as cisis beses
+@end lilypond
+
+durations
+@lilypond[verbatim, relative 1]
+a1 a2 a8 a4 a16 a8. a16
+@end lilypond
+
+octaves: high quote, low quote (comma)
+@lilypond[verbatim, relative 1]
+c c, c''
+@end lilypond
+
+@c normal use of LilyPond is \relative note entry
+@c so let's just show/explain that and make smart
+@c people look for non-\relative
+
+lilypond chooses nearest note
+@lilypond[verbatim, relative 1]
+c f c g c
+@end lilypond
+
+to go other way: add octaviation quote
+@lilypond[verbatim, relative 1]
+c f, c' g, c'
+@end lilypond
+
+rests and skips
+@lilypond[verbatim, relative 1]
+r2 s4 r4
+@end lilypond
+
+
+meter
+@c \time -> \meter ?
+@lilypond[verbatim, relative 1]
+\time 3/4 c c c | R1 * 3/4
+@end lilypond
+
+key
+@lilypond[verbatim, relative 0]
+\key f \major es as bes
+@end lilypond
+
+slur, tie, phrasing slur
+@lilypond[verbatim, relative 1]
+c\( ( ) d ~ d \) c
+@end lilypond
+
+simple chords
+@lilypond[verbatim, relative 1]
+<a c> <b d> <c e>
+@end lilypond
+
+suddenly lilypond gets really difficult:
+[explain about score -> \score and \notes]
+
+long chords; simultaneous music
+@lilypond[verbatim]
+% huh?
+% \singleLine
+% \paper { \singleLine }
+\paper { linewidth = -1.0 }
+\score {
+ \context Staff \notes \relative c'' <
+ { a b c }
+ { c d e }
+ >
+}
+@end lilypond
+
+@lilypond[verbatim]
+\paper { linewidth = -1.0 }
+\score {
+ \context GrandStaff \notes \relative c' <
+ { a' b c }
+ { \clef bass c d e }
+ >
+}
+@end lilypond
+
@node Running LilyPond
@section Running LilyPond
@section The first tune
+@cindex examples, tutorial
+
+The examples discussed are included in the distribution, in the
+subdirectory @file{input/tutorial/}@footnote{When we refer
+to filenames, they are relative to the top directory of the source
+package. In binary installations you should look in your doc section,
+eg, @code{/usr/share/doc/lilypond1.3/examples/input/tutorial}
+@cindex file names
+}. We recommend that you experiment with writing Lilypond input
+yourself, to get a feel for how the program behaves.
+
+
+
To demonstrate what LilyPond input looks like, we start off with a
full-fledged, yet simple example. It is a convoluted version
of the famous minuet in J. S. Bach's @emph{Klavierb@"uchlein}. The file
MAJOR_VERSION=1
MINOR_VERSION=3
PATCH_LEVEL=151
-MY_PATCH_LEVEL=jcn2
+MY_PATCH_LEVEL=jcn3
# use the above to send patches: MY_PATCH_LEVEL is always empty for a
# released version.
\version "1.3.146"
-
-
\score
{
\notes \relative c'' {
static void evaluate_empty (Grob*);
DECLARE_SCHEME_CALLBACK (width_callback, (SCM smob, SCM axis));
DECLARE_SCHEME_CALLBACK (get_bar_size, (SCM ));
+ DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM ));
DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM ));
DECLARE_SCHEME_CALLBACK (center_on_spanned_callback, (SCM element, SCM axis));
};
me->add_dependency (b);
}
+MAKE_SCHEME_CALLBACK (Span_bar,brew_molecule,1);
+
+/**
+ * Limitations/Bugs:
+ *
+ * (1) Elements from 'me->get_grob_property ("elements")' must be
+ * ordered according to their y coordinates relative to their common
+ * axis group parent. Otherwise, the computation goes mad. (TODO:
+ * apply a sort algorithm that ensures this precondition.) However,
+ * until now, I have seen no case where lily has not fulfilled this
+ * precondition.
+ *
+ * (2) This method depends on bar_engraver not being removed from
+ * staff context. If bar_engraver is removed, the size of the staff
+ * lines is evaluated as 0, which results in a solid span bar line
+ * with faulty y coordinate.
+ *
+ */
+SCM
+Span_bar::brew_molecule (SCM smobbed_me)
+{
+ Grob *me = unsmob_grob (smobbed_me);
+ Span_bar::evaluate_glyph(me);
+ SCM glyph = me->get_grob_property (ly_symbol2scm ("glyph"));
+ String glyph_str = ly_scm2string (glyph);
+ SCM first_elt = me->get_grob_property ("elements");
+
+ // first walk: compute axis_group parent via common_refpoint () on all bars
+ Grob *refpoint = 0;
+ int staff_bar_count = 0;
+ for (SCM elts = first_elt;
+ elts != SCM_EOL;
+ elts = gh_cdr (elts))
+ {
+ SCM smobbed_staff_bar = gh_car (elts);
+ Grob *staff_bar = unsmob_grob (smobbed_staff_bar);
+ refpoint = (staff_bar_count > 0) ?
+ staff_bar->common_refpoint (refpoint, Y_AXIS) :
+ staff_bar;
+ staff_bar_count++;
+ }
+ /* assert: refpoint is an axis-group object */
+ Grob *axis_group = refpoint;
+
+ // second walk: collect span bar components;
+ // compute extent of axis_group
+ Real last_staff_bar_length;
+ Real *interstaff_bar_length = new Real[staff_bar_count];
+ Real *interstaff_bar_yoffs = new Real[staff_bar_count];
+ Molecule *interstaff_bar_molecule = new Molecule[staff_bar_count];
+ Real axis_group_extent = 0.0;
+ staff_bar_count = 0;
+ for (SCM elts = first_elt;
+ elts != SCM_EOL;
+ elts = gh_cdr (elts))
+ {
+ SCM smobbed_staff_bar = gh_car (elts);
+ SCM smobbed_staff_bar_molecule =
+ Bar::brew_molecule (smobbed_staff_bar);
+ Grob *staff_bar = unsmob_grob (smobbed_staff_bar);
+ interstaff_bar_yoffs[staff_bar_count] =
+ staff_bar->relative_coordinate (axis_group, (Axis)Y_AXIS);
+ if (smobbed_staff_bar_molecule != SCM_EOL)
+ {
+ Real staff_bar_length =
+ unsmob_molecule (smobbed_staff_bar_molecule)->
+ extent (Y_AXIS).length ();
+ if (staff_bar_count > 0)
+ {
+ // clone bar_molecule and fix y extent
+ interstaff_bar_length[staff_bar_count] =
+ interstaff_bar_yoffs[staff_bar_count] -
+ interstaff_bar_yoffs[staff_bar_count - 1] -
+ last_staff_bar_length;
+ SCM smobbed_interstaff_bar_molecule =
+ Bar::compound_barline (staff_bar, glyph_str,
+ interstaff_bar_length[staff_bar_count]).
+ smobbed_copy ();
+ interstaff_bar_molecule[staff_bar_count] =
+ *unsmob_molecule (smobbed_interstaff_bar_molecule);
+ }
+ else
+ {
+ interstaff_bar_molecule[staff_bar_count] = Molecule::Molecule ();
+ }
+ last_staff_bar_length = staff_bar_length;
+ }
+ else
+ {
+ last_staff_bar_length = 0;
+ interstaff_bar_length[staff_bar_count] = 0;
+ interstaff_bar_molecule[staff_bar_count] = Molecule::Molecule ();
+ }
+ axis_group_extent += last_staff_bar_length;
+ axis_group_extent += interstaff_bar_length[staff_bar_count];
+ staff_bar_count++;
+ }
+ // assert(abs(axis_group_extent -
+ // axis_group->extent (axis_group, Y_AXIS).length ()) < EPSILON);
+
+ // third walk: correct y axis on all span bar components;
+ // put all components into a single span bar molecule
+ Molecule span_bar_molecule = Molecule::Molecule ();
+ staff_bar_count = 0;
+ for (SCM elts = first_elt;
+ elts != SCM_EOL;
+ elts = gh_cdr (elts))
+ {
+ interstaff_bar_yoffs[staff_bar_count] +=
+ (axis_group_extent - interstaff_bar_length[staff_bar_count]) / 2;
+ interstaff_bar_molecule[staff_bar_count].//DEBUG
+ translate_axis (-1.0 PT, X_AXIS);//DEBUG
+ interstaff_bar_molecule[staff_bar_count].
+ translate_axis (interstaff_bar_yoffs[staff_bar_count], Y_AXIS);
+ span_bar_molecule.add_molecule (interstaff_bar_molecule[staff_bar_count]);
+ staff_bar_count++;
+ }
+
+ // clean-up & exit
+ delete interstaff_bar_length;
+ delete interstaff_bar_yoffs;
+ delete interstaff_bar_molecule;
+ return span_bar_molecule.smobbed_copy ();
+}
+
MAKE_SCHEME_CALLBACK (Span_bar,width_callback,2);
SCM
Span_bar::width_callback (SCM element_smob, SCM scm_axis)
(SpanBar . (
(break-align-symbol . Staff_bar)
(bar-size-procedure . ,Span_bar::get_bar_size)
- (molecule-callback . ,Bar::brew_molecule)
+ (molecule-callback . ,Span_bar::brew_molecule)
(visibility-lambda . ,begin-of-line-invisible)
(X-extent-callback . ,Span_bar::width_callback)
(Y-offset-callbacks . (,Span_bar::center_on_spanned_callback))
according to values of @code{defaultBarType}, @code{barAlways},
@code{barNonAuto} and @code{measurePosition}.
-Legal values are described in @ref{(lilypond-internals)bar-line-interface}.
+Valid values are described in @ref{(lilypond-internals)bar-line-interface}.
.")
cmd = "sh -c \'%s\'" % cmd
if verbose_p:
progress (_ ("Invoking `%s\'") % cmd)
- st = os.system (cmd) >> 8
+ st = os.system (cmd)
if st:
name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
msg = name + ': ' + _ ("command exited with value %d") % st