From 7367bac15e22b0b2ae9a1a0a7f849860f9d66f45 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Wed, 20 Dec 2000 17:08:20 +0100 Subject: [PATCH] release: 1.3.119 ======= * Added some feature examples. * Bugfix for \partial and auto-beamer. * Bugfixes: warnings. * More feature examples. * Renamed some scm files. * Some more documentation fixes (move hacking.texi into normal documentation.) * Bugfix: header protection in parser.yy 1.3.117. --- CHANGES | 23 +- Documentation/hacking.texi | 655 +----------------- Documentation/user/development.itexi | 866 ++++++++++++++++++++++++ Documentation/user/lilypond.tely | 4 + Documentation/user/refman.itely | 366 +--------- VERSION | 4 +- input/test/number-staff-lines.ly | 22 +- lily/all-font-metrics.cc | 9 +- lily/font-metric.cc | 2 +- lily/include/engraver.hh | 5 +- lily/include/font-metric.hh | 3 +- lily/include/tfm.hh | 2 + lily/parser.yy | 4 +- lily/property-engraver.cc | 4 + lily/score.cc | 11 +- lily/translator-group.cc | 12 +- make/out/lilypond.lsm | 8 +- make/out/lilypond.spec | 4 +- po/nl.po | 2 +- scm/backend-property.scm | 0 scm/element-descriptions.scm | 0 scm/interface.scm | 0 scm/music-property.scm | 0 scm/translator-properties.scm | 0 scm/translator-property-description.scm | 4 +- scripts/lilypond-book.py | 6 +- 26 files changed, 972 insertions(+), 1044 deletions(-) create mode 100644 Documentation/user/development.itexi delete mode 100644 scm/backend-property.scm delete mode 100644 scm/element-descriptions.scm delete mode 100644 scm/interface.scm delete mode 100644 scm/music-property.scm delete mode 100644 scm/translator-properties.scm diff --git a/CHANGES b/CHANGES index 144b97e579..48dd80cd3e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,22 +1,21 @@ -1.3.118.jcn3 -============ - -* More feature examples. - -* Renamed some scm files. - -1.3.118.jcn2 -============ +1.3.119 +======= * Added some feature examples. * Bugfix for \partial and auto-beamer. -1.3.118.jcn1 -============ - * Bugfixes: warnings. +* More feature examples. + +* Renamed some scm files. + +* Some more documentation fixes (move hacking.texi into normal +documentation.) + +* Bugfix: header protection in parser.yy + 1.3.117.mb1 =========== diff --git a/Documentation/hacking.texi b/Documentation/hacking.texi index 80aa3de327..63583e9134 100644 --- a/Documentation/hacking.texi +++ b/Documentation/hacking.texi @@ -3,26 +3,10 @@ @settitle LilyPond internals -@node Top, LilyPond internals, (dir), (dir) +@node Top, , (dir), (dir) @top -@menu -* LilyPond internals:: -* Overview:: -* Request_engraver:: -* Coding standards:: -* Making patches:: -* Localisation:: -@end menu - -@node LilyPond internals, , Top, Top - -@menu -* Overview:: Overview -* Request_engraver:: Request_engraver -@end menu - @chapter Getting involved @@ -96,640 +80,3 @@ scanning sheet music. @chapter LilyPond internals - -@node Overview, , , Top -@section Overview - -GNU LilyPond is a "multi-pass" system. - -@table @samp - -@item Parsing: - -No difficult algorithms. The .ly file is read, and converted to a list -of @code{Scores}, which each contain @code{Music} and paper/midi-definitions. - -@item Interpreting music - -The music is walked through in time-order. The iterators which do the -walking report Music to Translators which use this information to -create elements, either MIDI or "visual" elements. The translators -form a hierarchy; the ones for paper output are Engravers, for MIDI -Performers. - -The translators swallow Music (mostly atomic gobs called Requests), -create elements, broadcast them to other translators on higher or same -level in the hierarchy: - -The stem of a voice A is broadcast to the staff which contains A, but -not to the stems, beams and noteheads of a different voice (say B) or -a different staff. The stem and noteheads of A are coupled, because -the the Note_heads_engraver broadcasts its heads, and the Stem_engraver catches -these. - -The engraver which agrees to handle a request decides whether to to -honor the request, ignore it, or merge it with other requests. Merging -of requests is preferably done with other requests done by members of -the same voicegroups (beams, brackets, stems). In this way you can put -the voices of 2 instruments in a conductor's score so they make chords -(the Beam requests of both instruments will be merged). - -@item Prebreaking - -Breakable stuff (eg. clefs and bars) are copied into pre and -postbreaks. - -@item Preprocessing - -Some dependencies are resolved, such as the direction of stems, beams, -and "horizontal" placement issues (the order of clefs, keys etc, -placement of chords in multi-voice music), - -@item Break calculation: - -The lines and horizontal positions of the columns are determined. - -@item Breaking - -Through some magical interactions with Line_of_score and Super_elem -(check out the source) the "lines" are produced. - -All other spanners can figure across which lines they are spread. If -applicable, they break themselves into pieces. After this, each piece -(or, if there are no pieces, the original spanner itself) throws out -any dependencies which are in the wrong line. - -@item Postprocesing: - -Some items and all spanners need computation after the Paper_column -positions are determined. Examples: slurs, vertical positions of -staffs. - -@item Output paper - -@end table - - -@node Request_engraver, , , Top -@section Request_engraver - -In the previous section the idea of Request has been explained, but -this only solves one half of the problem. The other half is deciding -which requests should be honored, which should merged with other -requests, and which should be ignored. Consider this input - -@example - - \type Staff < % chord - @{ \meter 2/4; [c8 c8] @} - @{\meter 2/4; [e8 e8] @} - > - -@end example - -Both the cs and es are part of a staff (they are in the same -Voice_group), so they should share meters, but the two [ ] pairs -should be merged. - -The judge in this "allocation" problem a set of brokers: the requests -are transmitted to so-called engravers which respond if they want to -accept a request eg, the @code{Notehead_engraver} will accept -@code{Note_req}s, and turn down @code{Slur_req}s. If the Music_iterator -cannot find a engraver that wants the request, it is junked (with a -warning message). - -After all requests have been either assigned, or junked, the Engraver -will process the requests (which usually means creating an @code{Item} -or @code{Spanner}). If a @code{Request_engraver} creates something, it -tells the enclosing context. If all items/spanners have been created, -then each Engraver is notified of any created Score_element, via a -broadcasting system. - -@unnumberedsubsec example: - -@example - - c4 - -@end example - -produces: - -@example - - Note_request (duration 1/4) - Stem_request (duration 1/4) - -@end example - -Note_request will be taken by a @code{Notehead_engraver}, stem_request -will be taken by a @code{Stem_beam_engraver}. @code{Notehead_engraver} -creates a @code{Notehead}, @code{Stem_beam_engraver} creates a -@code{Stem}. Both announce this to the Staff_engraver. Staff_engraver -will tell @code{Stem_beam_engraver} about the @code{Notehead}, which -will add the @code{Notehead} to the @code{Stem} it just created. - -To decide on merging, several engravers have been grouped. Please -check @file{init/engraver.ly}. - -@node Coding standards, , , Top - -@chapter CodingStyle - standards while programming for GNU LilyPond - -Functions and methods do not return errorcodes: they never crash, but -report a programming_error and try to carry on.q - - -@unnumberedsubsec Languages - -C++ and Python are preferred. Python code should use an indent of 8, -using TAB characters. - -@unnumberedsubsec Filenames - -Definitions of classes that are only accessed via pointers -(*) or references (&) shall not be included as include files. - -filenames - -@example - ".hh" Include files - ".cc" Implementation files - ".icc" Inline definition files - ".tcc" non inline Template defs -@end example - -in emacs: - -@example - (setq auto-mode-alist - (append '(("\\.make$" . makefile-mode) - ("\\.cc$" . c++-mode) - ("\\.icc$" . c++-mode) - ("\\.tcc$" . c++-mode) - ("\\.hh$" . c++-mode) - ("\\.pod$" . text-mode) - ) - auto-mode-alist)) -@end example - - -The class Class_name_abbreviation is coded in @file{class-name-abbr.*} - -@unnumberedsubsec Indentation - -Standard GNU coding style is used. In emacs: - -@example - (add-hook 'c++-mode-hook - '(lambda() (c-set-style "gnu") - ) - ) -@end example - -If you like using font-lock, you can also add this to your @file{.emacs}: - -@example - (setq font-lock-maximum-decoration t) - (setq c++-font-lock-keywords-3 - (append - c++-font-lock-keywords-3 - '(("\\b\\([a-zA-Z_]+_\\)\\b" 1 font-lock-variable-name-face) - ("\\b\\([A-Z]+[a-z_]+\\)\\b" 1 font-lock-type-face)) - )) -@end example - -@unnumberedsubsec Classes and Types - -@example - This_is_a_class -@end example - -@unnumberedsubsec Members - -@example - Class::member () - Type Class::member_type_ - Type Class::member_type () -@end example - -the @code{type} is a Hungarian notation postfix for @code{Type}. See below - -@unnumberedsubsec Macros - -Macros should be written completely in uppercase - -@unnumberedsubsec Broken code - -Broken code (hardwired dependencies, hardwired constants, slow -algorithms and obvious limitations) should be marked as such: either -with a verbose TODO, or with a short "ugh" comment. - -@unnumberedsec Hungarian notation naming convention - -Proposed is a naming convention derived from the so-called -@emph{Hungarian Notation}. Macros, @code{enum}s and @code{const}s are all -uppercase, with the parts of the names separated by underscores. - -The hungarian notation is to be used when variables are not declared -near usage (mostly in member variables and functions). - -@unnumberedsubsec Types - -@table @samp -@item @code{byte} - unsigned char. (The postfix _by is ambiguous) -@item @code{b} - bool -@item @code{bi} - bit -@item @code{ch} - char -@item @code{f} - float -@item @code{i} - signed integer -@item @code{str} - string class -@item @code{sz} - Zero terminated c string -@item @code{u} - unsigned integer -@end table - -@unnumberedsubsec User defined types - -@example - - /** Slur blah. blah. - (slur) - */ - class Slur @{@}; - Slur* slur_p = new Slur; - -@end example - -@unnumberedsubsec Modifiers - -The following types modify the meaning of the prefix. -These are preceded by the prefixes: - -@table @samp -@item @code{a} - array -@item @code{array} - user built array. -@item @code{c} - const. Note that the proper order is @code{Type const} - i.s.o. @code{const Type} -@item @code{C} - A const pointer. This would be equivalent to @code{_c_l}, but since any - "const" pointer has to be a link (you can't delete a const pointer), - it is superfluous. -@item @code{l} - temporary pointer to object (link) -@item @code{p} - pointer to newed object -@item @code{r} - reference -@end table - -@unnumberedsubsec Adjective - -Adjectives such as global and static should be spelled out in full. -They come before the noun that they refer to, just as in normal english. - -@example - -foo_global_i: a global variable of type int commonly called "foo". - -@end example - -static class members do not need the static_ prefix in the name (the -Class::var notation usually makes it clear that it is static) - -@table @samp -@item @code{loop_i} - Variable loop: an integer -@item @code{u} - Temporary variable: an unsigned integer -@item @code{test_ch} - Variable test: a character -@item @code{first_name_str} - Variable first_name: a String class object -@item @code{last_name_ch_a} - Variable last_name: a @code{char} array -@item @code{foo_i_p} - Variable foo: an @code{Int*} that you must delete -@item @code{bar_i_l} - Variable bar: an @code{Int*} that you must not delete -@end table - -Generally default arguments are taboo, except for nil pointers. - -The naming convention can be quite conveniently memorised, by -expressing the type in english, and abbreviating it - -@example - - static Array foo - -@end example - -@code{foo} can be described as "the static int-pointer user-array", so you get - -@example - - foo_static_l_arr - -@end example - - -@unnumberedsec Miscellaneous - -For some tasks, some scripts are supplied, notably creating patches, a -mirror of the website, generating the header to put over cc and hh -files, doing a release. - -Use them. - -@node Making patches, , , Top - - -@unnumberedsec Track and distribute your code changes - -This page documents how to distribute your changes to GNU lilypond - -We would like to have unified context diffs with full pathnames. A -script automating supplied with Lily. - -Distributing a change normally goes like this: - -@itemize @bullet -@item make your fix/add your code -@item Add changes to CHANGES, and add yourself to Documentation/topdocs/AUTHORS.texi -@item generate a patch, -@item e-mail your patch to one of the mailing lists - gnu-music-discuss@@gnu.org or bug-gnu-music@@gnu.org -@end itemize - -Please do not send entire files, even if the patch is bigger than the -original. A patch makes it clear what is changed, and it won't -overwrite previous (not yet released) changes. - -@unnumberedsec Generating a patch - -Simple version: run - -@example - make -C lilypond-x.y.z/ distclean - make -C lilypond-x.y.z.NEW/ distclean - diff -urN lilypond-x.y.z/ lilypond-x.y.z.NEW/ -@end example - -Complicated (but automated) version: - -In @file{VERSION}, set MY_PATCH_LEVEL: - -@example - - VERSION: - ... - MY_PATCH_LEVEL=jcn1 - -@end example - -In @file{CHANGES}, enter a summary of changes: - -@example - pl 0.1.73.jcn1 - - added PATCHES.texi -@end example - -Then, from the top of Lily's source tree, type - -@example - make release -@end example - -These handy python scripts assume a directory structure which looks -like: - -@example - - lilypond -> lilypond-x.y.z # symlink to development directory - lilypond-x.y.z/ # current development - patches/ # patches between different releases - releases/ # .tar.gz releases - -@end example - -(Some scripts also assume this lives in @file{$HOME/usr/src}). - - -@unnumberedsec Applying patches - - -If you're following LilyPond development regularly, you probably want to -download just the patch for each subsequent release. -After downloading the patch (into the patches directory, of course), simply -apply it: - -@example - - gzip -dc ../patches/lilypond-0.1.74.diff.gz | patch -p1 -E - -@end example - -and don't forget to make automatically generated files: - -@example - - autoconf footnote(patches don't include automatically generated files, - i.e. file(configure) and files generated by file(configure).) - - configure - -@end example - -@node Localisation, , , Top - -@chapter Localisation - User messages in LilyPond - -@section Introduction - -This document provides some guidelines for uniformising user messages. -In the absence of other standards, we'll be using these rules when coding -for for LilyPond@footnote{ -In addition to the C++ coding standards that come with Lily -}. Hopefully, this can be replaced by general GNU -guidelines in the future. - -Not-preferred messages are marked with @code{+}. -By convention, agrammatical examples are marked with @code{*}. - - -@section Guidelines - -@itemize @bullet - -@item -Every message to the user should be localised (and thus be marked -for localisation). This includes warning and error messages. - -@item -Don't localise/gettextify: - -@itemize @minus -@item @code{programming_error ()}s -@item @code{programming_warning ()}s -@item debug strings -@item output strings (PostScript, TeX)@footnote{ -This may seem ridiculously obvious, however, makeinfo-3.12s localises -output strings. Sending bug report now ---jcn -} -@end itemize - - - -@item -Messages to be localised must be encapsulated in @code{_ (STRING)} -or @code{_f (FORMAT, ...)}. Eg: - -@example -warning (_ ("Need music in a score")); -error (_f ("Can't open file: `%s'", file_name)); -@end example - -In some rare cases you may need to call @code{gettext ()} by hand. -This happens when you pre-define (a list of) string constants for later -use. In that case, you'll probably also need to mark these string -constants for translation, using @code{_i (STRING)}. The @code{_i} -macro is a no-op, it only serves as a marker for @file{xgettext}. - -@example -char const* messages[] = @{ - _i ("enable debugging output"), - _i ("ignore lilypond version"), - 0 -@}; - -void -foo (int i) -@{ - puts (gettext (messages [i])); -@} -@end example - -See also -@file{flower/getopt-long.cc} and @file{lily/main.cc}. - -@item -Don't use leading or trailing whitespace in messages. - -@item -Messages containing a final verb, or a gerund (@code{-ing}-form) -always start with a capital. Other (simpler) messages start with -a lowercase letter: - -@example -The word `foo' is not declared. -`foo': not declared. -Not declaring: `foo'. -@end example - -@item -To avoid having a number of different messages for the same situation, -we'll use quoting like this @code{"message: `%s'"} for all strings. -Numbers are not quoted: - -@example -_f ("Can't open file: `%s'", name_str) -_f ("Can't find charater number: %d", i) -@end example - -@item -Think about translation issues. -In a lot of cases,it's better to translate a whole message. -The english grammar mustn't be imposed on the translator. -So, iso - -@example -_ ("Stem at ") + moment.str () + _(" doen't fit in beam") -@end example - -@noindent -have - -@example -_f ("Stem at %s doen't fit in beam", moment.str ()) -@end example - -@item -Split up multi-sentence messages, whenever possible. Instead of - -@example -warning (_f ("out of tune! Can't find: `%s', "Key_engraver")); - -warning (_f ("Can't find font `%s', loading default", - font_name)); -@end example - -@noindent -rather say: - -@example -warning (_ ("out of tune:"); -warning (_f ("Can't find: `%s', "Key_engraver")); - -warning (_f ("Can't find font: `%s', font_name)); -warning (_f ("Loading default font")); -@end example - -@item -If you must have multiple-sentence messages, use full punctuation. -Use two spaces after end of sentence punctuation. -No punctuation (esp. period) is used at the end of simple messages. - -@example - _f ("Non-matching braces in text `%s', adding braces", text) - _ ("Debug output disabled. Compiled with NPRINT.") - _f ("Huh? Not a Request: `%s'. Ignoring.", request) -@end example - -@item -Don't modularise too much; a lot of words cannot be translated -without context. -It's probably safe to treat most occurences of words like -stem, beam, crescendo as separately translatable words. - -@item -When translating, it is preferrable to put interesting information -at the end of the message, rather than embedded in the middle. -This especially applies to frequently used messages, even if this -would mean sacrificing a bit of eloquency. This holds for original -messages too, of course. - -@example - en: can't open: `foo.ly' -+ nl: kan `foo.ly' niet openen (1) - kan niet openen: `foo.ly'* (2) - niet te openen: `foo.ly'* (3) -@end example - -The first nl message, although gramatically and stylishly correct, -is not friendly for parsing by humans (even if they speak dutch). -I guess we'd prefer something like (2) or (3). - -@item -Please don't run make po/po-update with GNU gettext < 0.10.35 - -@end itemize - -@bye - - - -@bye - - diff --git a/Documentation/user/development.itexi b/Documentation/user/development.itexi new file mode 100644 index 0000000000..e01549b272 --- /dev/null +++ b/Documentation/user/development.itexi @@ -0,0 +1,866 @@ +@node Internals, , , top + +@menu +* Conversion stages:: Lilypond is a multi-pass program. + +* Grobs:: Graphical object +* Engraver:: +* Music_iterator:: +* Music:: +* Molecule:: Molecule are stand-alone descriptions of output +@end menu + + +@node Conversion stages, , , Internals + +When translating the input to notation, there are number of distinct +phases. We list them here: + + +@table @samp + +@item Parsing: + +The .ly file is read, and converted to a list of @code{Scores}, which +each contain @code{Music} and paper/midi-definitions. + +@item Interpreting music + +All music events are "read" in the same order as they would be played +(or read from paper). At every step of the interpretation, musical +events are delivered to +interpretation contexts, +@cindex engraver +which use them to build grobs (or MIDI objects, for MIDI output). + +@item Prebreaking + +At places where line breaks may occur, clefs and bars are prepared for +a possible line break. + +@item Preprocessing + +In this stage, all information that is needed to determine line breaking +is computed. + +@item Break calculation: + +The lines and horizontal positions of the columns are determined. + +@item Breaking + +Relations between all grobs are modified to reflect line breaks. See +also @ref{Pointer substitution}. + +@item Outputting: + +All vertical dimensions and spanning objects are computed, and all grobs +are output, line by line. + +@end table + + +@node Grobs, , , Internals +@section Grobs + +This section is about Grobs (short for Graphical Objects), which are +formatting objects used to create the final output. This material is +normally the domain of LilyPond gurus, but occasionally, a normal user +also has to deal with grobs. + +The most simple interaction with Grobs are when you use +@code{\override}: + +@example + \property Voice.Stem \override #'direction = #1 +@end example + +This piece of lily input causes all stem objects to be stem-up +henceforth. In effect, you are telling lilypond to extend the defintion +of the "Stem" grob with the setting @code{direction := 1}. Of course +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. + +@menu +* What is a grob?:: +* Callbacks:: +* Setting grob properties:: +* Items and Spanners:: +* Pointer substitution:: +@end menu + +@node What is a grob?, , , Grobs + +In music notation, lots of symbols are related in some way. You can +think of music notation as a graph where nodes are formed by the +symbols, and the arcs by their relations. A grob is node in that +graph. A grob stores references to other grobs, the directed edges in +the graph. + +The objective of this big graph of grobs, is to specify the notation +problem. The solution of this problem is a description of the printout +that is in closed form, i.e. but a list of values. These values are +Molecules. (see @ref{Molecules}) + +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. This mechanism is rather clumsy to use, but it allows +you tweak any setting of any grob. + +@node Items and Spanners, , , Grobs +@unnumberedsubsec Items and Spanners + +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}. + +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. + +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. + +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. + +@node Pointer substitution, , , Grobs +@unnumberedsubsec Pointer substitution + + +Symbols that cross line-breaks (such as slurs) cause some more +complications. When a spanner crosses a line-break, then the spanner is +"broken into pieces", for every line that the spanner is in, a copy of +the grob is made. A substitution process redirects all grob-reference +so that spanner grob will only reference other grobs in the same line. + +@node Engraver, , , Internals + +@node Music_iterator, , , Internals + +@node Music, , , Internals + +@node Molecule, , , Internals + +The objective of any typesetting system is to put ink on paper in the +right places. For LilyPond, this final stage is left to the TeX and the +printer subsystem. For lily, the last stage in processing a score is +outputting a description of what to put where. This description roughly +looks like + +@example + PUT glyph AT (x,y) + PUT glyph AT (x,y) + PUT glyph AT (x,y) +@end example + +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 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: + +@example + Molecule = COMBINE Molecule Molecule + | TRANSLATE Offset Molecule + | GLYPH-DESCRIPTION + ; +@end example + +(refer to the C++ code for more details). All visible, +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. + + + +@node Development, , , top +@chapter Development + +@menu +* Coding standards:: +* Making patches:: +* Localisation:: +@end menu + +@section CodingStyle - standards while programming for GNU LilyPond + +As a general rule, you should always try to continue computations, even +if there is some kind of error. When the program stops, it is often very +hard for a user to pinpoint what part of the input causes an +error. Finding the culprit is much easier if there is some viewable +output. + +So functions and methods do not return errorcodes, they never crash, but +report a programming_error and try to carry on. + +@unnumberedsubsec Languages + +C++ and Python are preferred. Python code should use an indent of 8, +using TAB characters. + +@unnumberedsubsec Filenames + +Definitions of classes that are only accessed via pointers +(*) or references (&) shall not be included as include files. + +filenames + +@example + ".hh" Include files + ".cc" Implementation files + ".icc" Inline definition files + ".tcc" non inline Template defs +@end example + +in emacs: + +@example + (setq auto-mode-alist + (append '(("\\.make$" . makefile-mode) + ("\\.cc$" . c++-mode) + ("\\.icc$" . c++-mode) + ("\\.tcc$" . c++-mode) + ("\\.hh$" . c++-mode) + ("\\.pod$" . text-mode) + ) + auto-mode-alist)) +@end example + + +The class Class_name is coded in @file{class-name.*} + +@unnumberedsubsec Indentation + +Standard GNU coding style is used. In emacs: + +@example + (add-hook 'c++-mode-hook + '(lambda() (c-set-style "gnu") + ) + ) +@end example + +If you like using font-lock, you can also add this to your @file{.emacs}: + +@example + (setq font-lock-maximum-decoration t) + (setq c++-font-lock-keywords-3 + (append + c++-font-lock-keywords-3 + '(("\\b\\([a-zA-Z_]+_\\)\\b" 1 font-lock-variable-name-face) + ("\\b\\([A-Z]+[a-z_]+\\)\\b" 1 font-lock-type-face)) + )) +@end example + +@unnumberedsubsec Classes and Types + +@example + This_is_a_class +@end example + +@unnumberedsubsec Members + +@example + Class::member () + Type Class::member_type_ + Type Class::member_type () +@end example + +the @code{type} is a Hungarian notation postfix for @code{Type}. See below + +@unnumberedsubsec Macros + +Macro names should be written in uppercase completely. + +@unnumberedsubsec Broken code + +Try not to write broken code. This includes hardwired dependencies, +hardwired constants, slow algorithms and obvious limitations. If you can +not avoid it, mark the place clearly, and add a comment explaining +shortcomings of the code. + +@unnumberedsec Hungarian notation naming convention + +The C++ part of LilyPond uses a naming convention derived from the +so-called @emph{Hungarian Notation}. Macros, @code{enum}s and +@code{const}s are all uppercase, with the parts of the names separated +by underscores. + +The hungarian notation is to be used when variables are not declared +near usage (mostly in member variables and functions). + +@unnumberedsubsec Types + +@table @samp +@item @code{byte} + unsigned char. (The postfix _by is ambiguous) +@item @code{b} + bool +@item @code{bi} + bit +@item @code{ch} + char +@item @code{f} + float +@item @code{i} + signed integer +@item @code{str} + string class +@item @code{sz} + Zero terminated c string +@item @code{u} + unsigned integer +@end table + +@unnumberedsubsec User defined types + +@example + + /* + Slur blah. blah. + */ + class Slur @{ + ... + @}; + Slur* slur_p = new Slur; + +@end example + +@unnumberedsubsec Modifiers + +The following types modify the meaning of the prefix. +These are preceded by the prefixes: + +@table @samp +@item @code{a} + array +@item @code{arr} + user built array. +@item @code{c} + const. Note that the proper order is @code{Type const} + and not @code{const Type} +@item @code{C} + A const pointer. This would be equivalent to @code{_c_l}, but since any + "const" pointer has to be a link (you can't delete a const pointer), + it is superfluous. +@item @code{l} + temporary pointer to object (link) +@item @code{p} + pointer to newed object +@item @code{r} + reference +@end table + +@unnumberedsubsec Adjective + +Adjectives such as global and static should be spelled out in full. +They come before the noun that they refer to, just as in normal english. + +@example + +foo_global_i: a global variable of type int commonly called "foo". + +@end example + +static class members do not need the static_ prefix in the name (the +Class::var notation usually makes it clear that it is static) + +@table @samp +@item @code{loop_i} + Variable loop: an integer +@item @code{u} + Temporary variable: an unsigned integer +@item @code{test_ch} + Variable test: a character +@item @code{first_name_str} + Variable first_name: a String class object +@item @code{last_name_ch_a} + Variable last_name: a @code{char} array +@item @code{foo_i_p} + Variable foo: an @code{Int*} that you must delete +@item @code{bar_i_l} + Variable bar: an @code{Int*} that you must not delete +@end table + +Generally default arguments are taboo, except for nil pointers. + +The naming convention can be quite conveniently memorised, by +expressing the type in english, and abbreviating it + +@example + + static Array foo + +@end example + +@code{foo} can be described as "the static int-pointer user-array", so you get + +@example + + foo_static_l_arr + +@end example + + +@unnumberedsec Miscellaneous + +For some tasks, some scripts are supplied, notably creating patches, a +mirror of the website, generating the header to put over cc and hh +files, doing a release. + +Use them. + +@node Making patches, , , Top + + +@unnumberedsec Track and distribute your code changes + +This page documents how to distribute your changes to GNU lilypond + +We would like to have unified context diffs with full pathnames. A +script automating supplied with Lily. + +Distributing a change normally goes like this: + +@itemize @bullet +@item make your fix/add your code +@item Add changes to CHANGES, and add yourself to Documentation/topdocs/AUTHORS.texi +@item generate a patch, +@item e-mail your patch to one of the mailing lists + gnu-music-discuss@@gnu.org or bug-gnu-music@@gnu.org +@end itemize + +Please do not send entire files, even if the patch is bigger than the +original. A patch makes it clear what is changed, and it won't +overwrite previous (not yet released) changes. + +@unnumberedsec Generating a patch + +Simple version: run + +@example + make -C lilypond-x.y.z/ distclean + make -C lilypond-x.y.z.NEW/ distclean + diff -urN lilypond-x.y.z/ lilypond-x.y.z.NEW/ +@end example + +Complicated (but automated) version: + +In @file{VERSION}, set MY_PATCH_LEVEL: + +@example + + VERSION: + ... + MY_PATCH_LEVEL=jcn1 + +@end example + +In @file{CHANGES}, enter a summary of changes: + +@example + 0.1.73.jcn1 + =========== + + * A concise, yet clearly readable description of what changed. + +@end example + +Then, from the top of Lily's source tree, type + +@example + make release +@end example + +These handy python scripts assume a directory structure which looks +like: + +@example + + lilypond -> lilypond-x.y.z # symlink to development directory + lilypond-x.y.z/ # current development + patches/ # patches between different releases + releases/ # .tar.gz releases + +@end example + +@unnumberedsec Applying patches + +[outdated: please use xdeltas] + +If you're following LilyPond development regularly, you probably want to +download just the patch for each subsequent release. +After downloading the patch (into the patches directory, of course), simply +apply it: + +@example + + gzip -dc ../patches/lilypond-0.1.74.diff.gz | patch -p1 -E + +@end example + +and don't forget to make automatically generated files: + +@example + + autoconf footnote(patches don't include automatically generated files, + i.e. file(configure) and files generated by file(configure).) + + configure + +@end example + +@node Localisation, , , Top + +@chapter Localisation - User messages in LilyPond + +@section Introduction + +This document provides some guidelines for uniformising user messages. +In the absence of other standards, we'll be using these rules when coding + for LilyPond. Hopefully, this can be replaced by general GNU +guidelines in the future. + +Not-preferred messages are marked with @code{+}. By convention, +agrammatical examples are marked with @code{*}. + +@section Guidelines + +@itemize @bullet + +@item +Every message to the user should be localised (and thus be marked +for localisation). This includes warning and error messages. + +@item +Don't localise/gettextify: + +@itemize @minus +@item @code{programming_error ()}s +@item @code{programming_warning ()}s +@item debug strings +@item output strings (PostScript, TeX) +@end itemize + +@item +Messages to be localised must be encapsulated in @code{_ (STRING)} +or @code{_f (FORMAT, ...)}. Eg: + +@example +warning (_ ("Need music in a score")); +error (_f ("Can't open file: `%s'", file_name)); +@end example + +In some rare cases you may need to call @code{gettext ()} by hand. +This happens when you pre-define (a list of) string constants for later +use. In that case, you'll probably also need to mark these string +constants for translation, using @code{_i (STRING)}. The @code{_i} +macro is a no-op, it only serves as a marker for @file{xgettext}. + +@example +char const* messages[] = @{ + _i ("enable debugging output"), + _i ("ignore lilypond version"), + 0 +@}; + +void +foo (int i) +@{ + puts (gettext (messages [i])); +@} +@end example + +See also +@file{flower/getopt-long.cc} and @file{lily/main.cc}. + +@item +Don't use leading or trailing whitespace in messages. + +@item +Messages containing a final verb, or a gerund (@code{-ing}-form) +always start with a capital. Other (simpler) messages start with +a lowercase letter: + +@example +The word `foo' is not declared. +`foo': not declared. +Not declaring: `foo'. +@end example + +@item +To avoid having a number of different messages for the same situation, +we'll use quoting like this @code{"message: `%s'"} for all strings. +Numbers are not quoted: + +@example +_f ("Can't open file: `%s'", name_str) +_f ("Can't find charater number: %d", i) +@end example + +@item +Think about translation issues. In a lot of cases, it is better to +translate a whole message. The english grammar mustn't be imposed on +the translator. So, iso + +@example +_ ("Stem at ") + moment.str () + _(" doen't fit in beam") +@end example + +@noindent +have + +@example +_f ("Stem at %s doen't fit in beam", moment.str ()) +@end example + +@item +Split up multi-sentence messages, whenever possible. Instead of + +@example +warning (_f ("out of tune! Can't find: `%s', "Key_engraver")); + +warning (_f ("Can't find font `%s', loading default", + font_name)); +@end example + +@noindent +rather say: + +@example +warning (_ ("out of tune:"); +warning (_f ("Can't find: `%s', "Key_engraver")); + +warning (_f ("Can't find font: `%s', font_name)); +warning (_f ("Loading default font")); +@end example + +@item +If you must have multiple-sentence messages, use full punctuation. +Use two spaces after end of sentence punctuation. +No punctuation (esp. period) is used at the end of simple messages. + +@example + _f ("Non-matching braces in text `%s', adding braces", text) + _ ("Debug output disabled. Compiled with NPRINT.") + _f ("Huh? Not a Request: `%s'. Ignoring.", request) +@end example + +@item +Don't modularise too much; a lot of words cannot be translated +without context. +It's probably safe to treat most occurences of words like +stem, beam, crescendo as separately translatable words. + +@item +When translating, it is preferrable to put interesting information +at the end of the message, rather than embedded in the middle. +This especially applies to frequently used messages, even if this +would mean sacrificing a bit of eloquency. This holds for original +messages too, of course. + +@example + en: can't open: `foo.ly' ++ nl: kan `foo.ly' niet openen (1) + kan niet openen: `foo.ly'* (2) + niet te openen: `foo.ly'* (3) +@end example + +The first nl message, although gramatically and stylishly correct, +is not friendly for parsing by humans (even if they speak dutch). +I guess we'd prefer something like (2) or (3). + +@item +Please don't run make po/po-update with GNU gettext < 0.10.35 + +@end itemize diff --git a/Documentation/user/lilypond.tely b/Documentation/user/lilypond.tely index ccb2641060..88b3b59f16 100644 --- a/Documentation/user/lilypond.tely +++ b/Documentation/user/lilypond.tely @@ -100,6 +100,8 @@ this and other documentation. @c Move to Reference Manual? * Internals:(lilypond-internals). Auto generated detailed documentation. * convert-ly:: Upgrading input files. +* Internals:: +* Development:: Some hints on developing for LilyPond. * Index:: Unified index. @end menu @@ -126,6 +128,8 @@ this and other documentation. @include convert-ly.itexi +@include development.itexi + @node Index, , , Top @unnumbered Index diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 55cd7287c8..60018dacba 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -39,8 +39,6 @@ * contextdefs:: contextdefs * 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. @@ -693,8 +691,8 @@ You can alter the length of duration by writing appearance of note heads or rests. -Rests are entered like notes, with note name `@code{r}@indexcode{r}', -or `@code{R}@indexcode{R}'. There is also a note name +Rests are entered like notes, with note name `@code{r}@indexcode{r}', or +`@code{R}@indexcode{R}'. There is also a note name `@code{s}@indexcode{s}', which produces a space of the specified duration. `@code{R}' is specifically meant for entering parts: the @code{R} rest can expand to fill a score with rests, or it can be @@ -705,6 +703,10 @@ You can control the expansion by setting the property empty measures, and the multimeasure rests automatically adds the appropriate number. +Note that there is currently no way to condense multiple rests into a +single multimeasure rest. + + @cindex lyrics expressions @@ -2017,10 +2019,10 @@ A context is an object that holds the reading state of the expression; it contains information like @itemize @bullet - @item What notes are playing at this point? - @item What symbols will be printed at this point? - @item In what style will they printed? - @item What is the current key signature, time signature, point within + @item What notes are playing at this point? + @item What symbols will be printed at this point? + @item In what style will they printed? + @item What is the current key signature, time signature, point within the measure, etc.? @end itemize @@ -2136,16 +2138,6 @@ sequential music is also the default @code{Voice} context. The @code{d4} gets interpreted in the same context as @code{c4}. - - -These are the contexts supplied with the package. They are defined -in the initialization file @file{ly/engraver.ly}. - -@table @samp -@end table - - - Properties that are set in one context are inherited by all of the contained contexts. This means that a property valid for the @code{Voice} context can be set in the @code{Score} context (for @@ -2156,33 +2148,18 @@ corresponding to the appropriate context. In this case, the syntax is @example - @var{propname} @code{=} @var{value} @end example This assignment happens before interpretation starts, so a @code{\property} expression will override any predefined settings. -The @code{\property} expression will create any property you specify. -There is no guarantee that a property will be used. So if you spell -a property name wrong, there will be no error message. - The property settings are used during the interpretation phase. They are read by the LilyPond modules where interpretation contexts are built of. These modules are called @emph{translators}. Translators for notation are called @emph{engravers}, and translators for sound are called @emph{performers}. -The precise result of a property is determined by the implementation -of the translator that reads them. Therefore, the result of a -property can vary, since it is implementation and configuration -dependent. - -In order to fully find out what properties are used, you must -currently search the source code for calls to @code{get_property}. -The rest of the section is devoted to an (incomplete) overview of -available properties. - @mbinclude properties.itely @node Notation output definitions, , , Reference Manual @@ -2200,7 +2177,6 @@ The most important output definition is the @code{\paper} block, for music notation. The syntax is @example - @code{\paper @{} [@var{paperidentifier}] @var{items} @code{@}} @end example @@ -2213,9 +2189,13 @@ where each of the items is one of @item A context definition. See section @ref{contextdefs} for more information on context definitions. - @item - FIXME now in SCM +@ignore + + FIXME + + @item + A margin shape declaration. The syntax is @example @@ -2232,15 +2212,15 @@ where each of the items is one of the successive pairs of dimensions. The last pair of dimensions will define the characeristics of all lines beyond those explicitly specified. +@end ignore @item \stylesheet declaration. Its syntax is @example - \stylesheet @var{scm} + \stylesheet @var{alist} @end example - - See font.scm for details of @var{scm} + See @file{font.scm} for details of @var{alist}. @end itemize @@ -2274,17 +2254,7 @@ select. @node Paper variables, , , Reference Manual -There is a large number of paper variables that are used to control -details of the layout. These variables control the defaults for the -entire score. Usually, they do not have to be changed; they are by -default set to values that depend on the font size in use. The -values are used by the graphic objects while formatting the score; -they are therefore implementation dependent. Most variables are -accompanied by documentation in the initalization file -@file{params.ly} or @file{paperSZ.ly}, where @code{SZ} is the staff -height in points. - -Nevertheless, here are some variables you may want to use or change: +The paper block has some variables you may want to use or change: @table @samp @item @code{indent}@indexcode{indent} @@ -2313,7 +2283,8 @@ Nevertheless, here are some variables you may want to use or change: Defaults to 0. @item @code{stafflinethickness}@indexcode{stafflinethickness} - Determines the thickness of staff and bar lines. + Determines the thickness of staff lines, and also acts as a scaling +parameter for other line thicknesses. @end table @@ -2393,8 +2364,12 @@ one of @item @code{\accepts} @var{contextname} @code{;} Add @var{contextname} to the list of context this context can - contain. The first listed context the context to create by + contain. The first listed context is the context to create by default. + + @item @code{\denies}. The opposite of @code{\accepts}. Added for +completeness, but is never used in practice. + @item @code{\remove} @var{engravername} @code{;} Remove a previously added (with @code{\consists}) engraver. @@ -2487,10 +2462,8 @@ translator: @node Sound output, , , Reference Manual @section Sound output - - -The MIDI block is analogous to the paper block, but it is simpler. -The @code{\midi} block can contain: +The MIDI block is analogous to the paper block, but it is somewhat +simpler. The @code{\midi} block can contain: @cindex MIDI block @itemize @bullet @@ -2630,284 +2603,3 @@ 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 -normally the domain of LilyPond gurus, but occasionally, a normal user -also has to deal with grobs. - -The most simple interaction with Grobs are when you use -@code{\override}: - -@example - \property Voice.Stem \override #'direction = #1 -@end example - -This piece of lily input causes all stem objects to be stem-up -henceforth. In effect, you are telling lilypond to extend the defintion -of the "Stem" grob with the setting @code{direction := 1}. Of course -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. - -@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. This mechanism is rather clumsy to use, but it allows -you tweak any setting of any grob. - -@node Items and Spanners, , , Grobs -@unnumberedsubsec Items and Spanners - -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}. - -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. - -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. - -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. - -@node Pointer substitution, , , Grobs -@unnumberedsubsec Pointer substitution - - -Symbols that cross line-breaks (such as slurs) cause some more -complications. When a spanner crosses a line-break, then the spanner is -"broken into pieces", for every line that the spanner is in, a copy of -the grob is made. A substitution process redirects all grob-reference -so that spanner grob will only reference other grobs in the same line. - -@node Molecule, , , Reference Manual - -The objective of any typesetting system is to put ink on paper in the -right places. For LilyPond, this final stage is left to the TeX and the -printer subsystem. For lily, the last stage in processing a score is -outputting a description of what to put where. This description roughly -looks like - -@example - PUT glyph AT (x,y) - PUT glyph AT (x,y) - PUT glyph AT (x,y) -@end example - -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 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: - -@example - Molecule = COMBINE Molecule Molecule - | TRANSLATE Offset Molecule - | GLYPH-DESCRIPTION - ; -@end example - -(refer to the C++ code for more details). All visible, -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 79eb818f78..7b3b1cf65f 100644 --- a/VERSION +++ b/VERSION @@ -1,8 +1,8 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=1 MINOR_VERSION=3 -PATCH_LEVEL=118 -MY_PATCH_LEVEL=jcn3 +PATCH_LEVEL=119 +MY_PATCH_LEVEL= # use the above to send patches: MY_PATCH_LEVEL is always empty for a # released version. diff --git a/input/test/number-staff-lines.ly b/input/test/number-staff-lines.ly index d8f758a1e9..5494d66c52 100644 --- a/input/test/number-staff-lines.ly +++ b/input/test/number-staff-lines.ly @@ -1,17 +1,19 @@ \header{ -texidoc=" -The number of stafflines of a staff can be set with the property -numberOfStaffLines. Ledger lines both on note heads and rests are -adjusted. Barlines also are adjusted. -"; + +texidoc=" The number of stafflines of a staff can be set. Ledger +lines both on note heads and rests are adjusted. Barlines also are +adjusted. "; + } \score { - \context Voice \notes\relative c { - - c' c c c | g' g g g \property Staff . numberOfStaffLines = 3 - +\context Voice \notes\relative c { + c' c c c | g' g g g } - \paper { } + \paper { + +\translator { \StaffContext +StaffSymbol \override #'line-count = #3 +} } \midi { } } diff --git a/lily/all-font-metrics.cc b/lily/all-font-metrics.cc index 2a67d59770..6d1fe1d95d 100644 --- a/lily/all-font-metrics.cc +++ b/lily/all-font-metrics.cc @@ -67,7 +67,8 @@ All_font_metrics::find_afm (String name) if (verbose_global_b) progress_indication ("[" + path); val = read_afm_file (path); - + unsmob_metrics (val)->path_ = path; + unsmob_metrics (val)->description_ = gh_cons (name_str, gh_double2scm (1.0)); if (verbose_global_b) @@ -85,7 +86,8 @@ All_font_metrics::find_afm (String name) if (tfm->info_.checksum != afm->checksum_) { String s = _f ("checksum mismatch for font file: `%s'", path.ch_C ()); - s+= "\n"; + s += _f ("does not match: `%s'", tfm->path_.ch_C()); // FIXME + s += "\n"; s += " TFM: " + to_str ((int) tfm->info_.checksum); s += " AFM: " + to_str ((int) afm->checksum_); s += "\n"; @@ -122,12 +124,15 @@ All_font_metrics::find_tfm (String name) if (path.empty_b()) return 0; + if (verbose_global_b) progress_indication ("[" + path); val = Tex_font_metric::make_tfm (path); + if (verbose_global_b) progress_indication ("]"); + unsmob_metrics (val)->path_ = path; unsmob_metrics (val)->description_ = gh_cons (name_str, gh_double2scm (1.0)); tfm_p_dict_->set (sname, val); diff --git a/lily/font-metric.cc b/lily/font-metric.cc index 8ff6a36bac..360f4d6ed3 100644 --- a/lily/font-metric.cc +++ b/lily/font-metric.cc @@ -69,7 +69,7 @@ Font_metric::Font_metric () smobify_self (); } -Font_metric::Font_metric (Font_metric const &) +Font_metric::Font_metric (Font_metric const &s) { } diff --git a/lily/include/engraver.hh b/lily/include/engraver.hh index a87cbbc811..729c5d7d57 100644 --- a/lily/include/engraver.hh +++ b/lily/include/engraver.hh @@ -25,11 +25,8 @@ class Engraver : public virtual Translator { friend class Engraver_group_engraver; protected: - /// utility - // Paper_def * paper_l() const; - /* - Call this last thing. + Call this when you're finished with ELEM_P. */ virtual void typeset_grob (Grob*elem_p); /* diff --git a/lily/include/font-metric.hh b/lily/include/font-metric.hh index 767b3475df..2ebbf303b1 100644 --- a/lily/include/font-metric.hh +++ b/lily/include/font-metric.hh @@ -14,12 +14,13 @@ #include "lily-guile.hh" #include "smobs.hh" #include "lily-proto.hh" +#include "string.hh" struct Font_metric { public: SCM description_; - + String path_; virtual Box get_char (int ascii) const; virtual Box text_dimension (String) const; virtual Molecule find_by_name (String) const; diff --git a/lily/include/tfm.hh b/lily/include/tfm.hh index 068ca68ae2..2da00c7b54 100644 --- a/lily/include/tfm.hh +++ b/lily/include/tfm.hh @@ -161,6 +161,8 @@ public: Tfm_header header_; Array char_metrics_; Array ascii_to_metric_idx_; + + String path_; private: Tex_font_metric (); }; diff --git a/lily/parser.yy b/lily/parser.yy index 2cf1bf94a3..7366cea832 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -532,7 +532,7 @@ score_body: $$->set_spot (THIS->here_input ()); } | score_body lilypond_header { - scm_unprotect_object ( $1->self_scm ()); + scm_unprotect_object ($2->self_scm ()); $$->header_p_ = $2; } | score_body output_def { @@ -629,8 +629,6 @@ Music_list: /* empty */ { SCM s = $$; SCM c = gh_cons ($2->self_scm (), SCM_EOL); scm_unprotect_object ($2->self_scm ()); /* UGH */ - - if (gh_pair_p (gh_cdr (s))) gh_set_cdr_x (gh_cdr (s), c); /* append */ else diff --git a/lily/property-engraver.cc b/lily/property-engraver.cc index 80e909c5b2..8ba9d331be 100644 --- a/lily/property-engraver.cc +++ b/lily/property-engraver.cc @@ -139,13 +139,17 @@ Property_engraver::apply_properties (SCM p, Grob *e, Translator_group*origin) */ if (val != SCM_EOL) { // not the right type: error message. + SCM errport = scm_current_error_port (); SCM typefunc = scm_eval2 (ly_symbol2scm ("type-name"), SCM_EOL); SCM type_name = gh_call1 (typefunc, type_p); +#if 0 warning (_f ("Wrong type for property: %s, type: %s, value found: %s, type: %s", ly_symbol2string (prop_sym).ch_C (), ly_scm2string (type_name).ch_C (), ly_scm2string (ly_write2scm (val)).ch_C (), ly_scm2string (ly_type (val)).ch_C ())); +#endif + scm_puts ("\n", errport); } } } diff --git a/lily/score.cc b/lily/score.cc index 9e774cd6c5..417c3b3a44 100644 --- a/lily/score.cc +++ b/lily/score.cc @@ -39,16 +39,23 @@ Score::Score (Score const &s) : Input (s) { music_ = SCM_EOL; - + header_p_ = 0; smobify_self (); Music * m =unsmob_music (s.music_); music_ = m?m->clone()->self_scm () : SCM_EOL; + scm_unprotect_object (music_); for (int i=0; i < s.def_p_arr_.size (); i++) def_p_arr_.push(s.def_p_arr_[i]->clone()); errorlevel_i_ = s.errorlevel_i_; - header_p_ = (s.header_p_) ? new Scheme_hash_table (*s.header_p_): 0; + if (s.header_p_) + { + header_p_ = (s.header_p_) ? new Scheme_hash_table (*s.header_p_): 0; + + scm_unprotect_object(header_p_->self_scm ()); + } + } Score::~Score() diff --git a/lily/translator-group.cc b/lily/translator-group.cc index 80fa807b56..367e6d1277 100644 --- a/lily/translator-group.cc +++ b/lily/translator-group.cc @@ -409,13 +409,17 @@ type_check_assignment (SCM val, SCM sym, SCM type_symbol) && gh_procedure_p (type_p) && gh_call1 (type_p, val) == SCM_BOOL_F) { + SCM errport = scm_current_error_port (); ok = false; SCM typefunc = scm_eval2 (ly_symbol2scm ("type-name"), SCM_EOL); SCM type_name = gh_call1 (typefunc, type_p); - warning (_f ("Failed typecheck for `%s', value `%s' must be of type `%s'", - ly_symbol2string (sym).ch_C (), - ly_scm2string (ly_write2scm( val)).ch_C (), - ly_scm2string (type_name).ch_C ())); + + scm_puts (_f ("Failed typecheck for `%s', value `%s' must be of type `%s'", + ly_symbol2string (sym).ch_C (), + ly_scm2string (ly_write2scm( val)).ch_C (), + ly_scm2string (type_name).ch_C ()).ch_C (), + errport); + scm_puts ("\n", errport); } } return ok; diff --git a/make/out/lilypond.lsm b/make/out/lilypond.lsm index 90aff62e5f..4a50713f93 100644 --- a/make/out/lilypond.lsm +++ b/make/out/lilypond.lsm @@ -1,15 +1,15 @@ Begin3 Title: LilyPond -Version: 1.3.118 -Entered-date: 17DEC00 +Version: 1.3.119 +Entered-date: 20DEC00 Description: Keywords: music notation typesetting midi fonts engraving Author: hanwen@cs.uu.nl (Han-Wen Nienhuys) janneke@gnu.org (Jan Nieuwenhuizen) Maintained-by: hanwen@stack.nl (Han-Wen Nienhuys) Primary-site: sunsite.unc.edu /pub/Linux/apps/sound/convert - 1000k lilypond-1.3.118.tar.gz + 1000k lilypond-1.3.119.tar.gz Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/ - 1000k lilypond-1.3.118.tar.gz + 1000k lilypond-1.3.119.tar.gz Copying-policy: GPL End diff --git a/make/out/lilypond.spec b/make/out/lilypond.spec index d789c64523..660ed7cb52 100644 --- a/make/out/lilypond.spec +++ b/make/out/lilypond.spec @@ -1,11 +1,11 @@ %define info yes Name: lilypond -Version: 1.3.118 +Version: 1.3.119 Release: 1 License: GPL Group: Applications/Publishing -Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.118.tar.gz +Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.3.119.tar.gz Summary: A program for printing sheet music. URL: http://www.cs.uu.nl/~hanwen/lilypond # Icon: lilypond-icon.gif diff --git a/po/nl.po b/po/nl.po index be49057db7..266852ac97 100644 --- a/po/nl.po +++ b/po/nl.po @@ -838,7 +838,7 @@ msgstr "kan niet vinden of scheppen: `%s'" msgid "" "Can't find property type-check for `%s'. Perhaps you made a typing error?" msgstr "" -"Kan geen type-controle vinden voor property `%s'. Misschien een tiepfout?" +"Kan geen type-controle vinden voor property `%s'. Misschien een tikfout?" #. warning () ? #: translator-group.cc:420 diff --git a/scm/backend-property.scm b/scm/backend-property.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/scm/element-descriptions.scm b/scm/element-descriptions.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/scm/interface.scm b/scm/interface.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/scm/music-property.scm b/scm/music-property.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/scm/translator-properties.scm b/scm/translator-properties.scm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/scm/translator-property-description.scm b/scm/translator-property-description.scm index a620aa8728..866a237ef7 100644 --- a/scm/translator-property-description.scm +++ b/scm/translator-property-description.scm @@ -270,11 +270,11 @@ itself. ") (translator-property-description 'voltaSpannerDuration moment? "maximum duration of the volta bracket. Set to a duration to control the size of the brackets printed by -@code{lternative}. It specifies the number of whole notes duration +@code{\\alternative}. It specifies the number of whole notes duration to use for the brackets. This can be used to shrink the length of brackets in the situation where one alternative is very large. It may have odd effects if the specified duration is longer than the music -given in an @code{lternative}. +given in an @code{\\alternative}. ") (translator-property-description 'weAreGraceContext boolean? "") (translator-property-description 'whichBar string? "This property is read to determine what type of barline to create. diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index bd0e3c822e..0634dad0ab 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -1015,9 +1015,9 @@ def fix_epswidth (chunks): for c in chunks: if c[0] == 'lilypond' and 'eps' in c[2]: body = re.sub (r"""\\lilypondepswidth{(.*?)}""", find_eps_dims, c[1]) - newchunks.append(('lilypond', body, c[2], c[3], c[4])) - else: - newchunks.append (c) + # why do we junk opts, todo, basename? + new_chunk = (('lilypond', body)) + newchunks.append (c) return newchunks -- 2.39.5