CVSROOT: /cvsroot/lilypond Module name: lilypond Branch: lilypond_2_6 Changes by: Mats Bengtsson <[EMAIL PROTECTED]> 05/08/03 09:39:48
Modified files: . : ChangeLog Documentation/user: programming-interface.itely Log message: * Documentation/user/programming-interface.itely (Markup construction in Scheme): Corrected markup syntax in the translation table. CVSWeb URLs: http://savannah.gnu.org/cgi-bin/viewcvs/lilypond/lilypond/ChangeLog.diff?only_with_tag=lilypond_2_6&tr1=1.3836.2.13&tr2=1.3836.2.14&r1=text&r2=text http://savannah.gnu.org/cgi-bin/viewcvs/lilypond/lilypond/Documentation/user/programming-interface.itely.diff?only_with_tag=lilypond_2_6&tr1=1.37&tr2=1.37.2.1&r1=text&r2=text Patches: Index: lilypond/ChangeLog diff -u lilypond/ChangeLog:1.3836.2.13 lilypond/ChangeLog:1.3836.2.14 --- lilypond/ChangeLog:1.3836.2.13 Tue Aug 2 16:03:10 2005 +++ lilypond/ChangeLog Wed Aug 3 09:39:47 2005 @@ -1,3 +1,9 @@ +2005-08-03 Mats Bengtsson <[EMAIL PROTECTED]> + + * Documentation/user/programming-interface.itely (Markup + construction in Scheme): Corrected markup syntax in the + translation table. + 2005-08-02 Han-Wen Nienhuys <[EMAIL PROTECTED]> * VERSION (PACKAGE_NAME): release 2.6.2 Index: lilypond/Documentation/user/programming-interface.itely diff -u /dev/null lilypond/Documentation/user/programming-interface.itely:1.37.2.1 --- /dev/null Wed Aug 3 09:39:48 2005 +++ lilypond/Documentation/user/programming-interface.itely Wed Aug 3 09:39:48 2005 @@ -0,0 +1,769 @@ [EMAIL PROTECTED] -*- coding: latin-1; mode: texinfo; -*- [EMAIL PROTECTED] Interfaces for programmers [EMAIL PROTECTED] Interfaces for programmers + + + [EMAIL PROTECTED] +* Programmer interfaces for input :: +* Markup programmer interface:: +* Contexts for programmers:: [EMAIL PROTECTED] menu + [EMAIL PROTECTED] Programmer interfaces for input [EMAIL PROTECTED] Programmer interfaces for input + [EMAIL PROTECTED] +* Input variables and Scheme:: +* Internal music representation:: +* Extending music syntax:: +* Manipulating music expressions:: +* Displaying music expressions:: +* Using LilyPond syntax inside Scheme:: [EMAIL PROTECTED] menu + [EMAIL PROTECTED] Input variables and Scheme [EMAIL PROTECTED] Input variables and Scheme + + +The input format supports the notion of variables: in the following +example, a music expression is assigned to a variable with the name [EMAIL PROTECTED] [EMAIL PROTECTED] +traLaLa = @{ c'4 d'4 @} [EMAIL PROTECTED] example + [EMAIL PROTECTED] + +There is also a form of scoping: in the following example, the [EMAIL PROTECTED] block also contains a @code{traLaLa} variable, which is +independent of the outer @code{\traLaLa}. [EMAIL PROTECTED] +traLaLa = @{ c'4 d'4 @} +\layout @{ traLaLa = 1.0 @} [EMAIL PROTECTED] example [EMAIL PROTECTED] +In effect, each input file is a scope, and all @code{\header}, [EMAIL PROTECTED], and @code{\layout} blocks are scopes nested inside that +toplevel scope. + +Both variables and scoping are implemented in the GUILE module system. +An anonymous Scheme module is attached to each scope. An assignment of +the form [EMAIL PROTECTED] +traLaLa = @{ c'4 d'4 @} [EMAIL PROTECTED] example + [EMAIL PROTECTED] +is internally converted to a Scheme definition [EMAIL PROTECTED] +(define traLaLa @var{Scheme value of [EMAIL PROTECTED] }''}) [EMAIL PROTECTED] example + +This means that input variables and Scheme variables may be freely +mixed. In the following example, a music fragment is stored in the +variable @code{traLaLa}, and duplicated using Scheme. The result is +imported in a @code{\score} block by means of a second variable [EMAIL PROTECTED]: [EMAIL PROTECTED] +traLaLa = @{ c'4 d'4 @} + +#(define newLa (map ly:music-deep-copy + (list traLaLa traLaLa))) +#(define twice + (make-sequential-music newLa)) + [EMAIL PROTECTED] \twice @} [EMAIL PROTECTED] example + +In the above example, music expressions can be `exported' from the +input to the Scheme interpreter. The opposite is also possible. By +wrapping a Scheme value in the function @code{ly:export}, a Scheme +value is interpreted as if it were entered in LilyPond syntax. Instead +of defining @code{\twice}, the example above could also have been +written as [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] #(ly:export (make-sequential-music (list newLa))) @} [EMAIL PROTECTED] example + [EMAIL PROTECTED] + +Mixing Scheme and LilyPond identifiers is not possible with the [EMAIL PROTECTED] option. + [EMAIL PROTECTED] Internal music representation [EMAIL PROTECTED] Internal music representation + +When a music expression is parsed, it is converted into a set of +Scheme music objects. The defining property of a music object is that +it takes up time. Time is a rational number that measures the length +of a piece of music, in whole notes. + +A music object has three kinds of types: [EMAIL PROTECTED] @bullet [EMAIL PROTECTED] +music name: Each music expression has a name, for example, a note +leads to a @internalsref{NoteEvent}, and @code{\simultaneous} leads to +a @internalsref{SimultaneousMusic}. A list of all expressions +available is in the internals manual, under [EMAIL PROTECTED] expressions}. + [EMAIL PROTECTED] +`type' or interface: Each music name has several `types' or +interfaces, for example, a note is an @code{event}, but it is also a [EMAIL PROTECTED], a @code{rhythmic-event}, and a @code{melodic-event}. + +All classes of music are listed in the internals manual, under [EMAIL PROTECTED] classes}. + [EMAIL PROTECTED] +C++ object: Each music object is represented by a C++ object. For +technical reasons, different music objects may be represented by +different C++ object types. For example, a note is @code{Event} +object, while @code{\grace} creates a @code{Grace_music} object. + +We expect that distinctions between different C++ types will disappear +in the future. [EMAIL PROTECTED] itemize + +The actual information of a music expression is stored in properties. +For example, a @internalsref{NoteEvent} has @code{pitch} and [EMAIL PROTECTED] properties that store the pitch and duration of that +note. A list of all properties available is in the internals manual, +under @internalsref{Music properties}. + +A compound music expression is a music object that contains other +music objects in its properties. A list of objects can be stored in +the @code{elements} property of a music object, or a single `child' +music object in the @code{element} object. For example, [EMAIL PROTECTED] has its children in @code{elements}, +and @internalsref{GraceMusic} has its single argument in [EMAIL PROTECTED] The body of a repeat is stored in the @code{element} +property of @internalsref{RepeatedMusic}, and the alternatives in [EMAIL PROTECTED] + + + + [EMAIL PROTECTED] Extending music syntax [EMAIL PROTECTED] Extending music syntax + [EMAIL PROTECTED] TODO: rewrite example. [EMAIL PROTECTED] The use of FUNC as example argument is rather confusing. + +The syntax of composite music expressions, like @code{\repeat}, [EMAIL PROTECTED], and @code{\context} follows the general form of + [EMAIL PROTECTED] [EMAIL PROTECTED] @var{non-music-arguments} @var{music-arguments} [EMAIL PROTECTED] example + +Such syntax can also be defined as user code. To do this, it is +necessary to create a @emph{music function}. This is a specially marked +Scheme function. For example, the music function @code{\applymusic} applies +a user-defined function to a music expression. Its syntax is + [EMAIL PROTECTED] +\applymusic [EMAIL PROTECTED] @var{music} [EMAIL PROTECTED] example + +A music function is created with @code{ly:make-music-function}, + [EMAIL PROTECTED] +(ly:make-music-function [EMAIL PROTECTED] example + [EMAIL PROTECTED] takes a Scheme function and a Music expression as +arguments. This is encoded in its parameter list, + [EMAIL PROTECTED] +(list procedure? ly:music?) [EMAIL PROTECTED] example + +The function itself takes another argument, an Input location +object. That object is used to provide error messages with file names +and line numbers. The definition is the second argument of [EMAIL PROTECTED]:make-music-function}. The body simply calls the function + [EMAIL PROTECTED] +(lambda (where func music) + (func music)) [EMAIL PROTECTED] example + +The above Scheme code only defines the functionality. The tag [EMAIL PROTECTED] is selected by defining + [EMAIL PROTECTED] +applymusic = #(ly:make-music-function + (list procedure? ly:music?) + (lambda (parser location func music) + (func music))) [EMAIL PROTECTED] example + +A @code{def-music-function} macro is introduced on top of [EMAIL PROTECTED]:make-music-function} to ease the definition of music +functions: + [EMAIL PROTECTED] +applymusic = #(def-music-function (parser location func music) + (procedure? ly:music?) + (func music)) [EMAIL PROTECTED] example + +Examples of the use of @code{\applymusic} are in the next section. + [EMAIL PROTECTED] [EMAIL PROTECTED]/@/music@/-functions@/-init@/.ly}. + [EMAIL PROTECTED] Manipulating music expressions [EMAIL PROTECTED] Manipulating music expressions + +Music objects and their properties can be accessed and manipulated +directly, through the @code{\applymusic} mechanism. +The syntax for @code{\applymusic} is [EMAIL PROTECTED] +\applymusic [EMAIL PROTECTED] @var{music} [EMAIL PROTECTED] example + [EMAIL PROTECTED] +This means that the Scheme function @var{func} is called with [EMAIL PROTECTED] as its argument. The return value of @var{func} is the +result of the entire expression. @var{func} may read and write music +properties using the functions @code{ly:music-property} and [EMAIL PROTECTED]:music-set-property!}. + +An example is a function that reverses the order of elements in +its argument, [EMAIL PROTECTED],verbatim,raggedright] +#(define (rev-music-1 m) + (ly:music-set-property! m 'elements + (reverse (ly:music-property m 'elements))) + m) + +\applymusic #rev-music-1 { c'4 d'4 } [EMAIL PROTECTED] lilypond + +The use of such a function is very limited. The effect of this +function is void when applied to an argument that does not have +multiple children. The following function application has no effect + [EMAIL PROTECTED] +\applymusic #rev-music-1 \grace @{ c4 d4 @} [EMAIL PROTECTED] example + [EMAIL PROTECTED] +In this case, @code{\grace} is stored as @internalsref{GraceMusic}, which +has no @code{elements}, only a single @code{element}. Every generally +applicable function for @code{\applymusic} must -- like music expressions +themselves -- be recursive. + +The following example is such a recursive function: It first extracts +the @code{elements} of an expression, reverses them and puts them +back. Then it recurses, both on @code{elements} and @code{element} +children. [EMAIL PROTECTED] +#(define (reverse-music music) + (let* ((elements (ly:music-property music 'elements)) + (child (ly:music-property music 'element)) + (reversed (reverse elements))) + + ; set children + (ly:music-set-property! music 'elements reversed) + + ; recurse + (if (ly:music? child) (reverse-music child)) + (map reverse-music reversed) + + music)) [EMAIL PROTECTED] example + +A slightly more elaborate example is in [EMAIL PROTECTED]/@/test,reverse@/-music@/.ly}. + +Some of the input syntax is also implemented as recursive music +functions. For example, the syntax for polyphony [EMAIL PROTECTED] +<<a \\ b>> [EMAIL PROTECTED] example + [EMAIL PROTECTED] +is actually implemented as a recursive function that replaces the +above by the internal equivalent of [EMAIL PROTECTED] +<< \context Voice = "1" @{ \voiceOne a @} + \context Voice = "2" @{ \voiceTwo b @} >> [EMAIL PROTECTED] example + +Other applications of @code{\applymusic} are writing out repeats +automatically (@inputfileref{input/@/test,unfold@/-all@/-repeats@/.ly}), +saving keystrokes (@inputfileref{input/@/test,music@/-box@/.ly}) and +exporting LilyPond input to other formats [EMAIL PROTECTED] no @inputfileref{} here +(eg. @file{input/@/no@/-notation/@/to@/-xml@/.ly}). + [EMAIL PROTECTED] + [EMAIL PROTECTED]/@/music@/-functions@/.scm}, @file{scm/@/music@/-types@/.scm}, [EMAIL PROTECTED]/@/test,add@/-staccato@/.ly}, [EMAIL PROTECTED]/@/test,unfold@/-all@/-repeats@/.ly}, and [EMAIL PROTECTED]/@/test,music@/-box@/.ly}. + + [EMAIL PROTECTED] Displaying music expressions [EMAIL PROTECTED] Displaying music expressions + [EMAIL PROTECTED] internal storage [EMAIL PROTECTED] @code{\displayMusic} + +When writing a music function, it is often instructive to inspect how +a music expression is stored internally. This can be done with the +music function @code{\displayMusic}. + [EMAIL PROTECTED] [EMAIL PROTECTED] +\displayMusic @{ c'4\f @} [EMAIL PROTECTED] [EMAIL PROTECTED] example + + [EMAIL PROTECTED] Using LilyPond syntax inside Scheme [EMAIL PROTECTED] Using LilyPond syntax inside Scheme + +Creating music expressions in Scheme can be tedious, as they are +heavily nested and the resulting Scheme code is large. For some +simple tasks, this can be avoided, using common LilyPond syntax inside +Scheme, with the dedicated @[EMAIL PROTECTED] ... [EMAIL PROTECTED] syntax. + +The following two expressions give equivalent music expressions: [EMAIL PROTECTED] +mynotes = @{ \override Stem #'thickness = #4 + @{ c'8 d' @} @} + +#(define mynotes [EMAIL PROTECTED] \override Stem #'thickness = #4 + @{ c'8 d' @} [EMAIL PROTECTED]) [EMAIL PROTECTED] example + +The content of @[EMAIL PROTECTED] ... [EMAIL PROTECTED] is enclosed in an implicit @[EMAIL PROTECTED] +... @}} block, which is parsed. The resulting music expression, a [EMAIL PROTECTED] music object, is then returned and usable in Scheme. + +Arbitrary Scheme forms, including variables, can be used in @[EMAIL PROTECTED] ... [EMAIL PROTECTED] +expressions with the @code{$} character (@code{$$} can be used to +produce a single @code{$} character). This makes the creation of simple +functions straightforward. In the following example, a function +setting the TextScript's padding is defined: + [EMAIL PROTECTED],verbatim,raggedright] +#(use-modules (ice-9 optargs)) +#(define* (textpad padding #:optional once?) + (ly:export ; this is necessary for using the expression + ; directly inside a block + (if once? + #{ \once \override TextScript #'padding = #$padding #} + #{ \override TextScript #'padding = #$padding #}))) + + { + c'^"1" + #(textpad 3.0 #t) % only once + c'^"2" + c'^"3" + #(textpad 5.0) + c'^"4" + c'^"5" + } [EMAIL PROTECTED] lilypond + +Here, the variable @code{padding} is a number; music expression +variables may also be used in a similar fashion, as in the following +example: + [EMAIL PROTECTED],verbatim,raggedright] +#(define (with-padding padding) + (lambda (music) + #{ \override TextScript #'padding = #$padding + $music + \revert TextScript #'padding #})) + +{ + c'^"1" + \applymusic #(with-padding 3) { c'^"2" c'^"3" } + c'^"4" +} [EMAIL PROTECTED] lilypond + +The function created by @code{(with-padding 3)} adds @code{\override} and [EMAIL PROTECTED] statements around the music given as an argument, and returns +this new expression. Thus, this example is equivalent to: + [EMAIL PROTECTED] [EMAIL PROTECTED] + c'^"1" + @{ \override TextScript #'padding = #3 + @{ c'^"2" c'^"3"@} + \revert TextScript #'padding + @} + c'^"4" [EMAIL PROTECTED] [EMAIL PROTECTED] example + +This function may also be defined as a music function: + [EMAIL PROTECTED],verbatim,raggedright] +withPadding = + #(def-music-function (parser location padding music) (number? ly:music?) + #{ \override TextScript #'padding = #$padding + $music + \revert TextScript #'padding #}) + +{ + c'^"1" + \withPadding #3 { c'^"2" c'^"3"} + c'^"4" +} [EMAIL PROTECTED] lilypond + + [EMAIL PROTECTED] Markup programmer interface [EMAIL PROTECTED] Markup programmer interface + [EMAIL PROTECTED] Please rewrite the second sentence; I don't understand its meaning. AS + +Markups are implemented as special Scheme functions. When applied +with as arguments an output definition (@code{\layout} or [EMAIL PROTECTED]), and a list of properties and other arguments, produce +a Stencil object. + [EMAIL PROTECTED] +* Markup construction in Scheme:: +* How markups work internally :: +* Markup command definition:: [EMAIL PROTECTED] menu + [EMAIL PROTECTED] Markup construction in Scheme [EMAIL PROTECTED] Markup construction in Scheme + [EMAIL PROTECTED] defining markup commands + +The @code{markup} macro builds markup expressions in Scheme while +providing a LilyPond-like syntax. For example, [EMAIL PROTECTED] +(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") + #:bigger #:line ("foo" "bar" "baz"))) [EMAIL PROTECTED] example + [EMAIL PROTECTED] +is equivalent to: [EMAIL PROTECTED] +\markup \column < @{ \bold \italic "hello" \raise #0.4 "world" @} + \bigger @{ foo bar baz @} > [EMAIL PROTECTED] example + [EMAIL PROTECTED] +This example exposes the main translation rules between regular +LilyPond markup syntax and Scheme markup syntax, which are summed up +is this table: + [EMAIL PROTECTED] [EMAIL PROTECTED] @columnfractions .3 .3 [EMAIL PROTECTED] @b{LilyPond} @tab @b{Scheme} [EMAIL PROTECTED] @code{\command} @tab @code{#:command} [EMAIL PROTECTED] @code{\variable} @tab @code{variable} [EMAIL PROTECTED] @[EMAIL PROTECTED] ... @}} @tab @code{#:line ( ... )} [EMAIL PROTECTED] @code{\center-align @{ ... @}} @tab @code{#:center-align ( ... )} [EMAIL PROTECTED] @code{string} @tab @code{"string"} [EMAIL PROTECTED] @code{#scheme-arg} @tab @code{scheme-arg} [EMAIL PROTECTED] multitable [EMAIL PROTECTED] quotation + +Besides, the whole scheme language is accessible inside the [EMAIL PROTECTED] macro: thus, one may use function calls inside [EMAIL PROTECTED] in order to manipulate character strings for +instance. This proves useful when defining new markup commands (see [EMAIL PROTECTED] command definition}). + [EMAIL PROTECTED] + +One can not feed the @code{#:line} (resp @code{#:center}, [EMAIL PROTECTED]:column}) command with a variable or the result of a function +call. Example: + [EMAIL PROTECTED] +(markup #:line (fun-that-returns-markups)) [EMAIL PROTECTED] lisp + [EMAIL PROTECTED] +is invalid. One should use the @code{make-line-markup} (resp., [EMAIL PROTECTED] or @code{make-column-markup}) function +instead, [EMAIL PROTECTED] +(markup (make-line-markup (fun-that-returns-markups))) [EMAIL PROTECTED] lisp + [EMAIL PROTECTED] How markups work internally [EMAIL PROTECTED] How markups work internally + +In a markup like + [EMAIL PROTECTED] +\raise #0.5 "foo" [EMAIL PROTECTED] example + [EMAIL PROTECTED] [EMAIL PROTECTED] is actually represented by the @code{raise-markup} +function. The markup expression is stored as + [EMAIL PROTECTED] +(list raise-markup 0.5 (list simple-markup "foo")) [EMAIL PROTECTED] example + +When the markup is converted to printable objects (Stencils), the [EMAIL PROTECTED] function is called as + [EMAIL PROTECTED] +(apply raise-markup + @var{\layout object} + @var{list of property alists} + 0.5 + @var{the "foo" markup}) [EMAIL PROTECTED] example + +The @code{raise-markup} function first creates the stencil for the [EMAIL PROTECTED] string, and then it raises that Stencil by 0.5 staff space. +This is a rather simple example; more complex examples are in the rest +of this section, and in @file{scm/@/define@/-markup@/-commands@/.scm}. + [EMAIL PROTECTED] Markup command definition [EMAIL PROTECTED] Markup command definition + +New markup commands can be defined +with the @code{def-markup-command} scheme macro. [EMAIL PROTECTED] +(def-markup-command (@var{command-name} @var{layout} @var{props} @var{arg1} @var{arg2} ...) + (@var{arg1-type?} @var{arg2-type?} ...) + ..command body..) [EMAIL PROTECTED] lisp + +The arguments signify + [EMAIL PROTECTED] @var [EMAIL PROTECTED] argi [EMAIL PROTECTED] command argument [EMAIL PROTECTED] argi-type? +a type predicate for the [EMAIL PROTECTED] argument [EMAIL PROTECTED] layout +the `layout' definition [EMAIL PROTECTED] props +a list of alists, containing all active properties. [EMAIL PROTECTED] table + +As a simple example, we show how to add a @code{\smallcaps} command, +which selects @TeX{}'s small caps font. Normally, we could select the +small caps font as follows: + [EMAIL PROTECTED] +\markup @{ \override #'(font-shape . caps) Text-in-caps @} [EMAIL PROTECTED] example + +This selects the caps font by setting the @code{font-shape} property to [EMAIL PROTECTED]'caps} for interpreting @code{Text-in-caps}. + +To make the above available as @code{\smallcaps} command, we have to +define a function using @code{def-markup-command}. The command should +take a single argument, of type markup. Therefore, the start of the +definition should read [EMAIL PROTECTED] +(def-markup-command (smallcaps layout props argument) (markup?) [EMAIL PROTECTED] example + [EMAIL PROTECTED] + +What follows is the content of the command: we should interpret +the @code{argument} as a markup, i.e., + [EMAIL PROTECTED] +(interpret-markup layout @dots{} argument) [EMAIL PROTECTED] example + [EMAIL PROTECTED] +This interpretation should add @code{'(font-shape . caps)} to the active +properties, so we substitute the following for the @dots{} in the +above example: + [EMAIL PROTECTED] +(cons (list '(font-shape . caps) ) props) [EMAIL PROTECTED] example + [EMAIL PROTECTED] +The variable @code{props} is a list of alists, and we prepend to it by +cons'ing a list with the extra setting. + + +Suppose that we are typesetting a recitative in an opera, and +we would like to define a command that will show character names in a +custom manner. Names should be printed with small caps and translated a +bit to the left and top. We will define a @code{\character} command +that takes into account the necessary translation, and uses the newly +defined @code{\smallcaps} command: + [EMAIL PROTECTED] +#(def-markup-command (character layout props name) (string?) + "Print the character name in small caps, translated to the left and + top. Syntax: \\character #\"name\"" + (interpret-markup layout props + (markup "" #:translate (cons -3 1) #:smallcaps name))) [EMAIL PROTECTED] example + +There is one complication that needs explanation: texts above and below +the staff are moved vertically to be at a certain distance (the [EMAIL PROTECTED] property) from the staff and the notes. To make sure +that this mechanism does not annihilate the vertical effect of our [EMAIL PROTECTED]:translate}, we add an empty string (@code{""}) before the +translated text. Now the @code{""} will be put above the notes, and the [EMAIL PROTECTED] is moved in relation to that empty string. The net effect is +that the text is moved to the upper left. + +The final result is as follows: [EMAIL PROTECTED] [EMAIL PROTECTED] + c''^\markup \character #"Cleopatra" + e'^\markup \character #"Giulio Cesare" [EMAIL PROTECTED] [EMAIL PROTECTED] example + [EMAIL PROTECTED],raggedright] +#(def-markup-command (smallcaps layout props str) (string?) + "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" + (interpret-markup layout props + (make-line-markup + (map (lambda (s) + (if (= (string-length s) 0) + s + (markup #:large (string-upcase (substring s 0 1)) + #:translate (cons -0.6 0) + #:tiny (string-upcase (substring s 1))))) + (string-split str #\Space))))) + +#(def-markup-command (character layout props name) (string?) + "Print the character name in small caps, translated to the left and + top. Syntax: \\character #\"name\"" + (interpret-markup layout props + (markup "" #:translate (cons -3 1) #:smallcaps name))) + +{ + c''^\markup \character #"Cleopatra" c'' c'' c'' + e'^\markup \character #"Giulio Cesare" e' e' e' +} [EMAIL PROTECTED] lilypond + +We have used the @code{caps} font shape, but suppose that our font +does not have a small-caps variant. In that case we have to fake +the small caps font by setting a string in upcase with the first +letter a little larger: + [EMAIL PROTECTED] +#(def-markup-command (smallcaps layout props str) (string?) + "Print the string argument in small caps." + (interpret-markup layout props + (make-line-markup + (map (lambda (s) + (if (= (string-length s) 0) + s + (markup #:large (string-upcase (substring s 0 1)) + #:translate (cons -0.6 0) + #:tiny (string-upcase (substring s 1))))) + (string-split str #\Space))))) [EMAIL PROTECTED] example + +The @code{smallcaps} command first splits its string argument into +tokens separated by spaces (@code{(string-split str #\Space)}); for +each token, a markup is built with the first letter made large and +upcased (@code{#:large (string-upcase (substring s 0 1))}), and a +second markup built with the following letters made tiny and upcased +(@code{#:tiny (string-upcase (substring s 1))}). As LilyPond +introduces a space between markups on a line, the second markup is +translated to the left (@code{#:translate (cons -0.6 0) ...}). Then, +the markups built for each token are put in a line by [EMAIL PROTECTED](make-line-markup ...)}. Finally, the resulting markup is passed +to the @code{interpret-markup} function, with the @code{layout} and [EMAIL PROTECTED] arguments. + + + [EMAIL PROTECTED] Contexts for programmers [EMAIL PROTECTED] Contexts for programmers + + [EMAIL PROTECTED] +* Context evaluation:: +* Running a function on all layout objects:: [EMAIL PROTECTED] menu + [EMAIL PROTECTED] Context evaluation [EMAIL PROTECTED] Context evaluation + [EMAIL PROTECTED] calling code during interpreting [EMAIL PROTECTED] @code{\applycontext} + +Contexts can be modified during interpretation with Scheme code. The +syntax for this is [EMAIL PROTECTED] +\applycontext @var{function} [EMAIL PROTECTED] example + [EMAIL PROTECTED] should be a Scheme function taking a single argument, +being the context to apply it to. The following code will print the +current bar number on the standard output during the compile: + [EMAIL PROTECTED] +\applycontext + #(lambda (x) + (format #t "\nWe were called in barnumber ~a.\n" + (ly:context-property x 'currentBarNumber))) [EMAIL PROTECTED] example + + + [EMAIL PROTECTED] Running a function on all layout objects [EMAIL PROTECTED] Running a function on all layout objects + + [EMAIL PROTECTED] calling code on layout objects [EMAIL PROTECTED] @code{\applyoutput} + + +The most versatile way of tuning an object is @code{\applyoutput}. Its +syntax is [EMAIL PROTECTED] +\applyoutput @var{proc} [EMAIL PROTECTED] example + [EMAIL PROTECTED] +where @var{proc} is a Scheme function, taking three arguments. + +When interpreted, the function @var{proc} is called for every layout +object found in the context, with the following arguments: [EMAIL PROTECTED] @bullet [EMAIL PROTECTED] the layout object itself, [EMAIL PROTECTED] the context where the layout object was created, and [EMAIL PROTECTED] the context where @code{\applyoutput} is processed. [EMAIL PROTECTED] itemize + + +In addition, the cause of the layout object, i.e., the music +expression or object that was responsible for creating it, is in the +object property @code{cause}. For example, for a note head, this is a [EMAIL PROTECTED] event, and for a @internalsref{Stem} object, +this is a @internalsref{NoteHead} object. + +Here is a function to use for @code{\applyoutput}; it blanks +note-heads on the center-line: + [EMAIL PROTECTED] +(define (blanker grob grob-origin context) + (if (and (memq (ly:grob-property grob 'interfaces) + note-head-interface) + (eq? (ly:grob-property grob 'staff-position) 0)) + (set! (ly:grob-property grob 'transparent) #t))) [EMAIL PROTECTED] example + _______________________________________________ Lilypond-cvs mailing list Lilypond-cvs@gnu.org http://lists.gnu.org/mailman/listinfo/lilypond-cvs