X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fuser%2Fprogramming-interface.itely;h=431e029919d8e9d1f1d49719f04eccec78b99acb;hb=f9214bac21e9926dc3248416f58190c98c4167a9;hp=661d9ae09e468a6d17d653800826457a649ab9c1;hpb=3f2cea0658f4e79be7911986664297c79708f62f;p=lilypond.git diff --git a/Documentation/user/programming-interface.itely b/Documentation/user/programming-interface.itely index 661d9ae09e..431e029919 100644 --- a/Documentation/user/programming-interface.itely +++ b/Documentation/user/programming-interface.itely @@ -1,126 +1,428 @@ -@c -*-texinfo-*- -@node Interfaces for programmers -@appendix Interfaces for programmers +@c -*- coding: utf-8; mode: texinfo; -*- +@c This file is part of lilypond.tely +@ignore + Translation of GIT committish: FILL-IN-HEAD-COMMITTISH + + When revising a translation, copy the HEAD committish of the + version that you are working on. See TRANSLATION for details. +@end ignore +@node Interfaces for programmers +@chapter Interfaces for programmers +Advanced tweaks may be performed by using Scheme. If you are +not familiar with Scheme, you may wish to read our +@ref{Scheme tutorial}. @menu -* Programmer interfaces for input :: +* Music functions:: +* Programmer interfaces:: +* Building complicated functions:: * Markup programmer interface:: * Contexts for programmers:: +* Scheme procedures as properties:: @end menu -@node Programmer interfaces for input -@appendixsec Programmer interfaces for input + +@node Music functions +@section Music functions + +This section discusses how to create music functions within LilyPond. + +@menu +* Overview of music functions:: +* Simple substitution functions:: +* Paired substitution functions:: +* Mathematics in functions:: +* Void functions:: +* Functions without arguments:: +* Overview of available music functions:: +@end menu + +@node Overview of music functions +@subsection Overview of music functions + +Making a function which substitutes a variable into LilyPond +code is easy. The general form of these functions is + +@example +function = +#(define-music-function (parser location @var{var1} @var{var2}... ) + (@var{var1-type?} @var{var2-type?}...) + #@{ + @emph{...music...} + #@}) +@end example + +@noindent +where + +@multitable @columnfractions .33 .66 +@item @var{argi} @tab @var{i}th variable +@item @var{argi-type?} @tab type of variable +@item @var{...music...} @tab normal LilyPond input, using + variables as @code{#$var1}. +@end multitable + +There following input types may be used as variables +in a music function. This list is not exhaustive; see +other documentation specifically about Scheme for more +variable types. + +@multitable @columnfractions .33 .66 +@headitem Input type @tab @var{argi-type?} notation +@item Integer @tab @code{integer?} +@item Float (decimal number) @tab @code{number?} +@item Text string @tab @code{string?} +@item Markup @tab @code{markup?} +@item Music expression @tab @code{ly:music?} +@item A pair of variables @tab @code{pair?} +@end multitable + +The @code{parser} and @code{location} argument are mandatory, +and are used in some advanced situations. The @code{parser} +argument is used to access to the value of another LilyPond +variable. The @code{location} argument +is used to set the @q{origin} of the music expression that is built +by the music function, so that in case of a syntax error LilyPond +can tell the user an appropriate place to look in the input file. + + +@node Simple substitution functions +@subsection Simple substitution functions + +Here is a simple example, + +@lilypond[quote,verbatim,ragged-right] +padText = #(define-music-function (parser location padding) (number?) + #{ + \once \override TextScript #'padding = #$padding + #}) + +\relative c''' { + c4^"piu mosso" b a b + \padText #1.8 + c4^"piu mosso" d e f + \padText #2.6 + c4^"piu mosso" fis a g +} +@end lilypond + +Music expressions may be substituted as well, + +@lilypond[quote,verbatim,ragged-right] +custosNote = #(define-music-function (parser location note) + (ly:music?) + #{ + \once \override Voice.NoteHead #'stencil = + #ly:text-interface::print + \once \override Voice.NoteHead #'text = + \markup \musicglyph #"custodes.mensural.u0" + \once \override Voice.Stem #'stencil = ##f + $note + #}) + +{ c' d' e' f' \custosNote g' } +@end lilypond + +Multiple variables may be used, + +@lilypond[quote,verbatim,ragged-right] +tempoMark = #(define-music-function (parser location padding marktext) + (number? string?) +#{ + \once \override Score . RehearsalMark #'padding = $padding + \once \override Score . RehearsalMark #'extra-spacing-width = #'(+inf.0 . -inf.0) + \mark \markup { \bold $marktext } +#}) + +\relative c'' { +c2 e +\tempoMark #3.0 #"Allegro" +g c +} +@end lilypond + + +@node Paired substitution functions +@subsection Paired substitution functions + +Some @code{\override} commands require a pair of numbers +(called a @code{cons cell} in Scheme). To pass these numbers +into a function, either use a @code{pair?} variable, or +insert the @code{cons} into the music function. + +@quotation +@example +manualBeam = +#(define-music-function (parser location beg-end) + (pair?) +#@{ + \once \override Beam #'positions = #$beg-end +#@}) + +\relative @{ + \manualBeam #'(3 . 6) c8 d e f +@} +@end example +@end quotation + +@noindent +or + +@lilypond[quote,verbatim,ragged-right] +manualBeam = +#(define-music-function (parser location beg end) + (number? number?) +#{ + \once \override Beam #'positions = #(cons $beg $end) +#}) + +\relative { + \manualBeam #3 #6 c8 d e f +} +@end lilypond + + +@node Mathematics in functions +@subsection Mathematics in functions + +Music functions can involve Scheme programming in +addition to simple substitution, + +@lilypond[quote,verbatim,ragged-right] +AltOn = #(define-music-function (parser location mag) (number?) + #{ \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 +} + +{ c'2 \AltOn #0.5 c'4 c' + \AltOn #1.5 c' c' \AltOff c'2 } +@end lilypond + +@noindent +This example may be rewritten to pass in music expressions, + +@lilypond[quote,verbatim,ragged-right] +withAlt = #(define-music-function (parser location 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 #}) + +{ c'2 \withAlt #0.5 {c'4 c'} + \withAlt #1.5 {c' c'} c'2 } +@end lilypond + +@node Void functions +@subsection Void functions + +A music function must return a music expression, but sometimes we +may want to have a function which does not involve music (such as +turning off Point and Click). To do this, we return a @code{void} +music expression. + +That is why the form +that is returned is the @code{(make-music ...)}. With the +@code{'void} property set to @code{#t}, the parser is told to +actually disregard this returned music +expression. Thus the important part of the void music function is the +processing done by the function, not the music expression that is +returned. + +@example +noPointAndClick = +#(define-music-function (parser location) () + (ly:set-option 'point-and-click #f) + (make-music 'SequentialMusic 'void #t)) +... +\noPointAndClick % disable point and click +@end example + + +@node Functions without arguments +@subsection Functions without arguments + +In most cases a function without arguments should be written +with an identifier, + +@example +dolce = \markup@{ \italic \bold dolce @} +@end example + +However, in rare cases it may be useful to create a music function +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 #@} + #@{#@})) +@end example + +To actually display bar numbers where this function is called, +invoke lilypond with + +@example +lilypond -d display-bar-numbers FILENAME.ly +@end example + + +@node Overview of available music functions +@subsection Overview of available music functions + +@c fixme ; this should be move somewhere else? +The following commands are music functions + +@include identifiers.tely + + + +@node Programmer interfaces +@section Programmer interfaces + +This section contains information about mixing LilyPond +and Scheme. @menu * Input variables and Scheme:: * Internal music representation:: -* Extending music syntax:: -* Manipulating music expressions:: @end menu -@node Input variables and Scheme -@appendixsubsec Input variables and Scheme +@node Input variables and Scheme +@subsection Input variables and Scheme -The input format supports the notion of variable: in the following +The input format supports the notion of variables: in the following example, a music expression is assigned to a variable with the name @code{traLaLa}. + @example - traLaLa = \notes @{ c'4 d'4 @} +traLaLa = @{ c'4 d'4 @} @end example @noindent There is also a form of scoping: in the following example, the -@code{\paper} block also contains a @code{traLaLa} variable, which is +@code{\layout} block also contains a @code{traLaLa} variable, which is independent of the outer @code{\traLaLa}. @example - traLaLa = \notes @{ c'4 d'4 @} - \paper @{ traLaLa = 1.0 @} +traLaLa = @{ c'4 d'4 @} +\layout @{ traLaLa = 1.0 @} @end example @c In effect, each input file is a scope, and all @code{\header}, -@code{\midi} and @code{\paper} blocks are scopes nested inside that +@code{\midi}, 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 +An anonymous Scheme module is attached to each scope. An assignment of the form @example - traLaLa = \notes @{ c'4 d'4 @} +traLaLa = @{ c'4 d'4 @} @end example @noindent is internally converted to a Scheme definition @example - (define traLaLa @var{Scheme value of ``@code{\notes ... }''}) +(define traLaLa @var{Scheme value of `@code{... }'}) @end 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} by means of a second variable +variable @code{traLaLa}, and duplicated using Scheme. The result is +imported in a @code{\score} block by means of a second variable @code{twice}: -@example - traLaLa = \notes @{ c'4 d'4 @} - #(define newLa (map ly:music-deep-copy - (list traLaLa traLaLa))) - #(define twice - (make-sequential-music newLa)) +@lilypond[verbatim] +traLaLa = { c'4 d'4 } - \score @{ \twice @} -@end example +%% dummy action to deal with parser lookahead +#(display "this needs to be here, sorry!") + +#(define newLa (map ly:music-deep-copy + (list traLaLa traLaLa))) +#(define twice + (make-sequential-music newLa)) + +{ \twice } +@end lilypond -In the above example, music expressions can be `exported' from the -input to the Scheme interpreter. The opposite is also possible. By +Due to parser lookahead + +In this example, the assignment happens after parser has verified that +nothing interesting happens after @code{traLaLa = @{ ... @}}. Without +the dummy statement in the above example, the @code{newLa} definition +is executed before @code{traLaLa} is defined, leading to a syntax +error. + +The above example shows how to @q{export} music expressions 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 +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 @example - @dots{} - \score @{ #(ly:export (make-sequential-music newLa)) @} +@dots{} +@{ #(ly:export (make-sequential-music (list newLa))) @} +@end example + +Scheme code is evaluated as soon as the parser encounters it. To +define some Scheme code in a macro (to be called later), use +@ref{Void functions} or + +@example +#(define (nopc) + (ly:set-option 'point-and-click #f)) + +... +#(nopc) +@{ c'4 @} @end example + @refbugs -Mixing Scheme and lily identifiers is not possible with @code{--safe}. +Mixing Scheme and LilyPond identifiers is not possible with the +@code{--safe} option. + @node Internal music representation -@appendixsubsec Internal music representation +@subsection 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. +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: @itemize @bullet @item - music name: Each music expression has a name, for example, a note +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 @internalsref{Music -expressions}. +a @internalsref{SimultaneousMusic}. A list of all expressions +available is in the Program reference manual, under +@internalsref{Music expressions}. @item - `type' or interface: Each music name has several `types' or interface, - for example, a note is an @code{event}, but it is also a @code{note-event}, - a @code{rhythmic-event} and a @code{melodic-event}. +@q{type} or interface: Each music name has several @q{types} or +interfaces, for example, a note is an @code{event}, but it is also a +@code{note-event}, a @code{rhythmic-event}, and a +@code{melodic-event}. All classes of music are listed in the +Program reference, under +@internalsref{Music classes}. - All classes of music are listed in the internals manual, under - @internalsref{Music classes}. @item -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. +C++ object: Each music object is represented by an object of the C++ +class @code{Music}. @end itemize The actual information of a music expression is stored in properties. @@ -130,183 +432,431 @@ 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, +music objects in its properties. A list of objects can be stored in +the @code{elements} property of a music object, or a single @q{child} +music object in the @code{element} object. For example, @internalsref{SequentialMusic} has its children in @code{elements}, and @internalsref{GraceMusic} has its single argument in -@code{element}. The body of a repeat is in @code{element} property of -@internalsref{RepeatedMusic}, and the alternatives in @code{elements}. +@code{element}. The body of a repeat is stored in the @code{element} +property of @internalsref{RepeatedMusic}, and the alternatives in +@code{elements}. + +@node Building complicated functions +@section Building complicated functions +This section explains how to gather the information necessary +to create complicated music functions. + +@menu +* Displaying music expressions:: +* Music properties:: +* Doubling a note with slurs (example):: +* Adding articulation to notes (example):: +@end menu -@node Extending music syntax -@appendixsubsec Extending music syntax -The syntax of composite music expressions, like -@code{\repeat}, @code{\transpose} and @code{\context} -follows the general form of +@node Displaying music expressions +@subsection Displaying music expressions + +@cindex internal storage +@funindex \displayMusic +@funindex \displayLilyMusic + +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} @example - \@code{keyword} @var{non-music-arguments} @var{music-arguments} +@{ + \displayMusic @{ c'4\f @} +@} @end 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 +@noindent +will display @example -\applymusic #@var{func} @var{music} +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) + (make-music + 'AbsoluteDynamicEvent + 'text + "f"))))) @end example -A music function is created with @code{ly:make-music-function}, +By default, LilyPond will print these messages to the console along +with all the other messages. To split up these messages and save +the results of @code{\display@{STUFF@}}, redirect the output to +a file. @example - (ly:make-music-function +lilypond file.ly >display.txt @end example -@code{\applymusic} takes a Scheme function and a Music expression as -argument. This is encoded in its first argument, +With a bit of reformatting, the above information is +easier to read, @example - (list procedure? ly:music?) +(make-music 'SequentialMusic + 'elements (list (make-music 'EventChord + 'elements (list (make-music 'NoteEvent + 'duration (ly:make-duration 2 0 1 1) + 'pitch (ly:make-pitch 0 0 0)) + (make-music 'AbsoluteDynamicEvent + 'text "f"))))) @end 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 -@code{ly:make-music-function}. The body is function simply calls the -function +A @code{@{ ... @}} music sequence has the name @code{SequentialMusic}, +and its inner expressions are stored as a list in its @code{'elements} +property. A note is represented as an @code{EventChord} expression, +containing a @code{NoteEvent} object (storing the duration and +pitch properties) and any extra information (in this case, an +@code{AbsoluteDynamicEvent} with a @code{"f"} text property. + + +@node Music properties +@subsection Music properties + +The @code{NoteEvent} object is the first object of the +@code{'elements} property of @code{someNote}. @example - (lambda (where func music) - (func music)) +someNote = c' +\displayMusic \someNote +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)))) @end example -The above Scheme code only defines the functionality. The tag -@code{\applymusic} is selected by defining +The @code{display-scheme-music} function is the function used by +@code{\displayMusic} to display the Scheme representation of a music +expression. @example - apply = #(ly:make-music-function - (list procedure? ly:music?) - (lambda (where func music) - (func music))) +#(display-scheme-music (first (ly:music-property someNote 'elements))) +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) @end example -Examples of the use of @code{\applymusic} are in the next section. +Then the note pitch is accessed through the @code{'pitch} property +of the @code{NoteEvent} object, +@example +#(display-scheme-music + (ly:music-property (first (ly:music-property someNote 'elements)) + 'pitch)) +===> +(ly:make-pitch 0 0 0) +@end example -@node Manipulating music expressions -@appendixsubsec Manipulating music expressions +The note pitch can be changed by setting this 'pitch property, -Music objects and their properties can be accessed and manipulated -directly, through the @code{\applymusic} mechanism. -The syntax for @code{\applymusic} is @example -\applymusic #@var{func} @var{music} +#(set! (ly:music-property (first (ly:music-property someNote 'elements)) + 'pitch) + (ly:make-pitch 0 1 0)) ;; set the pitch to d'. +\displayLilyMusic \someNote +===> +d' @end example -@noindent -This means that the scheme function @var{func} is called with -@var{music} 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 -@code{ly:music-set-property!}. - -An example is a function that reverses the order of elements in -its argument: -@lilypond[verbatim,raggedright] - #(define (rev-music-1 m) - (ly:music-set-property! m 'elements (reverse - (ly:music-property m 'elements))) - m) - \score { \notes \applymusic #rev-music-1 { c4 d4 } } -@end lilypond -The use of such a function is very limited. The effect of this -function is void when applied to an argument which is does not have -multiple children. The following function application has no effect: +@node Doubling a note with slurs (example) +@subsection Doubling a note with slurs (example) + +Suppose we want to create a function which translates +input like @samp{a} into @samp{a( a)}. We begin +by examining the internal representation of the music +we want to end up with. + +@example +\displayMusic@{ a'( a') @} +===> +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)) + (make-music + 'SlurEvent + 'span-direction + -1))) + (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)) + (make-music + 'SlurEvent + 'span-direction + 1))))) +@end example + +The bad news is that the @code{SlurEvent} expressions +must be added @q{inside} the note (or more precisely, +inside the @code{EventChord} expression). + +Now we examine the input, + +@example +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)))))) +@end example + +So in our function, we need to clone this expression (so that we +have two notes to build the sequence), add @code{SlurEvents} to the +@code{'elements} property of each one, and finally make a +@code{SequentialMusic} with the two @code{EventChords}. @example - \applymusic #rev-music-1 \grace @{ c4 d4 @} +doubleSlur = #(define-music-function (parser location note) (ly:music?) + "Return: @{ note ( note ) @}. + `note' is supposed to be an EventChord." + (let ((note2 (ly:music-deep-copy note))) + (set! (ly:music-property note 'elements) + (cons (make-music 'SlurEvent 'span-direction -1) + (ly:music-property note 'elements))) + (set! (ly:music-property note2 'elements) + (cons (make-music 'SlurEvent 'span-direction 1) + (ly:music-property note2 'elements))) + (make-music 'SequentialMusic 'elements (list note note2)))) +@end example + + +@node Adding articulation to notes (example) +@subsection Adding articulation to notes (example) + +The easy way to add articulation to notes is to merge two music +expressions into one context, as explained in +@ref{Creating contexts}. However, suppose that we want to write +a music function which does this. + +A @code{$variable} inside the @code{#@{...#@}} notation is like +using a regular @code{\variable} in classical LilyPond +notation. We know that + +@example +@{ \music -. -> @} @end example @noindent -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. +will not work in LilyPond. We could avoid this problem by attaching +the articulation to a fake note, -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. @example -#(define (reverse-music music) - (let* ((elements (ly:music-property music 'elements)) - (child (ly:music-property music 'element)) - (reversed (reverse elements))) +@{ << \music s1*0-.-> @} +@end example + +@noindent +but for the sake of this example, we will learn how to do this in +Scheme. We begin by examining our input and desired output, + +@example +% input +\displayMusic c4 +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)))) +===== +% desired output +\displayMusic c4-> +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)) + (make-music + 'ArticulationEvent + 'articulation-type + "marcato"))) +@end example - ; set children - (ly:music-set-property! music 'elements reversed) +We see that a note (@code{c4}) is represented as an @code{EventChord} +expression, with a @code{NoteEvent} expression in its elements list. To +add a marcato articulation, an @code{ArticulationEvent} expression must +be added to the elements property of the @code{EventChord} +expression. - ; recurse - (if (ly:music? child) (reverse-music child)) - (map reverse-music reversed) +To build this function, we begin with - music)) +@example +(define (add-marcato event-chord) + "Add a marcato ArticulationEvent to the elements of `event-chord', + which is supposed to be an EventChord expression." + (let ((result-event-chord (ly:music-deep-copy event-chord))) + (set! (ly:music-property result-event-chord 'elements) + (cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements))) + result-event-chord)) @end example -A slightly more elaborate example is in -@inputfileref{input/test,reverse-music.ly}. +The first line is the way to define a function in Scheme: the function +name is @code{add-marcato}, and has one variable called +@code{event-chord}. In Scheme, the type of variable is often clear +from its name. (this is good practice in other programming languages, +too!) -Some of the input syntax is also implemented as recursive music -functions. For example, the syntax for polyphony @example - <> +"Add a marcato..." @end example @noindent -is actually implemented as a recursive function that replaces the -above by the internal equivalent of +is a description of what the function does. This is not strictly +necessary, but just like clear variable names, it is good practice. + +@example +(let ((result-event-chord (ly:music-deep-copy event-chord))) +@end example + +@code{let} is used to declare local variables. Here we use one local +variable, named @code{result-event-chord}, to which we give the value +@code{(ly:music-deep-copy event-chord)}. @code{ly:music-deep-copy} is +a function specific to LilyPond, like all functions prefixed by +@code{ly:}. It is use to make a copy of a music +expression. Here we copy @code{event-chord} (the parameter of the +function). Recall that our purpose is to add a marcato to an +@code{EventChord} expression. It is better to not modify the +@code{EventChord} which was given as an argument, because it may be +used elsewhere. + +Now we have a @code{result-event-chord}, which is a +@code{NoteEventChord} expression and is a copy of @code{event-chord}. We +add the marcato to its elements list property. + +@example +(set! place new-value) +@end example + +Here, what we want to set (the "place") is the "elements" property of +@code{result-event-chord} expression + @example - << \context Voice = "1" @{ \voiceOne a @} - \context Voice = "2" @{ \voiceTwo b @} >> +(ly:music-property result-event-chord 'elements) @end 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 (@inputfileref{input/test,to-xml.ly}) +@code{ly:music-property} is the function used to access music properties +(the @code{'elements}, @code{'duration}, @code{'pitch}, etc, that we +see in the @code{\displayMusic} output above). The new value is the +former elements property, with an extra item: the +@code{MarcatoEvent} expression, which we copy from the +@code{\displayMusic} output, -@seealso +@example +(cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements)) +@end example -@file{scm/music-functions.scm}, @file{scm/music-types.scm}, -@inputfileref{input/test,add-staccato.ly}, -@inputfileref{input/test,unfold-all-repeats.ly}, and -@inputfileref{input/test,music-box.ly}. +@code{cons} is used to add an element to a list without modifying the +original list. This is what we +want: the same list as before, plus the new @code{ArticulationEvent} +expression. The order inside the elements property is not important here. +Finally, once we have added the @code{MarcatoEvent} to its elements +property, we can return @code{result-event-chord}, hence the last line of +the function. + +Now we transform the @code{add-marcato} function into a music +function, + +@example +addMarcato = #(define-music-function (parser location event-chord) + (ly:music?) + "Add a marcato ArticulationEvent to the elements of `event-chord', + which is supposed to be an EventChord expression." + (let ((result-event-chord (ly:music-deep-copy event-chord))) + (set! (ly:music-property result-event-chord 'elements) + (cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements))) + result-event-chord)) +@end example + +We may verify that this music function works correctly, + +@example +\displayMusic \addMarcato c4 +@end example @node Markup programmer interface -@appendixsec Markup programmer interface +@section Markup programmer interface +Markups are implemented as special Scheme functions which produce a +Stencil object given a number of arguments. @menu -* Markup construction in scheme:: -* Markup command definition:: +* Markup construction in Scheme:: +* How markups work internally:: +* New markup command definition:: @end menu -@node Markup construction in scheme -@appendixsubsec Markup construction in scheme -@cindex defining markup commands +@node Markup construction in Scheme +@subsection Markup construction in Scheme + +@cindex defining markup commands The @code{markup} macro builds markup expressions in Scheme while -providing a LilyPond-like syntax. For example, +providing a LilyPond-like syntax. For example, @example (markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") #:bigger #:line ("foo" "bar" "baz"))) @@ -315,189 +865,235 @@ providing a LilyPond-like syntax. For example, @noindent is equivalent to: @example -\markup \column < @{ \bold \italic "hello" \raise #0.4 "world" @} - \bigger @{ foo bar baz @} > +\markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} + \bigger \line @{ foo bar baz @} @} @end example @noindent -This example exposes the main translation rules between regular -LilyPond markup syntax and scheme markup syntax, which are summed up -is this table: -@multitable @columnfractions .5 .5 +This example demonstrates the main translation rules between regular +LilyPond markup syntax and Scheme markup syntax. + +@quotation +@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{\command} @tab @code{#:command} @item @code{\variable} @tab @code{variable} -@item @code{@{ ... @}} @tab @code{#:line ( ... )} -@item @code{\center-align < ... >} @tab @code{#:center ( ... )} +@item @code{\center-align @{ ... @}} @tab @code{#:center-align ( ... )} @item @code{string} @tab @code{"string"} @item @code{#scheme-arg} @tab @code{scheme-arg} @end multitable +@end quotation + +The whole Scheme language is accessible inside the +@code{markup} macro. For example, You may use function calls inside +@code{markup} in order to manipulate character strings. This is +useful when defining new markup commands (see +@ref{New markup command definition}). -Besides, the whole scheme language is accessible inside the -@code{markup} macro: thus, one may use function calls inside -@code{markup} in order to manipulate character strings for -instance. This proves useful when defining new markup commands (see -@ref{Markup command definition}). @refbugs -One can not feed the @code{#:line} (resp @code{#:center}, -@code{#:column}) command with a variable or the result of a function -call. E.g.: +The markup-list argument of commands such as @code{#:line}, +@code{#:center}, and @code{#:column} cannot be a variable or +the result of a function call. + @lisp -(markup #:line (fun-that-returns-markups)) +(markup #:line (function-that-returns-markups)) @end lisp -is illegal. One should use the @code{make-line-markup} (resp -@code{make-center-markup}, @code{make-column-markup}) function -instead: + +@noindent +is invalid. One should use the @code{make-line-markup}, +@code{make-center-markup}, or @code{make-column-markup} functions +instead, + @lisp -(markup (make-line-markup (fun-that-returns-markups))) +(markup (make-line-markup (function-that-returns-markups))) @end lisp -@node Markup command definition -@appendixsubsec Markup command definition + +@node How markups work internally +@subsection How markups work internally + +In a markup like + +@example +\raise #0.5 "text example" +@end example + +@noindent +@code{\raise} is actually represented by the @code{raise-markup} +function. The markup expression is stored as + +@example +(list raise-markup 0.5 (list simple-markup "text example")) +@end example + +When the markup is converted to printable objects (Stencils), the +@code{raise-markup} function is called as + +@example +(apply raise-markup + @var{\layout object} + @var{list of property alists} + 0.5 + @var{the "text example" markup}) +@end example + +The @code{raise-markup} function first creates the stencil for the +@code{text example} 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}. + + +@node New markup command definition +@subsection New markup command definition New markup commands can be defined -with the @code{def-markup-command} scheme macro. +with the @code{define-markup-command} Scheme macro. + @lisp -(def-markup-command (@var{command-name} @var{paper} @var{props} @var{arg1} @var{arg2} ...) +(define-markup-command (@var{command-name} @var{layout} @var{props} @var{arg1} @var{arg2} ...) (@var{arg1-type?} @var{arg2-type?} ...) ..command body..) @end lisp -The arguments signify +The arguments are @table @var @item argi @var{i}th command argument @item argi-type? a type predicate for the i@var{th} argument -@item paper -the `paper' definition +@item layout +the @q{layout} definition @item props -a list of alists, containing all active properties. +a list of alists, containing all active properties. @end 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: +which selects a small caps font. Normally we could select the +small caps font, -@verbatim - \markup { \override #'(font-shape . caps) Text-in-caps } -@end verbatim +@example +\markup @{ \override #'(font-shape . caps) Text-in-caps @} +@end example +@noindent This selects the caps font by setting the @code{font-shape} property to @code{#'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 markup type. Therefore, the start of the +To make the above available as @code{\smallcaps} command, we must +define a function using @code{define-markup-command}. The command should +take a single argument of type @code{markup}. Therefore the start of the definition should read + @example - (def-markup-command (smallcaps paper props argument) (markup?) +(define-markup-command (smallcaps layout props argument) (markup?) @end example @noindent What follows is the content of the command: we should interpret -the @code{argument} as a markup, i.e. +the @code{argument} as a markup, i.e., @example - (interpret-markup paper @dots{} argument) +(interpret-markup layout @dots{} argument) @end example @noindent This interpretation should add @code{'(font-shape . caps)} to the active -properties, so we substitute the following for the @dots{} in the +properties, so we substitute the following for the @dots{} in the above example: @example - (cons (list '(font-shape . caps) ) props) +(cons (list '(font-shape . caps) ) props) @end example @noindent The variable @code{props} is a list of alists, and we prepend to it by -consing a list with the extra setting. +cons'ing a list with the extra setting. -Suppose that we are typesetting a recitative in an opera, and +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 +custom manner. Names should be printed with small caps and moved a bit to the left and top. We will define a @code{\character} command -that takes into account the needed translation, and uses the newly +which takes into account the necessary translation and uses the newly defined @code{\smallcaps} command: -@verbatim -#(def-markup-command (character paper props name) (string?) - "Print the character name in small caps, translated to the left and - top. Syntax: \\character #\"name\"" - (interpret-markup paper props - (markup "" #:translate (cons -4 2) #:smallcaps name))) -@end verbatim +@example +#(define-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 #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) +@end example There is one complication that needs explanation: texts above and below the staff are moved vertically to be at a certain distance (the -@code{padding} property) from the staff and the notes. To make sure +@code{padding} property) from the staff and the notes. To make sure that this mechanism does not annihilate the vertical effect of our -@code{#:translate}, we add an empty string (@code{""}) before the -translated text. Now the @code{""} will be put above the notes, and the -@code{name} is moved in relation to that empty string. The net effect is +@code{#:translate}, we add an empty string (@code{#:hspace 0}) before the +translated text. Now the @code{#:hspace 0} will be put above the notes, +and the +@code{name} 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: -@verbatim -\score { - \notes { \fatText - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" - } -} -@end verbatim - -@lilypond[raggedright] -#(def-markup-command (smallcaps paper props str) (string?) - "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" - (interpret-markup paper 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 paper props name) (string?) - "Print the character name in small caps, translated to the left and - top. Syntax: \\character #\"name\"" - (interpret-markup paper props - (markup "" #:translate (cons -4 0) #:smallcaps name))) - -\score { - \notes { \fatText - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" - } + +@example +@{ + c''^\markup \character #"Cleopatra" + e'^\markup \character #"Giulio Cesare" +@} +@end example + +@lilypond[quote,ragged-right] +#(define-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))))) + +#(define-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 #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) + +{ + c''^\markup \character #"Cleopatra" c'' c'' c'' + e'^\markup \character #"Giulio Cesare" e' e' e' } @end lilypond We have used the @code{caps} font shape, but suppose that our font -that 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 +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: @example -#(def-markup-command (smallcaps paper props str) (string?) - "Print the string argument in small caps." - (interpret-markup paper 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))))) +#(define-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))))) @end example The @code{smallcaps} command first splits its string argument into @@ -505,19 +1101,22 @@ 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 +(@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, +translated to the left (@code{#:translate (cons -0.6 0) ...}). Then, the markups built for each token are put in a line by -@code{(make-line-markup ...)}. Finally, the resulting markup is passed -to the @code{interpret-markup} function, with the @code{paper} and +@code{(make-line-markup ...)}. Finally, the resulting markup is passed +to the @code{interpret-markup} function, with the @code{layout} and @code{props} arguments. +Note: there is now an internal command @code{\smallCaps} which can +be used to set text in small caps. See +@ref{Overview of text markup commands} for details. -@node Contexts for programmers -@appendixsec Contexts for programmers +@node Contexts for programmers +@section Contexts for programmers @menu * Context evaluation:: @@ -525,71 +1124,141 @@ to the @code{interpret-markup} function, with the @code{paper} and @end menu @node Context evaluation -@appendixsubsec Context evaluation +@subsection Context evaluation @cindex calling code during interpreting -@cindex @code{\applycontext} +@funindex \applyContext -Contexts can be modified during interpretation with Scheme code. The +Contexts can be modified during interpretation with Scheme code. The syntax for this is @example - \applycontext @var{function} +\applyContext @var{function} @end example @var{function} should be a Scheme function taking a single argument, -being the context to apply it to. The following code will print the +being the context to apply it to. The following code will print the current bar number on the standard output during the compile: @example - \applycontext - #(lambda (x) - (format #t "\nWe were called in barnumber ~a.\n" - (ly:context-property x 'currentBarNumber))) +\applyContext + #(lambda (x) + (format #t "\nWe were called in barnumber ~a.\n" + (ly:context-property x 'currentBarNumber))) @end example @node Running a function on all layout objects -@appendixsubsec Running a function on all layout objects +@subsection Running a function on all layout objects @cindex calling code on layout objects -@cindex @code{\applyoutput} +@funindex \applyOutput -The most versatile way of tuning an object is @code{\applyoutput}. Its +The most versatile way of tuning an object is @code{\applyOutput}. Its syntax is @example -\applyoutput @var{proc} +\applyOutput @var{context} @var{proc} @end example @noindent 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: +object found in the context @var{context}, with the following +arguments: @itemize @bullet @item the layout object itself, @item the context where the layout object was created, and -@item the context where @code{\applyoutput} is processed. +@item the context where @code{\applyOutput} is processed. @end itemize -In addition, the cause of the layout object, i.e. the music +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 @internalsref{NoteHead} event, and for a @internalsref{Stem} object, this is a @internalsref{NoteHead} object. -Here is a function to use for @code{\applyoutput}; it blanks +Here is a function to use for @code{\applyOutput}; it blanks note-heads on the center-line: @example (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)) + (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))) +@end example + + +@node Scheme procedures as properties +@section Scheme procedures as properties - (set! (ly:grob-property grob 'transparent) #t))) +Properties (like thickness, direction, etc.) can be set at fixed values +with \override, e.g. + +@example +\override Stem #'thickness = #2.0 @end example +Properties can also be set to a Scheme procedure, + +@lilypond[fragment,verbatim,quote,relative=2] +\override Stem #'thickness = #(lambda (grob) + (if (= UP (ly:grob-property grob 'direction)) + 2.0 + 7.0)) +c b a g b a g b +@end lilypond + +@noindent +In this case, the procedure is executed as soon as the value of the +property is requested during the formatting process. + +Most of the typesetting engine is driven by such callbacks. +Properties that typically use callbacks include + +@table @code +@item stencil + The printing routine, that constructs a drawing for the symbol +@item X-offset + The routine that sets the horizontal position +@item X-extent + The routine that computes the width of an object +@end table + +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 + +@example +(ly:make-simple-closure (ly:make-simple-closure (list @var{proc}))) +@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.