From: fred Date: Wed, 27 Mar 2002 00:34:33 +0000 (+0000) Subject: lilypond-1.3.116 X-Git-Tag: release/1.5.59~1042 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=359a78a9f86c840d7fcbdd3ba407e54adc3044f7;p=lilypond.git lilypond-1.3.116 --- diff --git a/Documentation/GNUmakefile b/Documentation/GNUmakefile index 1b3462f693..3a21d70c30 100644 --- a/Documentation/GNUmakefile +++ b/Documentation/GNUmakefile @@ -12,6 +12,10 @@ include $(depth)/make/stepmake.make default: local-doc +test-reg: + rm -f out-www/regression-test.html out-www/regression-test.texi + $(MAKE) out=www out-www/regression-test.html + local-WWW: copy-for-me txt-to-html $(outdir)/regression-test.ps.gz $(outdir)/regression-test.html footify copy-for-me: diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely index b2d8b87c0b..98d6a1b34d 100644 --- a/Documentation/regression-test.tely +++ b/Documentation/regression-test.tely @@ -61,6 +61,8 @@ and documenting bugfixes. @lilypondfile{glissando.ly} +@lilypondfile{follow-thread.ly} + @section Chord names @@ -83,6 +85,10 @@ and documenting bugfixes. @lilypondfile{beam-position.ly} +@lilypondfile{auto-beam-bar.ly} + +@lilypondfile{beam-rest.ly} + @lilypondfile{slur-nice.ly} @lilypondfile{slur-symmetry.ly} @lilypondfile{slur-symmetry-1.ly} diff --git a/Documentation/user/GNUmakefile b/Documentation/user/GNUmakefile index 906ea48fb5..e1b1d32f0d 100644 --- a/Documentation/user/GNUmakefile +++ b/Documentation/user/GNUmakefile @@ -18,7 +18,7 @@ PS_FILES = $(DVI_FILES:.dvi=.ps) $(OUTDOC_FILES:.doc=.ps) $(OUTTEX_FILES:.tex=. PS_GZ_FILES= $(addsuffix .gz, $(PS_FILES)) -# INFO_FILES = $(addprefix $(outdir)/, lilypond.info lilypond-internals.info) +INFO_FILES = $(addprefix $(outdir)/, lilypond.info lilypond-internals.info) STEPMAKE_TEMPLATES=tex texinfo documentation LOCALSTEPMAKE_TEMPLATES=lilypond ly diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 92b5299069..90e9e53e42 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -40,6 +40,7 @@ * Sound output:: Sound output * midilist:: midilist * Grobs:: Graphical objects +* Molecule:: Molecules * Pre-defined Identifiers:: Pre-defined Identifiers @c May be fragile. Better make single link to generated doco? * Interpretation contexts:(lilypond-internals)LilyPond interpretation contexts. @@ -2616,6 +2617,7 @@ provide shorthands for some settings. Most of them are in @end table @node Grobs, , , Reference Manual +@section Grobs This section is about Grobs (short for Graphical Objects), which are formatting objects used to create the final output. This material is @@ -2636,17 +2638,218 @@ there are many more ways of customizing Lily output, and since most of them involve Grobs in some form, this section explains some details of how grobs work. -Types of grob? +@menu +* What is a grob?:: +* Callbacks:: +* Setting grob properties:: +* Items and Spanners:: +* Pointer substitution:: +@end menu + +@node What is a grob?, , , Grobs + +All grobs have an X and Y-position on the page. These X and Y positions +are stored in a relative format, so they can easily be combined by +stacking them, hanging one grob to the side of another, and coupling +them into a grouping-grob. + +Each grob has a reference point, or parent: the position of a grob is +stored relative to that reference point. For example the X-reference +point of a staccato dot usually is the note head that it applies +to. Whenever the note head is moved, the staccato dot moves along +automatically. + +If you keep following offset reference points, you will always end up at +the root-object. This root object is called @code{Line_of_score} +@ref{(lilypond-internals)Element Line_of_score}, and it represents a +system (ie. a line of music). + +All grobs carry a set of grob-properties. In the Stem example above, +the property @code{direction} is set to value @code{1}. The function +that draws the symbol (@code{Stem::brew_molecule}) uses the value of +@code{direction} to determine how to print the stem and the flag. The +appearance of a grob is determined solely by the values of its +properties. + +Often, a grob also is associated with a symbol. On the other hand, Some +grobs do not print any symbols, but take care of grouping objects. For +example, there is a separate grob that stacks staffs vertically, so they +are not printed in overstrike. The NoteCollision @ref{(lilypond-internals)Element +NoteCollision} is another example of an abstract grob. It only moves +around chords, but doesn't print anything. + +A complete list of grob types is found in @ref{(lilypond-internals)Elements} + +Grobs are created in the "Interpreting music" phase, by things in +LilyPond called engravers. In this phase of the translation, a load of +grobs are created, and they are linked into a giant network of objects. +This network of grobs forms the "specification" of the print +problem. This problem is then solved: configurations, directions, +dimensions, line breaks, etc. are calculated. Finally, the printing +description in the form of Molecules (@ref{Molecule}) is extracted from +the network. These are then dumped into the output file + +@node Callbacks, , , Grobs + +Offsets of grobs are relative to a parent reference point. Most +positions are not known when an object is created, so these are +calculated as needed. This is done by adding a callback for a specific +direction. + +Suppose you have the following code in a .ly file. +@example + #(define (my-callback gr axis) + (* 2.0 (get-gr-property grob 'direction)) + ) + +.... + + \property Voice.Stem \override #'Y-offset-callbacks = #(list + my-callback) +@end example + +When the Y-offset of a Stem object is needed, LilyPond will +automatically execute all callbacks for that object. In this case, it +will find @code{my-callback}, and execute that. The result is that the +stem is translated by two staff spaces in its direction. + +(note: Y-offset-callbacks is also a property) + + +Offset callbacks can be stacked, ie. + +@example + \property .... \override #'Y-offset-callbacks = #(list + callback1 callback2 callback3) + +@end example + +The callbacks will be executed in the order callback3 callback2 +callback1. This is used for quantized positioning: the staccato dot is +above or below a note head, and it must not be on a staff-line. + +To achieve this, for the staccato there are two callbacks: one callback +that positions the grob above or below the note head, and one callback +that rounds the Y-position of the grob to the nearest open space. + +Similarly, the size of a grob are determined through callbacks, settable +with grob properties @code{X-extent-callback} and @code{Y-extent-callback}. +There can be only one extent-callback for each axis. No callback (value #f) +means: "empty in this direction". If you fill in a pair, that pair +hard-codes the extent in that coordinate. + + +@node Setting grob properties, , , Grobs + +Grob properties are stored as GUILE association lists, with symbols as +keys. From C++, element properties can be accessed using the functions + +@example + SCM get_grob_property (SCM) const; + void set_grob_property (const char * , SCM val); + void set_immutable_grob_property (const char * , SCM val); + void set_immutable_grob_property (SCM key, SCM val); + void set_grob_property (SCM , SCM val); + void set_grob_pointer (const char*, SCM val); + SCM remove_grob_property (const char* nm); +@end example + +In GUILE, LilyPond provides + +@example + ly-get-grob-property GROB SYMBOL + ly-set-grob-property GROB SYMBOL VALUE +@end example + +All lookup functions identify undefined properties with +end-of-list (ie. @code{'()} in Scheme or @code{SCM_EOL} in C) + +Properties are stored in two ways: +@itemize @bullet +@item mutable properties: +element properties that change from object to object. The storage of +these are private to a grob. Typically this is used to store lists of +pointers to other grobs + +@item immutable properties: +element properties that are shared across different grobs of the same +type. The storage is shared, and hence it is read-only. Typically, this +is used to store function callbacks, and values for shared element +properties are read from @file{scm/element-description.scm}. +@end itemize + +There are two ways to manually set grob properties. + +You can change immutable grob properties. This is done with the +\override syntax: + +@example + \property Voice.Stem \override #'direction = #1 +@end example + +This will push the entry @code{'(direction . 1)} on the immutable +property list for stems, in effect overriding the setting from +@file{scm/element-description.scm}. This can be undone by + +@example + \property Voice.stem \revert #'direction +@end example + +If you use this a lot, this gets old quickly. So we also have a +shorthand, + +@example + \property Context.GrobType \set #'prop = #VAL +@end example + +this does a @code{\revert} followed by a @code{\override} + +The second way is \outputproperty. This construct looks like + +@example + \context ContextName \outputproperty @var{pred} #@var{sym} = #@var{val} +@end example + +In this case, in every grob that satisfies @var{pred}, the property +assignment @var{sym} = @var{val} is done. For example + +@example + \outputproperty + #(lambda (gr) (string? (ly-get-grob-property gr + 'text))) + #'extra-offset = #'(-1.0 . 0.0) +@end example + +This shifts all elements that have a @code{text} property one staff +space to the left. + +@node Items and Spanners, , , Grobs -What is a grob? +Grobs can also be distinguished in their role in the horizontal spacing. +A lot of grobs define constraints on the spacing by their sizes. For +example, note heads, clefs, stems, and all other symbols with a fixed +shape. These grobs form a subtype called @code{Item}. -Where do they come from? +Other grobs have a shape that depends on the horizontal spacing. For +example, slur, beam, tie, etc. These grobs form a subtype called +@code{Spanner}. All spanners have two span-points (these must be +@code{Item}s), one on the left and one on the right. The left bound is +also the X-reference point. -How can you override? +Some items need special treatment for line breaking. For example, a +clef is normally only printed at the start of a line (ie. after a line +break). To model this, `breakable' items (clef, key signature, bar lines, +etc.) are copied twice. Then we have three versions of each breakable +item: one version if there is no line break, one version that is printed +before the line break (at the end of a system), one version that is +printed after the line break. -Items and Spanners? +Whether these versions are visible and take up space, is determined by +the outcome of the visibility-lambda. This is a function taking a +direction (-1, 0 or 1) and returns a cons of booleans, signifying wether +this grob should be transparent and invisible. -X and Y parents, offsets and extents. +@node Pointer substitution, , , Grobs @node Molecule, , , Reference Manual @@ -2667,7 +2870,8 @@ you merely have to look at the tex output of lily to see this. Internally these instructions are encoded in Molecules:@footnote{At some point LilyPond also contained Atom-objects, but they have been replaced by Scheme expressions.}. A molecule is an object that combines -dimension information (how large is this ?) with what-to-print-where. +dimension information (how large is this glyph ?) with +what-to-print-where. Conceptually, Molecules can be constructed from Scheme code, by translating a Molecule and by combining two molecules. In BNF notation: @@ -2680,4 +2884,7 @@ translating a Molecule and by combining two molecules. In BNF notation: @end example (refer to the C++ code for more details). All visible, -ie. non-transparent, grobs have a function to create Molecule. +ie. non-transparent, grobs have a callback to create a Molecule. The +name of the property is @code{molecule-callback}, and its value should +be a Scheme function taking one argument (the grob) and returning a +Molecule. diff --git a/VERSION b/VERSION index b94cd0f76c..07b942cf3e 100644 --- a/VERSION +++ b/VERSION @@ -1,7 +1,7 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=1 MINOR_VERSION=3 -PATCH_LEVEL=115 +PATCH_LEVEL=116 MY_PATCH_LEVEL= # use the above to send patches: MY_PATCH_LEVEL is always empty for a diff --git a/lily/paper-outputter.cc b/lily/paper-outputter.cc index 781215c200..0bf6c9db98 100644 --- a/lily/paper-outputter.cc +++ b/lily/paper-outputter.cc @@ -273,12 +273,15 @@ Paper_outputter::output_score_header_fields (Paper_def *paper) for (int i = 0; i < global_score_header_fields.size (); i++) { String key = global_score_header_fields[i]; - // SCM val = gh_assoc (ly_str02scm (key.ch_C ()), fields); SCM val = gh_assoc (ly_symbol2scm (key.ch_C ()), fields); String s; + /* Only write header field to file if it exists */ if (gh_pair_p (val)) - s = ly_scm2string (gh_cdr (val)); - output_score_header_field (base, key, s); + { + s = ly_scm2string (gh_cdr (val)); + /* Always write header field file, even if string is empty ... */ + output_score_header_field (base, key, s); + } } } } diff --git a/lily/text-spanner.cc b/lily/text-spanner.cc index c83551e556..5280703bad 100644 --- a/lily/text-spanner.cc +++ b/lily/text-spanner.cc @@ -24,7 +24,6 @@ - contination types (vert. star, vert. end) |-> eat volta-spanner - more styles - more texts/positions - - style: hairpin ? */ MAKE_SCHEME_CALLBACK (Text_spanner, brew_molecule, 1); @@ -35,22 +34,42 @@ Text_spanner::brew_molecule (SCM smob) Grob *me= unsmob_grob (smob); Spanner *spanner = dynamic_cast (me); - Real staff_space = Staff_symbol_referencer::staff_space (me); - + + + /* Ugh, must be same as Hairpin::brew_molecule. */ + Real padding = gh_scm2double (me->get_grob_property ("padding")); + Real broken_left = spanner->get_broken_left_end_align (); + Real width = spanner->spanner_length (); + width -= broken_left; + Drul_array broken; + Drul_array extra_off; Direction d = LEFT; do { - Paper_column* s = dynamic_cast(spanner->get_bound (d)); // UGH - if (s && s->musical_b ()) - broken[d] = false; - else - broken[d] = true; + Item *b = spanner->get_bound (d); + broken[d] = b->break_status_dir () != CENTER; + + if (!broken [d]) + { + + Interval e = b->extent (b, X_AXIS); + Real r = 0.0; + if (!e.empty_b ()) + r = e[-d] + padding; + width += d * r; + extra_off[d] = r; + } } while (flip (&d) != LEFT); - - SCM properties = Font_interface::font_alist_chain (me); + // FIXME: ecs tells us + width += gh_scm2double (me->get_grob_property ("width-correct")); + /* /Ugh */ + + + SCM properties = Font_interface::font_alist_chain (me); + SCM edge_text = me->get_grob_property ("edge-text"); Drul_array edge; if (gh_pair_p (edge_text)) @@ -65,6 +84,8 @@ Text_spanner::brew_molecule (SCM smob) } while (flip (&d) != LEFT); } + width -= edge[LEFT].extent (X_AXIS).length () + + edge[RIGHT].extent (X_AXIS).length (); Drul_array shorten; shorten[LEFT] = 0; @@ -73,19 +94,12 @@ Text_spanner::brew_molecule (SCM smob) SCM s = me->get_grob_property ("shorten"); if (gh_pair_p (s)) { - shorten[LEFT] = gh_scm2double (gh_car (s)) * staff_space; - shorten[RIGHT] = gh_scm2double (gh_cdr (s)) * staff_space; + shorten[LEFT] = gh_scm2double (gh_car (s)); + shorten[RIGHT] = gh_scm2double (gh_cdr (s)); } - Real broken_left = spanner->get_broken_left_end_align (); - Real width = spanner->spanner_length (); - Grob *bnd = spanner->get_bound (RIGHT); - width += bnd->extent (bnd, X_AXIS).length (); - width -= broken_left; width -= shorten[LEFT] + shorten[RIGHT]; - width -= edge[LEFT].extent (X_AXIS).length () - + edge[RIGHT].extent (X_AXIS).length (); - + if (width < 0) { warning (_ ("Text_spanner too small")); @@ -138,7 +152,7 @@ Text_spanner::brew_molecule (SCM smob) m.add_at_edge (X_AXIS, RIGHT, edge_line[RIGHT], 0); if (!edge[RIGHT].empty_b ()) m.add_at_edge (X_AXIS, RIGHT, edge[RIGHT], 0); - m.translate_axis (broken_left, X_AXIS); + m.translate_axis (broken_left + extra_off[LEFT], X_AXIS); return m.smobbed_copy (); } diff --git a/scm/translator-description.scm b/scm/translator-description.scm index 879b4ff090..77a42612e8 100644 --- a/scm/translator-description.scm +++ b/scm/translator-description.scm @@ -204,7 +204,7 @@ put on top of all staffs, and appears only at left side of the staff." 'Break_align_engraver (engraver-description "Break_align_engraver" - "Align graphic elements with corresponding break-align-symbols into groups, and order the groups according to breakAlignOrder" + "Align grobs with corresponding break-align-symbols into groups, and order the groups according to breakAlignOrder" '(BreakAlignment BreakAlignGroup LeftEdge) '( breakAlignOrder @@ -285,7 +285,7 @@ If omitted, then dots appear on top of the notes. "Dynamic_engraver" "" '(DynamicLineSpanner - DynamicText Crescendo + DynamicText Hairpin TextSpanner) '( ))) @@ -484,7 +484,7 @@ making a single line staff that demonstrates the rhythm of a melody." (engraver-description "Property_engraver" "This is a engraver that converts \property settings into -back-end element-property settings. Example: Voice.stemLength will set +back-end grob-property settings. Example: Voice.stemLength will set #'length in all Stem objects. Due to CPU and memory requirements, the use of this engraver is deprecated." diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index 763aa79fa1..4d6b0e58f8 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -348,7 +348,6 @@ output_dict= { # should also support fragment in 'output-all': r""" -@include %(fn)s.texidoc @tex \catcode`\@=12 \input lilyponddefs @@ -776,7 +775,7 @@ def schedule_lilypond_block (chunk): needed_filetypes.append('png') if 'eps' in opts and not ('eps' in needed_filetypes): needed_filetypes.append('eps') - outname = os.path.join(g_outdir, basename) + pathbase = os.path.join (g_outdir, basename) def f(base, ext1, ext2): a = os.path.isfile(base + ext2) if (os.path.isfile(base + ext1) and @@ -786,11 +785,11 @@ def schedule_lilypond_block (chunk): not os.path.isfile(base + ext2): return 1 todo = [] - if 'tex' in needed_filetypes and f(outname, '.ly', '.tex'): + if 'tex' in needed_filetypes and f(pathbase, '.ly', '.tex'): todo.append('tex') - if 'eps' in needed_filetypes and f(outname, '.tex', '.eps'): + if 'eps' in needed_filetypes and f(pathbase, '.tex', '.eps'): todo.append('eps') - if 'png' in needed_filetypes and f(outname, '.eps', '.png'): + if 'png' in needed_filetypes and f(pathbase, '.eps', '.png'): todo.append('png') newbody = '' if 'verbatim' in opts: @@ -806,8 +805,10 @@ def schedule_lilypond_block (chunk): else: s = 'output-tex' else: # format == 'texi' - s = 'output-all' - newbody = newbody + get_output(s) % {'fn': basename } + if os.path.isfile (pathbase + '.texidoc'): + newbody = newbody + '\n@include %s.texidoc' % basename + s = 'output-all' + newbody = newbody + get_output (s) % {'fn': basename } return ('lilypond', newbody, opts, todo, basename) def process_lilypond_blocks(outname, chunks):#ugh rename