X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fextending%2Fprogramming-interface.itely;h=5e63eabcd4f96598e64c742beca832dadfedf3ca;hb=5d84bfad4626892bcffd05adcced53c8a2329047;hp=1e8e92dbbd8f084ea6f6e9684dc1049d4a98a67c;hpb=8446f57585d1bc069cb0b724650f586ddc73cd0c;p=lilypond.git diff --git a/Documentation/extending/programming-interface.itely b/Documentation/extending/programming-interface.itely index 1e8e92dbbd..5e63eabcd4 100644 --- a/Documentation/extending/programming-interface.itely +++ b/Documentation/extending/programming-interface.itely @@ -8,7 +8,7 @@ Guide, node Updating translation committishes.. @end ignore -@c \version "2.14.0" +@c \version "2.19.24" @node Interfaces for programmers @chapter Interfaces for programmers @@ -18,62 +18,70 @@ not familiar with Scheme, you may wish to read our @ref{Scheme tutorial}. @menu -* Lilypond code blocks:: +* LilyPond code blocks:: * Scheme functions:: * Music functions:: * Event functions:: * Markup functions:: * Contexts for programmers:: * Callback functions:: -* Inline Scheme code:: * Difficult tweaks:: @end menu -@node Lilypond code blocks -@section Lilypond code blocks +@node LilyPond code blocks +@section LilyPond code blocks + +@cindex LilyPond code blocks +@cindex code blocks, LilyPond +@funindex #@{ @dots{} #@} +@funindex $ +@funindex # + +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 by using LilyPond code blocks, +which enable common LilyPond syntax to be used within Scheme. + +LilyPond code blocks look like -Lilypond code blocks look like @example - #@{ @var{Lilypond code} #@} + #@{ @var{LilyPond code} #@} @end example -They can be used anywhere where you can write Scheme code: the Scheme -reader actually is changed for accommodating LilyPond code blocks. When -the LilyPond code block is being read, it is parsed superficially and -replaced by a call to the LilyPond @code{parser} which is executed at -runtime to interpret the LilyPond code block. -The point of the superficial parsing is the interpretation of @code{$} -signs which can be used for splicing in expressions from the surrounding -lexical Scheme context (like @code{let} variables and function -parameters). @code{$} can be used in the following ways: +Here is a trivial example: -@table @code -@item $$ -just passes a single @code{$} to the LilyPond parser. -@item $@var{form} -will evaluate the Scheme form at runtime and splice its value as an -identifier @code{\form} into the LilyPond parser. Depending on the -value type, it may be interpreted as several different syntactic -entities. -@item #$@var{form} -will evaluate the Scheme form at runtime and splice its value as a -Scheme expression into the LilyPond parser. -@item #@var{form} -Forms in Scheme expressions started with @code{#} are read and parsed -recursively for @code{$} signs. Those are treated as follows: -@item #@dots{}$@var{variable} -splices the value of the variable into the surrounding expression. -@item #@dots{}($ @var{form} @dots{}) -splices the value of the form into the surrounding expression. As -opposed to a LilyPond level @code{$@var{form}}, you need to separate the -form with a blank, making @code{$} be recognizable as a separate Scheme -symbol. -@end table +@lilypond[verbatim,quote] +ritpp = #(define-event-function () () + #{ ^"rit." \pp #} +) + +{ c'4 e'4\ritpp g'2 } +@end lilypond -A LilyPond code block may contain anything that you can use on the right -side of an assignment. In addition, an empty LilyPond block corresponds -to a void music expression, and a LilyPond block containing multiple -music events gets turned into a sequential music expression. +LilyPond code blocks can be used anywhere where you can write Scheme +code. The Scheme reader actually is changed for accommodating +LilyPond code blocks and can deal with embedded Scheme expressions +starting with @code{$} and@w{ }@code{#}. + +The reader extracts the LilyPond code block and generates a runtime +call to the LilyPond parser to interpret the LilyPond code. +Scheme expressions embedded in the LilyPond code are evaluated in the +lexical environment of the LilyPond code block, so all local variables +and function parameters available at the point the LilyPond code block +is written may be accessed. Variables defined in other Scheme modules, +like the modules containing @code{\header} and @code{\layout} blocks, +are not accessible as Scheme variables, i.e. prefixed +with@tie{}@code{#}, but they are accessible as LilyPond variables, i.e. +prefixed with@tie{}@code{\}. + +All music generated inside the code block has its +@samp{origin} set to the current input location. + +A LilyPond code block may contain anything that you can use on the +right side of an assignment. In addition, an empty LilyPond block +corresponds to a void music expression, and a LilyPond block +containing multiple music events gets turned into a sequential music +expression. @node Scheme functions @section Scheme functions @@ -101,7 +109,7 @@ The general form for defining scheme functions is: @example function = #(define-scheme-function - (parser location @var{arg1} @var{arg2} @dots{}) + (@var{arg1} @var{arg2} @dots{}) (@var{type1?} @var{type2?} @dots{}) @var{body}) @end example @@ -110,17 +118,12 @@ function = where @multitable @columnfractions .33 .66 -@item @code{parser} -@tab needs to be literally @code{parser} in order to give LilyPond code -blocks (@code{#@{}@dots{}@code{#@}}) access to the parser. - @item @code{@var{argN}} -@tab @var{n}th argument +@tab @var{n}th argument. @item @code{@var{typeN?}} -@tab a Scheme @emph{type predicate} for which @code{@var{argN}} -must return @code{#t}. Some of these predicates are specially -recognized by the parser, see below. There is also a special form +@tab A Scheme @emph{type predicate} for which @code{@var{argN}} +must return @code{#t}. There is also a special form @code{(@emph{predicate?} @emph{default})} for specifying optional arguments. If the actual argument is missing when the function is being called, the default value is substituted instead. Default values are @@ -131,36 +134,53 @@ don't follow it with a default value, @code{#f} is used as the default. Default values are not verified with @emph{predicate?} at either definition or run time: it is your responsibility to deal with the values you specify. Default values that happen to be music expressions -are copied while setting @code{origin} to the @code{location} parameter. +are copied while setting @code{origin} to the current input location. @item @code{@var{body}} @tab A sequence of Scheme forms evaluated in order, the last one being used as the return value of the scheme function. It may contain LilyPond code blocks enclosed in hashed braces -(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}), like described in @ref{Lilypond -code blocks}. Within LilyPond code blocks, use @code{$} to reference -function arguments (eg., @samp{$arg1}) or to start an inline Scheme -expression containing function arguments (eg., @w{@samp{$(cons arg1 -arg2)}}). If your function returns a music expression, it is cloned and -given the correct @code{origin}. +(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}), like described in +@ref{LilyPond code blocks}. Within LilyPond code blocks, use @code{#} +to reference function arguments (eg., @samp{#arg1}) or to start an +inline Scheme expression containing function arguments (eg., +@w{@samp{#(cons arg1 arg2)}}). Where normal Scheme expressions using +@code{#} don't do the trick, you might need to revert to immediate +Scheme expressions using @code{$}, for example as @samp{$music}. + +If your function returns a music expression, it is given a useful value +of @code{origin}. @end multitable @noindent -Some type predicates are specially recognized by the parser and will -make the parser look for the respective arguments in LilyPond syntax -rather than in Scheme syntax. Currently these are @code{ly:music?}, -@code{markup?}, @code{ly:pitch?}, and @code{ly:duration?}. - -If you really want to input one of the special items as a Scheme rather -than a LilyPond expression, you may write them as a Scheme expression -that calls @code{ly:export} at its outermost level. - -Other type predicates, including user-defined ones, will make the -respective argument only be accepted as a Scheme expression, usually -introduced with @code{#} or as the result of calling a scheme function -itself. - -For a list of available type predicates, see +Suitability of arguments for the predicates is determined by +actually calling the predicate after LilyPond has already converted them +into a Scheme expression. As a consequence, the argument can be +specified in Scheme syntax if desired (introduced with @code{#} or as +the result of calling a scheme function), but LilyPond will also convert +a number of LilyPond constructs into Scheme before actually checking the +predicate on them. Currently, those include music, postevents, simple +strings (with or without quotes), numbers, full markups and markup +lists, score, book, bookpart, context definition and output definition +blocks. + +Some +ambiguities LilyPond sorts out by checking with predicate +functions: is @samp{-3} a fingering postevent or a negative number? Is +@code{"a" 4} in lyric mode a string followed by a number, or a lyric +event of duration @code{4}? LilyPond tries the argument +predicate on successive interpretations until success, with an +order designed to minimize inconsistent interpretations and +lookahead. + +For example, a predicate accepting both music expressions and +pitches will consider @code{c''} to be a pitch rather than a music +expression. Immediately following durations or postevents will +change that interpretation. It's best to avoid overly +permissive predicates like @code{scheme?} when the application +rather calls for more specific argument types. + +For a list of available predefined type predicates, see @ruser{Predefined type predicates}. @seealso @@ -177,49 +197,85 @@ Installed Files: @subsection Scheme function usage Scheme functions can be called pretty much anywhere where a Scheme -expression starting with @code{#} can be written. You call a scheme -function by writing its name preceded by @code{\}, followed by its -arguments. The last argument can't be an optional argument. If there -are several optional arguments in a row, they are filled with values -left to right. Once an optional argument can't match input, it and all -immediately following optional arguments are replaced with their default -values, and the matching continues with the next non-optional argument. +expression starting with @code{#} can be written. You call a +scheme function from LilyPond by writing its name preceded by +@code{\}, followed by its arguments. Once an optional argument +predicate does not match an argument, LilyPond skips this and all +following optional arguments, replacing them with their specified +default, and @q{backs up} the argument that did not match to the +place of the next mandatory argument. Since the backed up +argument needs to go somewhere, optional arguments are not +actually considered optional unless followed by a mandatory +argument. + +There is one exception: if you write @code{\default} in the place of an +optional argument, this and all following optional arguments are skipped +and replaced by their default. This works even when no mandatory +argument follows since @code{\default} does not need to get backed up. +The @code{mark} and @code{key} commands make use of that trick to +provide their default behavior when just followed by @code{\default}. Apart from places where a Scheme value is required, there are a few -places where @code{#} expressions are accepted and evaluated for their -side effects but otherwise ignored. Mostly those are the places where -an assignment would be acceptable as well. - -There are a few special places where an argument matching -@code{ly:music?} has to be either a music identifier or a music -expression enclosed in @code{@{}@dots{}@code{@}} or -@code{<<}@dots{}@code{>>} explicitly, so that possibly following -optional durations or postevents can't be confused with additional -arguments. One obvious place is before a @code{ly:duration?} -predicate. Another is as the last argument of a scheme function when it -is used in a place where such optional parts could be considered either -part of the music argument or not. - -In those rare cases, you have to delimit your music arguments -appropriately to spare LilyPond from getting confused. +places where @code{#} expressions are currently accepted and evaluated +for their side effects but otherwise ignored. Mostly those are the +places where an assignment would be acceptable as well. + +Since it is a bad idea to return values that can be misinterpreted in +some context, you should use normal scheme functions only for those +cases where you always return a useful value, and use void scheme +functions (@pxref{Void scheme functions}) otherwise. + +For convenience, scheme functions may also be called directly from +Scheme bypassing the LilyPond parser. Their name can be used like +the name of an ordinary function. Typechecking of the arguments +and skipping optional arguments will happen in the same manner as +when called from within LilyPond, with the Scheme value +@code{*unspecified*} taking the role of the @code{\default} +reserved word for explicitly skipping optional arguments. @node Void scheme functions @subsection Void scheme functions - -Sometimes a function is only executed for its side effects. In that -case, using a scheme function means that its value will not usually be -considered: +@funindex define-void-function +@funindex \void + +Sometimes a procedure is executed in order to perform an action rather +than return a value. Some programming languages (like C and Scheme) use +functions for either concept and just discard the returned value +(usually by allowing any expression to act as statement, ignoring the +result). This is clever but error-prone: most C compilers nowadays +offer warnings for various non-``void'' expressions being discarded. +For many functions executing an action, the Scheme standards declare the +return value to be unspecified. LilyPond's Scheme interpreter Guile has +a unique value @code{*unspecified*} that it usually (such when using +@code{set!} directly on a variable) but unfortunately not consistently +returns in such cases. + +Defining a LilyPond function with @code{define-void-function} makes +sure that this special value (the only value satisfying the predicate +@code{void?}) will be returned. @example noPointAndClick = -#(define-scheme-function - (parser location) +#(define-void-function + () () (ly:set-option 'point-and-click #f)) -... +@dots{} \noPointAndClick % disable point and click @end example +If you want to evaluate an expression only for its side-effect and +don't want any value it may return interpreted, you can do so by +prefixing it with @code{\void}: + +@example +\void #(hashq-set! some-table some-key some-value) +@end example + +That way, you can be sure that LilyPond will not assign meaning to the +returned value regardless of where it encounters it. This will also +work for music functions such as @code{\displayMusic}. + @node Music functions @section Music functions @@ -250,14 +306,14 @@ The general form for defining music functions is: @example function = #(define-music-function - (parser location @var{arg1} @var{arg2} @dots{}) + (@var{arg1} @var{arg2} @dots{}) (@var{type1?} @var{type2?} @dots{}) @var{body}) @end example @noindent quite in analogy to @ref{Scheme function definitions}. More often than -not, @var{body} will be a @ref{Lilypond code blocks, Lilypond code block}. +not, @var{body} will be a @ref{LilyPond code blocks, LilyPond code block}. For a list of available type predicates, see @ruser{Predefined type predicates}. @@ -275,39 +331,32 @@ Installed Files: @node Music function usage @subsection Music function usage -Music functions may currently be used in three places. Depending on -where they are used, restrictions apply in order to be able to parse -them unambiguously. The result a music function returns must be -compatible with the context in which it is called. +A @q{music function} has to return an expression matching the predicate +@code{ly:music?}. This makes music function calls suitable as arguments +of type @code{ly:music?} for another music function call. + +When using a music function call in other contexts, the context may +cause further semantic restrictions. @itemize @item -At top level in a music expression. There are no special restrictions -on the argument list. +At the top level in a music expression a post-event is not accepted. @item -As a post-event, explicitly started with a direction indicator (one of -@code{-}, @code{^}, @w{and @code{_}}). All trailing arguments of the -music function with the predicate @code{ly:music?} will get parsed also -as post-events (if the last argument is a scheme function, this will -hold for trailing @code{ly:music?} arguments of the scheme function -instead). Note that returning a post-event will be acceptable for music -functions called as normal music, leading to a result roughly equivalent -to -@example -s 1*0-\fun -@end example +When a music function (as opposed to an event function) returns an +expression of type post-event, LilyPond requires one of the named +direction indicators (@code{-}, @code{^}, @w{and @code{_}}) in order to +properly integrate the post-event produced by the music function call +into the surrounding expression. @item -As a chord constituent. All trailing arguments of the music function -with the predicate @code{ly:music?} will get parsed also as chord -constituents. +As a chord constituent. The returned expression must be of a +@code{rhythmic-event} type, most likely a @code{NoteEvent}. @end itemize @noindent -The special rules for trailing arguments make it possible to write -polymorphic functions like @code{\tweak} that can be applied to -different constructs. +@q{Polymorphic} functions, like @code{\tweak}, can be applied to +post-events, chord constituent and top level music expressions. @node Simple substitution functions @subsection Simple substitution functions @@ -333,10 +382,10 @@ using a @code{pair?} variable: @example manualBeam = #(define-music-function - (parser location beg-end) + (beg-end) (pair?) #@{ - \once \override Beam #'positions = $beg-end + \once \override Beam.positions = #beg-end #@}) \relative c' @{ @@ -352,10 +401,10 @@ music expression: @lilypond[quote,verbatim,ragged-right] manualBeam = #(define-music-function - (parser location beg end) + (beg end) (number? number?) #{ - \once \override Beam #'positions = $(cons beg end) + \once \override Beam.positions = #(cons beg end) #}) \relative c' { @@ -363,6 +412,55 @@ manualBeam = } @end lilypond +@funindex \temporary +@cindex temporary overrides +@cindex overrides, temporary +@cindex properties, popping previous value + +Properties are maintained conceptually using one stack per property +per grob per context. Music functions may need to override one or +several properties for the duration of the function, restoring them +to their previous value before exiting. However, normal overrides +pop and discard the top of the current property stack before +pushing to it, so the previous value of the property is lost when it +is overridden. When the previous value must be preserved, prefix the +@code{\override} command with @code{\temporary}, like this: + +@example +\temporary \override @dots{} +@end example + +The use of @code{\temporary} causes the (usually set) @code{pop-first} +property in the override to be cleared, so the previous value is not +popped off the property stack before pushing the new value onto it. +When a subsequent @code{\revert} pops off the temporarily overriden +value, the previous value will re-emerge. + +In other words, calling @code{\temporary \override} and @code{\revert} +in succession on the same property will have a net effect of zero. +Similarly, pairing @code{\temporary} and @code{\undo} on the same +music containing overrides will have a net effect of zero. + +Here is an example of a music function which makes use of this. +The use of @code{\temporary} ensures the values of the +@code{cross-staff} and @code{style} properties are restored on exit +to whatever values they had when the @code{crossStaff} function was +called. Without @code{\temporary} the default values would have been +set on exit. + +@example +crossStaff = +#(define-music-function (notes) (ly:music?) + (_i "Create cross-staff stems") + #@{ + \temporary \override Stem.cross-staff = #cross-staff-connect + \temporary \override Flag.style = #'no-flag + #notes + \revert Stem.cross-staff + \revert Flag.style +#@}) +@end example + @node Mathematics in functions @subsection Mathematics in functions @@ -373,21 +471,21 @@ addition to simple substitution, @lilypond[quote,verbatim,ragged-right] AltOn = #(define-music-function - (parser location mag) + (mag) (number?) #{ - \override Stem #'length = $(* 7.0 mag) - \override NoteHead #'font-size = - $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + \override Stem.length = #(* 7.0 mag) + \override NoteHead.font-size = + #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) #}) AltOff = { - \revert Stem #'length - \revert NoteHead #'font-size + \revert Stem.length + \revert NoteHead.font-size } -\relative c' { - c2 \AltOn #0.5 c4 c +\relative { + c'2 \AltOn #0.5 c4 c \AltOn #1.5 c c \AltOff c2 } @end lilypond @@ -398,19 +496,19 @@ This example may be rewritten to pass in music expressions, @lilypond[quote,verbatim,ragged-right] withAlt = #(define-music-function - (parser location mag music) + (mag music) (number? ly:music?) #{ - \override Stem #'length = $(* 7.0 mag) - \override NoteHead #'font-size = - $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) - $music - \revert Stem #'length - \revert NoteHead #'font-size + \override Stem.length = #(* 7.0 mag) + \override NoteHead.font-size = + #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + #music + \revert Stem.length + \revert NoteHead.font-size #}) -\relative c' { - c2 \withAlt #0.5 { c4 c } +\relative { + c'2 \withAlt #0.5 { c4 c } \withAlt #1.5 { c c } c2 } @end lilypond @@ -432,10 +530,10 @@ without arguments, @example displayBarNum = #(define-music-function - (parser location) + () () (if (eq? #t (ly:get-option 'display-bar-numbers)) - #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} + #@{ \once \override Score.BarNumber.break-visibility = ##f #@} #@{#@})) @end example @@ -450,12 +548,12 @@ lilypond -d display-bar-numbers FILENAME.ly @node Void music functions @subsection Void music functions -A music function must return a music expression. If you want to execute -a function only for its side effect, it might make more sense to use a -scheme function instead. But there may be cases where you sometimes -want to produce a music expression, and sometimes not (like in the -previous example). Returning a @code{void} music expression via -@code{#@{ #@}} will do that. +A music function must return a music expression. If you want to +execute a function only for its side effect, you should use +@code{define-void-function}. But there may be cases where you +sometimes want to produce a music expression, and sometimes not (like +in the previous example). Returning a @code{void} music expression +via @code{#@{ #@}} will achieve that. @node Event functions @section Event functions @@ -468,10 +566,10 @@ the syntax of constructs you want to replace. For example, if you want to write dynamics commands, those are usually attached without direction indicator, like @code{c'\pp}. Here is a way to write arbitrary dynamics: -@lilypond[quote,verbatim,raggedright] -dyn=#(define-event-function (parser location arg) (markup?) +@lilypond[quote,verbatim,ragged-right] +dyn=#(define-event-function (arg) (markup?) (make-dynamic-script arg)) -\relative c' { c\dyn pfsss } +\relative { c'\dyn pfsss } @end lilypond You could do the same using a music function, but then you always would have to write a direction indicator before calling it, like @@ -496,21 +594,49 @@ Markups are implemented as special Scheme functions which produce a @subsection Markup construction in Scheme @cindex defining markup commands +@funindex \displayScheme + +Markup expressions are internally represented in Scheme using the +@code{markup} macro: -The @code{markup} macro builds markup expressions in Scheme while -providing a LilyPond-like syntax. For example, @example -(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") - #:larger #:line ("foo" "bar" "baz"))) +(markup @var{expr}) +@end example + +To see a markup expression in its Scheme form, use the +@code{\displayScheme} command: + +@example +\displayScheme +\markup @{ + \column @{ + \line @{ \bold \italic "hello" \raise #0.4 "world" @} + \larger \line @{ foo bar baz @} + @} +@} @end example @noindent -is equivalent to: +Compiling the code above will send the following to the display +console: + @example -#@{ \markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} - \larger \line @{ foo bar baz @} @} #@} +(markup + #:line + (#:column + (#:line + (#:bold (#:italic "hello") #:raise 0.4 "world") + #:larger + (#:line + (#:simple "foo" #:simple "bar" #:simple "baz"))))) @end example +To prevent the markup from printing on the page, use +@w{@samp{\void \displayScheme @var{markup}}}. Also, as with the +@code{\displayMusic} command, the output of @code{\displayScheme} +can be saved to an external file. See +@ref{Displaying music expressions}. + @noindent This example demonstrates the main translation rules between regular LilyPond markup syntax and Scheme markup syntax. Using @code{#@{ @@ -522,11 +648,12 @@ Scheme-only solution. @multitable @columnfractions .3 .3 @item @b{LilyPond} @tab @b{Scheme} @item @code{\markup markup1} @tab @code{(markup markup1)} -@item @code{\markup @{ markup1 markup2 ... @}} @tab - @code{(markup markup1 markup2 ... )} +@item @code{\markup @{ markup1 markup2 @dots{} @}} @tab + @code{(markup markup1 markup2 @dots{} )} @item @code{\markup-command} @tab @code{#:markup-command} @item @code{\variable} @tab @code{variable} -@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} +@item @code{\center-column @{ @dots{} @}} @tab + @code{#:center-column ( @dots{} )} @item @code{string} @tab @code{"string"} @item @code{#scheme-arg} @tab @code{scheme-arg} @end multitable @@ -613,11 +740,11 @@ New markup commands can be defined using the @code{define-markup-command} Scheme macro, at top-level. @lisp -(define-markup-command (@var{command-name} @var{layout} @var{props} @var{arg1} @var{arg2} ...) - (@var{arg1-type?} @var{arg2-type?} ...) +(define-markup-command (@var{command-name} @var{layout} @var{props} @var{arg1} @var{arg2} @dots{}) + (@var{arg1-type?} @var{arg2-type?} @dots{}) [ #:properties ((@var{property1} @var{default-value1}) - ...) ] - ..command body..) + @dots{}) ] + @dots{}command body@dots{}) @end lisp The arguments are @@ -662,6 +789,26 @@ you avoid performance pitfalls by just using Scheme arguments for the leading arguments of markup functions that take a markup as their last argument. +@funindex \markup +@cindex markup macro +@funindex interpret-markup +Markup commands have a rather complex life cycle. The body of a +markup command definition is responsible for converting the +arguments of the markup command into a stencil expression which is +returned. Quite often this is accomplished by calling the +@code{interpret-markup} function on a markup expression, passing +the @var{layout} and @var{props} arguments on to it. Those +arguments are usually only known at a very late stage in +typesetting. Markup expressions have their components assembled +into markup expressions already when @code{\markup} in a LilyPond +expression or the @code{markup} macro in Scheme is expanded. The +evaluation and typechecking of markup command arguments happens at +the time @code{\markup}/@code{markup} are interpreted. + +But the actual conversion of markup expressions into stencil +expressions by executing the markup function bodies only happens +when @code{interpret-markup} is called on a markup expression. + @node On properties @unnumberedsubsubsec On properties @@ -733,10 +880,10 @@ padding. "Draw a double box around text." (interpret-markup layout props #@{\markup \override #'(box-padding . 0.4) \box - \override #'(box-padding . 0.6) \box @{ $text @}#@})) + \override #'(box-padding . 0.6) \box @{ #text @}#@})) @end lisp -or, equivalently +or, equivalently @lisp #(define-markup-command (double-box layout props text) (markup?) @@ -775,9 +922,9 @@ now as follows: (box-padding 0.6)) "Draw a double box around text." (interpret-markup layout props - #@{\markup \override #`(box-padding . ,$inter-box-padding) \box - \override #`(box-padding . ,$box-padding) \box - @{ $text @} #@})) + #@{\markup \override #`(box-padding . ,inter-box-padding) \box + \override #`(box-padding . ,box-padding) \box + @{ #text @} #@})) @end lisp Again, the equivalent version using the markup macro would be: @@ -811,9 +958,9 @@ customized: (box-padding 0.6)) "Draw a double box around text." (interpret-markup layout props - #{\markup \override #`(box-padding . ,$inter-box-padding) \box - \override #`(box-padding . ,$box-padding) \box - { $text } #})) + #{\markup \override #`(box-padding . ,inter-box-padding) \box + \override #`(box-padding . ,box-padding) \box + { #text } #})) \markup \double-box A \markup \override #'(inter-box-padding . 0.8) \double-box A @@ -836,7 +983,7 @@ follow (documentation stripped): (number-pair?) #:category graphic #:properties ((thickness 1)) - "..documentation.." + "@dots{}documentation@dots{}" (let ((th (* (ly:output-def-lookup layout 'line-thickness) thickness)) (x (car dest)) @@ -853,7 +1000,7 @@ documentation, and is of no use for user-defined markup commands. (define-markup-command (draw-double-line layout props dest) (number-pair?) #:properties ((thickness 1)) - "..documentation.." + "@dots{}documentation@dots{}" (let ((th (* (ly:output-def-lookup layout 'line-thickness) thickness)) (x (car dest)) @@ -869,8 +1016,8 @@ Then, a property for setting the gap between two lines is added, called (number-pair?) #:properties ((thickness 1) (line-gap 0.6)) - "..documentation.." - ... + "@dots{}documentation@dots{}" + @dots{} @end lisp Finally, the code for drawing two lines is added. Two calls to @@ -905,12 +1052,18 @@ stencils are combined using @code{ly:stencil-add}: @node New markup list command definition @subsection New markup list command definition +@funindex define-markup-list-command +@funindex interpret-markup-list Markup list commands are defined with the @code{define-markup-list-command} Scheme macro, which is similar to the @code{define-markup-command} macro described in @ref{New markup command definition}, except that where the latter returns a single stencil, the former returns a list of stencils. +In a similar vein, @code{interpret-markup-list} is used instead of +@code{interpret-markup} for converting a markup list into a list +of stencils. + In the following example, a @code{\paragraph} markup list command is defined, which returns a list of justified lines, the first one being indented. The indent width is taken from the @code{props} argument. @@ -919,7 +1072,7 @@ indented. The indent width is taken from the @code{props} argument. #(define-markup-list-command (paragraph layout props args) (markup-list?) #:properties ((par-indent 2)) (interpret-markup-list layout props - #@{\markuplines \justified-lines @{ \hspace #$par-indent $args @} #@})) + #@{\markuplist \justified-lines @{ \hspace #par-indent #args @} #@})) @end example @@ -948,7 +1101,7 @@ interpreted using the @code{interpret-markup-list} function. This new markup list command can be used as follows: @example -\markuplines @{ +\markuplist @{ \paragraph @{ The art of music typography is called \italic @{(plate) engraving.@} The term derives from the traditional process of music printing. @@ -977,26 +1130,138 @@ This new markup list command can be used as follows: @cindex calling code during interpreting @funindex \applyContext +@funindex make-apply-context +@funindex ly:context-property +@funindex ly:context-set-property! +@funindex ly:context-grob-definition +@funindex ly:assoc-get +@funindex ly:context-pushpop-property + +Contexts can be modified during interpretation with Scheme code. +In a LilyPond code block, the syntax for this is: -Contexts can be modified during interpretation with Scheme code. The -syntax for this is @example \applyContext @var{function} @end example +In Scheme code, the syntax is: + +@example +(make-apply-context @var{function}) +@end example + @code{@var{function}} should be a Scheme function that takes a single argument: the context in which the @code{\applyContext} -command is being called. The following code will print the -current bar number on the standard output during the compile: +command is being called. The function can access as well as +override/set grob properties and context properties. Any actions +taken by the function that depend on the state of the context are +limited to the state of the context @emph{when the function is +called}. Also, changes effected by a call to @code{\applyContext} +remain in effect until they are directly modified again, or +reverted, even if the initial conditions that they depended on +have changed. + +The following scheme functions are useful when using +@code{\applyContext}: -@example +@table @code +@item ly:context-property +look up a context property value + +@item ly:context-set-property! +set a context property + +@item ly:context-grob-definition +@itemx ly:assoc-get +look up a grob property value + +@item ly:context-pushpop-property +do a @code{\temporary@tie{}\override} +or a @code{\revert} on a grob property +@end table + + +The following example looks up the current @code{fontSize} value, and +then doubles it: + +@lilypond[quote,verbatim] +doubleFontSize = \applyContext - #(lambda (x) - (format #t "\nWe were called in barnumber ~a.\n" - (ly:context-property x 'currentBarNumber))) -@end example + #(lambda (context) + (let ((fontSize (ly:context-property context 'fontSize))) + (ly:context-set-property! context 'fontSize (+ fontSize 6)))) + +{ + \set fontSize = -3 + b'4 + \doubleFontSize + b' +} +@end lilypond + + +The following example looks up the current colors of the +@code{NoteHead}, @code{Stem}, and @code{Beam} grobs, and then changes +each to a less saturated shade. + +@lilypond[quote,verbatim] +desaturate = +\applyContext + #(lambda (context) + (define (desaturate-grob grob) + (let* ((grob-def (ly:context-grob-definition context grob)) + (color (ly:assoc-get 'color grob-def black)) + (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color))) + (ly:context-pushpop-property context grob 'color new-color))) + (for-each desaturate-grob '(NoteHead Stem Beam))) + +\relative { + \time 3/4 + g'8[ g] \desaturate g[ g] \desaturate g[ g] + \override NoteHead.color = #darkred + \override Stem.color = #darkred + \override Beam.color = #darkred + g[ g] \desaturate g[ g] \desaturate g[ g] +} +@end lilypond +This also could be implemented as a music function, in order to +restrict the modifications to a single music block. Notice how +@code{ly:context-pushpop-property} is used both as a +@code{\temporary@tie{}\override} and as a @code{\revert}: + +@lilypond[quote,verbatim] +desaturate = +#(define-music-function + (music) (ly:music?) + #{ + \applyContext + #(lambda (context) + (define (desaturate-grob grob) + (let* ((grob-def (ly:context-grob-definition context grob)) + (color (ly:assoc-get 'color grob-def black)) + (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color))) + (ly:context-pushpop-property context grob 'color new-color))) + (for-each desaturate-grob '(NoteHead Stem Beam))) + #music + \applyContext + #(lambda (context) + (define (revert-color grob) + (ly:context-pushpop-property context grob 'color)) + (for-each revert-color '(NoteHead Stem Beam))) + #}) + +\relative { + \override NoteHead.color = #darkblue + \override Stem.color = #darkblue + \override Beam.color = #darkblue + g'8 a b c + \desaturate { d c b a } + g b d b g2 +} +@end lilypond + @node Running a function on all layout objects @subsection Running a function on all layout objects @@ -1005,20 +1270,24 @@ current bar number on the standard output during the compile: @cindex calling code on layout objects @funindex \applyOutput - The most versatile way of tuning an object is @code{\applyOutput} which works by inserting an event into the specified context -(@rinternals{ApplyOutputEvent}). Its syntax is +(@rinternals{ApplyOutputEvent}). Its syntax is either @example -\applyOutput @var{context} @var{proc} +\applyOutput @var{Context} @var{proc} +@end example +or +@example +\applyOutput @var{Context}.@var{Grob} @var{proc} @end example @noindent where @code{@var{proc}} is a Scheme function, taking three arguments. When interpreted, the function @code{@var{proc}} is called for -every layout object found in the context @code{@var{context}} at -the current time step, with the following arguments: +every layout object (with grob name @var{Grob} if specified) found +in the context @code{@var{Context}} at the current time step, with +the following arguments: @itemize @item the layout object itself, @item the context where the layout object was created, and @@ -1037,15 +1306,22 @@ note-heads on the center-line and next to it: @lilypond[quote,verbatim,ragged-right] #(define (blanker grob grob-origin context) - (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) - (< (abs (ly:grob-property grob 'staff-position)) 2)) + (if (< (abs (ly:grob-property grob 'staff-position)) 2) (set! (ly:grob-property grob 'transparent) #t))) -\relative c' { - a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2 +\relative { + a'4 e8 <<\applyOutput Voice.NoteHead #blanker a c d>> b2 } @end lilypond +To have @var{function} interpreted at the @code{Score} or @code{Staff} +level use these forms + +@example +\applyOutput Score@dots{} +\applyOutput Staff@dots{} +@end example + @node Callback functions @section Callback functions @@ -1054,17 +1330,17 @@ Properties (like @code{thickness}, @code{direction}, etc.) can be set at fixed values with @code{\override}, e.g. @example -\override Stem #'thickness = #2.0 +\override Stem.thickness = #2.0 @end example -Properties can also be set to a Scheme procedure, +Properties can also be set to a Scheme procedure: -@lilypond[fragment,verbatim,quote,relative=2] -\override Stem #'thickness = #(lambda (grob) +@lilypond[fragment,verbatim,quote] +\override Stem.thickness = #(lambda (grob) (if (= UP (ly:grob-property grob 'direction)) 2.0 7.0)) -c b a g b a g b +\relative { c'' b a g b a g b } @end lilypond @noindent @@ -1085,38 +1361,19 @@ Properties that typically use callbacks include The procedure always takes a single argument, being the grob. -If routines with multiple arguments must be called, the current grob -can be inserted with a grob closure. Here is a setting from -@code{AccidentalSuggestion}, - -@example -`(X-offset . - ,(ly:make-simple-closure - `(,+ - ,(ly:make-simple-closure - (list ly:self-alignment-interface::centered-on-x-parent)) - ,(ly:make-simple-closure - (list ly:self-alignment-interface::x-aligned-on-self))))) -@end example - -@noindent -In this example, both @code{ly:self-alignment-interface::x-aligned-on-self} and -@code{ly:self-alignment-interface::centered-on-x-parent} are called -with the grob as argument. The results are added with the @code{+} -function. To ensure that this addition is properly executed, the whole -thing is enclosed in @code{ly:make-simple-closure}. - -In fact, using a single procedure as property value is equivalent to +That procedure may access the usual value of the property, by first +calling the function that is the usual callback for that property, which +can by found in the Internals Reference or the file 'define-grobs.scm': @example -(ly:make-simple-closure (ly:make-simple-closure (list @var{proc}))) +\relative @{ + \override Flag.X-offset = #(lambda (flag) + (let ((default (ly:flag::calc-x-offset flag))) + (* default 4.0))) + c''4. d8 a4. g8 +@} @end example -@noindent -The inner @code{ly:make-simple-closure} supplies the grob as argument -to @var{proc}, the outer ensures that result of the function is -returned, rather than the @code{simple-closure} object. - From within a callback, the easiest method for evaluating a markup is to use grob-interpret-markup. For example: @@ -1125,25 +1382,30 @@ my-callback = #(lambda (grob) (grob-interpret-markup grob (markup "foo"))) @end example -@node Inline Scheme code -@section Inline Scheme code +@ignore + +@n ode Inline Scheme code +@s ection Inline Scheme code + +TODO: after this section had been written, LilyPond has improved +to the point that finding a @emph{simple} example where one would +@emph{have} to revert to Scheme has become rather hard. + +Until this section gets a rewrite, let's pretend we don't know. The main disadvantage of @code{\tweak} is its syntactical -inflexibility. For example, the following produces a syntax error. +inflexibility. For example, the following produces a syntax error +(or rather, it did so at some point in the past). @example -F = \tweak #'font-size #-3 -\flageolet +F = \tweak font-size #-3 -\flageolet -\relative c'' @{ - c4^\F c4_\F +\relative @{ + c''4^\F c4_\F @} @end example @noindent -In other words, @code{\tweak} doesn't behave like an articulation -regarding the syntax; in particular, it can't be attached with -@code{^} and @code{_}. - Using Scheme, this problem can be avoided. The route to the result is given in @ref{Adding articulation to notes (example)}, especially how to use @code{\displayMusic} as a helping guide. @@ -1156,8 +1418,8 @@ F = #(let ((m (make-music 'ArticulationEvent (ly:music-property m 'tweaks))) m) -\relative c'' @{ - c4^\F c4_\F +\relative @{ + c''4^\F c4_\F @} @end example @@ -1170,6 +1432,7 @@ font size is prepended to the property list with the written back with @code{set!}. The last element of the @code{let} block is the return value, @code{m} itself. +@end ignore @node Difficult tweaks @@ -1230,11 +1493,11 @@ of the broken tie is repositioned. (eq? (car (last-pair siblings)) grob)) (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) -\relative c'' { - \override Tie #'after-line-breaking = +\relative { + \override Tie.after-line-breaking = #my-callback - c1 ~ \break - c2 ~ c + c''1 ~ \break + c2 ~ 2 } @end lilypond @@ -1254,9 +1517,10 @@ and @code{PaperColumn}. They can be changed with the @example \overrideProperty -#"Score.NonMusicalPaperColumn" % Grob name -#'line-break-system-details % Property name -#'((next-padding . 20)) % Value +Score.NonMusicalPaperColumn % Grob name + . line-break-system-details % Property name + . next-padding % Optional subproperty name + #20 % Value @end example Note, however, that @code{\override}, applied to @@ -1272,4 +1536,3 @@ This chapter covers the various tools provided by LilyPond to help Scheme programmers get information into and out of the music streams. TODO -- figure out what goes in here and how to organize it -