From: Graham Percival Date: Sun, 4 Oct 2009 13:33:54 +0000 (+0100) Subject: Docs: move Programming interfaces into Extending. X-Git-Tag: release/2.13.6-1~56 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=193cb7a76b5dd0c8fe236a9b95cd6ef11f044328;p=lilypond.git Docs: move Programming interfaces into Extending. --- diff --git a/Documentation/extending.tely b/Documentation/extending.tely index 5f374fc465..bb985e2c36 100644 --- a/Documentation/extending.tely +++ b/Documentation/extending.tely @@ -45,6 +45,7 @@ by the authors. @menu * Scheme tutorial:: Programming inside LilyPond. +* Interfaces for programmers:: How to interface with scheme. Appendices @@ -60,6 +61,7 @@ Appendices @include extending/scheme-tutorial.itely +@include extending/programming-interface.itely @include fdl.itexi diff --git a/Documentation/extending/programming-interface.itely b/Documentation/extending/programming-interface.itely new file mode 100644 index 0000000000..471276f0b4 --- /dev/null +++ b/Documentation/extending/programming-interface.itely @@ -0,0 +1,1506 @@ +@c -*- coding: utf-8; mode: texinfo; -*- + +@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 + +@c \version "2.12.0" + +@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 +@rlearning{Scheme tutorial}. + +@menu +* Music functions:: +* Programmer interfaces:: +* Building complicated functions:: +* Markup programmer interface:: +* Contexts for programmers:: +* Scheme procedures as properties:: +* Using Scheme code instead of \tweak:: +* Difficult tweaks:: +@end menu + + +@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:: +@end menu + +@node Overview of music functions +@subsection Overview of music functions + +Making a function that 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{vari}... ) + (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) + #@{ + @emph{...music...} + #@}) +@end example + +@noindent +where + +@multitable @columnfractions .33 .66 +@item @var{vari} @tab @var{i}th variable +@item @var{vari-type?} @tab type of @var{i}th variable +@item @var{...music...} @tab normal LilyPond input, using + variables as @code{#$var1}, etc. +@end multitable + +The 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{vari-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} arguments are mandatory, +and are used in some advanced situations. The @code{parser} +argument is used to gain 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] +tempoPadded = #(define-music-function (parser location padding tempotext) + (number? string?) +#{ + \once \override Score.MetronomeMark #'padding = $padding + \tempo \markup { \bold $tempotext } +#}) + +\relative c'' { + \tempo \markup { "Low tempo" } + c4 d e f g1 + \tempoPadded #4.0 #"High tempo" + g4 f e d c1 +} +@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 that 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 a variable, + +@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 @command{lilypond} with + +@example +lilypond -d display-bar-numbers FILENAME.ly +@end example + + +@node Programmer interfaces +@section Programmer interfaces + +This section contains information about mixing LilyPond +and Scheme. + +@menu +* Input variables and Scheme:: +* Internal music representation:: +@end menu + + +@node Input variables and Scheme +@subsection Input variables and Scheme + +The input format supports the notion of variables: in the following +example, a music expression is assigned to a variable with the name +@code{traLaLa}. + +@example +traLaLa = @{ c'4 d'4 @} +@end example + +@noindent + +There is also a form of scoping: in the following example, the +@code{\layout} block also contains a @code{traLaLa} variable, which is +independent of the outer @code{\traLaLa}. +@example +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{\layout} blocks are scopes nested inside that +toplevel scope. + +Both variables and scoping are implemented in the GUILE module system. +An anonymous Scheme module is attached to each scope. An assignment of +the form +@example +traLaLa = @{ c'4 d'4 @} +@end example + +@noindent +is internally converted to a Scheme definition +@example +(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} block by means of a second variable +@code{twice}: + +@lilypond[verbatim] +traLaLa = { c'4 d'4 } + +%% 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 + +@c Due to parser lookahead + +In this example, the assignment happens after the 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 + +@example +... +@{ #(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 + + +@knownissues + +Mixing Scheme and LilyPond variables is not possible with the +@code{--safe} option. + + +@node 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. + +A music object has three kinds of types: +@itemize +@item +music name: Each music expression has a name. For example, a note +leads to a @rinternals{NoteEvent}, and @code{\simultaneous} leads to +a @rinternals{SimultaneousMusic}. A list of all expressions +available is in the Internals Reference manual, under +@rinternals{Music expressions}. + +@item +@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 +Internals Reference, under +@rinternals{Music classes}. + +@item +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. +For example, a @rinternals{NoteEvent} has @code{pitch} and +@code{duration} properties that store the pitch and duration of that +note. A list of all properties available can be found in the +Internals Reference, under @rinternals{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 @q{child} +music object in the @code{element} property. For example, +@rinternals{SequentialMusic} has its children in @code{elements}, +and @rinternals{GraceMusic} has its single argument in +@code{element}. The body of a repeat is stored in the @code{element} +property of @rinternals{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 Displaying music expressions +@subsection Displaying music expressions + +@cindex internal storage +@cindex displaying music expressions +@cindex internal representation, displaying +@cindex displayMusic +@funindex \displayMusic + +When writing a music function it is often instructive to inspect how +a music expression is stored internally. This can be done with the +music function @code{\displayMusic} + +@example +@{ + \displayMusic @{ c'4\f @} +@} +@end example + +@noindent +will display + +@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 0 0)) + (make-music + 'AbsoluteDynamicEvent + 'text + "f"))))) +@end example + +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 +lilypond file.ly >display.txt +@end example + +With a bit of reformatting, the above information is +easier to read, + +@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 0 0)) + (make-music 'AbsoluteDynamicEvent + 'text "f"))))) +@end example + +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 +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 @code{display-scheme-music} function is the function used by +@code{\displayMusic} to display the Scheme representation of a music +expression. + +@example +#(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 + +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 + +The note pitch can be changed by setting this @code{'pitch} property, + +@funindex \displayLilyMusic + +@example +#(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 + + +@node Doubling a note with slurs (example) +@subsection Doubling a note with slurs (example) + +Suppose we want to create a function that translates input like +@code{a} into @code{a( a)}. We begin by examining the internal +representation of the desired result. + +@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 +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 +@ruser{Creating contexts}. However, suppose that we want to write +a music function that does this. + +A @code{$variable} inside the @code{#@{...#@}} notation is like +a regular @code{\variable} in classical LilyPond notation. We +know that + +@example +@{ \music -. -> @} +@end example + +@noindent +will not work in LilyPond. We could avoid this problem by attaching +the articulation to a fake note, + +@example +@{ << \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 + +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. + +To build this function, we begin with + +@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 + +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!) + +@example +"Add a marcato..." +@end example + +@noindent +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 @code{'elements} +list property. + +@example +(set! place new-value) +@end example + +Here, what we want to set (the @q{place}) is the @code{'elements} +property of @code{result-event-chord} expression. + +@example +(ly:music-property result-event-chord 'elements) +@end example + +@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 @code{'elements} property, with an extra item: the +@code{ArticulationEvent} expression, which we copy from the +@code{\displayMusic} output, + +@example +(cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements)) +@end example + +@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 @code{'elements} property is not important here. + +Finally, once we have added the marcato articulation to its @code{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 +@section Markup programmer interface + +Markups are implemented as special Scheme functions which produce a +@code{Stencil} object given a number of arguments. + +@menu +* Markup construction in Scheme:: +* How markups work internally:: +* New markup command definition:: +* New markup list command definition:: +@end menu + + +@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, +@example +(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") + #:larger #:line ("foo" "bar" "baz"))) +@end example + +@noindent +is equivalent to: +@example +\markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} + \larger \line @{ foo bar baz @} @} +@end example + +@noindent +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{\markup-command} @tab @code{#:markup-command} +@item @code{\variable} @tab @code{variable} +@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} +@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}). + + +@knownissues + +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 (function-that-returns-markups)) +@end lisp + +@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 (function-that-returns-markups))) +@end lisp + + +@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{define-markup-command} Scheme macro. + +@lisp +(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 are + +@table @var +@item argi +@var{i}th command argument +@item argi-type? +a type predicate for the i@var{th} argument +@item layout +the @q{layout} definition +@item props +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 a small caps font. Normally we could select the +small caps font, + +@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 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 +(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., + +@example +(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 +above example: + +@example +(cons (list '(font-shape . caps) ) props) +@end example + +@noindent +The variable @code{props} is a list of alists, and we prepend to it by +cons'ing a list with the extra setting. + + +Suppose that we are typesetting a recitative in an opera and +we would like to define a command that will show character names in a +custom manner. Names should be printed with small caps and moved a +bit up and to the left. We will define a @code{\character} command +which takes into account the necessary translation and uses the newly +defined @code{\smallcaps} command: + +@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 +that this mechanism does not annihilate the vertical effect of our +@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: + +@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 +does not have a small-caps variant. In that case we have to fake +the small caps font by setting a string in uppercase with the +first letter a little larger: + +@example +#(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 +tokens separated by spaces (@code{(string-split str #\Space)}); for +each token, a markup is built with the first letter made large and +upcased (@code{#:large (string-upcase (substring s 0 1))}), and a +second markup built with the following letters made tiny and upcased +(@code{#:tiny (string-upcase (substring s 1))}). As LilyPond +introduces a space between markups on a line, the second markup is +translated to the left (@code{#:translate (cons -0.6 0) ...}). Then, +the markups built for each token are put in a line by +@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 +@ruser{Text markup commands}, for details. + +@knownissues + +Currently, the available combinations of arguments (after the standard +@var{layout} and @var{props} arguments) to a markup command defined with +@code{define-markup-command} are limited as follows. + +@table @asis +@item (no argument) +@itemx @var{list} +@itemx @var{markup} +@itemx @var{markup markup} +@itemx @var{scm} +@itemx @var{scm markup} +@itemx @var{scm scm} +@itemx @var{scm scm markup} +@itemx @var{scm scm markup markup} +@itemx @var{scm markup markup} +@itemx @var{scm scm scm} +@end table + +@noindent +In the above table, @var{scm} represents native Scheme data types like +@q{number} or @q{string}. + +As an example, it is not possible to use a markup command @code{foo} with +four arguments defined as + +@example +#(define-markup-command (foo layout props + num1 str1 num2 str2) + (number? string? number? string?) + ...) +@end example + +@noindent +If you apply it as, say, + +@example +\markup \foo #1 #"bar" #2 #"baz" +@end example + +@cindex Scheme signature +@cindex signature, Scheme +@noindent +@command{lilypond} complains that it cannot parse @code{foo} due to its +unknown Scheme signature. + + +@node New markup list command definition +@subsection New markup list command definition +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 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. +@example +#(define-markup-list-command (paragraph layout props args) (markup-list?) + (let ((indent (chain-assoc-get 'par-indent props 2))) + (interpret-markup-list layout props + (make-justified-lines-markup-list (cons (make-hspace-markup indent) + args))))) +@end example + +Besides the usual @code{layout} and @code{props} arguments, the +@code{paragraph} markup list command takes a markup list argument, named +@code{args}. The predicate for markup lists is @code{markup-list?}. + +First, the function gets the indent width, a property here named +@code{par-indent}, from the property list @code{props}. If the +property is not found, the default value is @code{2}. Then, a +list of justified lines is made using the +@code{make-justified-lines-markup-list} function, which is related +to the @code{\justified-lines} built-in markup list command. A +horizontal space is added at the beginning using the +@code{make-hspace-markup} function. Finally, the markup list is +interpreted using the @code{interpret-markup-list} function. + +This new markup list command can be used as follows: +@example +\markuplines @{ + \paragraph @{ + The art of music typography is called \italic @{(plate) engraving.@} + The term derives from the traditional process of music printing. + Just a few decades ago, sheet music was made by cutting and stamping + the music into a zinc or pewter plate in mirror image. + @} + \override-lines #'(par-indent . 4) \paragraph @{ + The plate would be inked, the depressions caused by the cutting + and stamping would hold ink. An image was formed by pressing paper + to the plate. The stamping and cutting was completely done by + hand. + @} +@} +@end example + +@node Contexts for programmers +@section Contexts for programmers + +@menu +* Context evaluation:: +* Running a function on all layout objects:: +@end menu + +@node Context evaluation +@subsection Context evaluation + +@cindex calling code during interpreting +@funindex \applyContext + +Contexts can be modified during interpretation with Scheme code. The +syntax for this is +@example +\applyContext @var{function} +@end example + +@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: + +@example +\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 +@subsection Running a function on all layout objects + + +@cindex calling code on layout objects +@funindex \applyOutput + + +The most versatile way of tuning an object is @code{\applyOutput}. Its +syntax is +@example +\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 @var{context}, with the following +arguments: +@itemize +@item the layout object itself, +@item the context where the layout object was created, and +@item the context where @code{\applyOutput} is processed. +@end itemize + + +In addition, the cause of the layout object, i.e., the music +expression or object that was responsible for creating it, is in the +object property @code{cause}. For example, for a note head, this is a +@rinternals{NoteHead} event, and for a @rinternals{Stem} object, +this is a @rinternals{NoteHead} object. + +Here is a function to use for @code{\applyOutput}; it blanks +note-heads on the center-line: + +@lilypond[quote,verbatim,ragged-right] +#(define (blanker grob grob-origin context) + (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) + (eq? (ly:grob-property grob 'staff-position) 0)) + (set! (ly:grob-property grob 'transparent) #t))) + +\relative { + e4 g8 \applyOutput #'Voice #blanker b d2 +} +@end lilypond + + +@node Scheme procedures as properties +@section Scheme procedures as properties + +Properties (like @code{thickness}, @code{direction}, etc.) can be +set at fixed values with @code{\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. + + +@node Using Scheme code instead of \tweak +@section Using Scheme code instead of @code{\tweak} + +The main disadvantage of @code{\tweak} is its syntactical +inflexibility. For example, the following produces a syntax error. + +@example +F = \tweak #'font-size #-3 -\flageolet + +\relative c'' @{ + c4^\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. + +@example +F = #(let ((m (make-music 'ArticulationEvent + 'articulation-type "flageolet"))) + (set! (ly:music-property m 'tweaks) + (acons 'font-size -3 + (ly:music-property m 'tweaks))) + m) + +\relative c'' @{ + c4^\F c4_\F +@} +@end example + +@noindent +Here, the @code{tweaks} properties of the flageolet object +@code{m} (created with @code{make-music}) are extracted with +@code{ly:music-property}, a new key-value pair to change the +font size is prepended to the property list with the +@code{acons} Scheme function, and the result is finally +written back with @code{set!}. The last element of the +@code{let} block is the return value, @code{m} itself. + + + +@node Difficult tweaks +@section Difficult tweaks + +There are a few classes of difficult adjustments. + +@itemize + + +@item +One type of difficult adjustment involves the appearance of +spanner objects, such as slurs and ties. Usually, only one +spanner object is created at a time, and it can be adjusted with +the normal mechanism. However, occasionally a spanner crosses a +line break. When this happens, the object is cloned. A separate +object is created for every system in which the spanner appears. +The new objects are clones of the original object and inherit all +properties, including @code{\override}s. + + +In other words, an @code{\override} always affects all pieces of a +broken spanner. To change only one part of a spanner at a line break, +it is necessary to hook into the formatting process. The +@code{after-line-breaking} callback contains the Scheme procedure that +is called after the line breaks have been determined and layout +objects have been split over different systems. + +In the following example, we define a procedure +@code{my-callback}. This procedure + +@itemize +@item +determines if the spanner has been split across line breaks +@item +if yes, retrieves all the split objects +@item +checks if this grob is the last of the split objects +@item +if yes, it sets @code{extra-offset}. +@end itemize + +This procedure is installed into @rinternals{Tie}, so the last part +of the broken tie is repositioned. + +@lilypond[quote,verbatim,ragged-right] +#(define (my-callback grob) + (let* ( + ; have we been split? + (orig (ly:grob-original grob)) + + ; if yes, get the split pieces (our siblings) + (siblings (if (ly:grob? orig) + (ly:spanner-broken-into orig) '() ))) + + (if (and (>= (length siblings) 2) + (eq? (car (last-pair siblings)) grob)) + (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) + +\relative c'' { + \override Tie #'after-line-breaking = + #my-callback + c1 ~ \break c2 ~ c +} +@end lilypond + +@noindent +When applying this trick, the new @code{after-line-breaking} callback +should also call the old one @code{after-line-breaking}, if there is +one. For example, if using this with @code{Hairpin}, +@code{ly:hairpin::after-line-breaking} should also be called. + + +@item Some objects cannot be changed with @code{\override} for +technical reasons. Examples of those are @code{NonMusicalPaperColumn} +and @code{PaperColumn}. They can be changed with the +@code{\overrideProperty} function, which works similar to @code{\once +\override}, but uses a different syntax. + +@example +\overrideProperty +#"Score.NonMusicalPaperColumn" % Grob name +#'line-break-system-details % Property name +#'((next-padding . 20)) % Value +@end example + +Note, however, that @code{\override}, applied to +@code{NonMusicalPaperColumn} and @code{PaperColumn}, still works as +expected within @code{\context} blocks. + +@end itemize + + + + + diff --git a/Documentation/notation.tely b/Documentation/notation.tely index 76bcaa95b9..39933622fc 100644 --- a/Documentation/notation.tely +++ b/Documentation/notation.tely @@ -90,7 +90,6 @@ Distributions will want to install lilypond.info in postinstall, doing: LilyPond input and output. * Spacing issues:: Display of output on paper. * Changing defaults:: Tuning output. -* Interfaces for programmers:: How to interface with scheme. Appendices @@ -115,7 +114,6 @@ Appendices @include notation/spacing.itely @include notation/changing-defaults.itely -@include notation/programming-interface.itely @include notation/notation-appendices.itely diff --git a/Documentation/notation/changing-defaults.itely b/Documentation/notation/changing-defaults.itely index 5ea8a2ebb5..ef8e5f737c 100644 --- a/Documentation/notation/changing-defaults.itely +++ b/Documentation/notation/changing-defaults.itely @@ -391,7 +391,7 @@ any context of type @var{type}, regardless of its given name. This variant is used with music expressions that can be interpreted at several levels. For example, the @code{\applyOutput} command (see -@ref{Running a function on all layout objects}). Without an explicit +@rextend{Running a function on all layout objects}). Without an explicit @code{\context}, it is usually applied to @code{Voice} @example @@ -1729,7 +1729,7 @@ f' The music stream which is generated from a section of an input file, including any automatically inserted elements, may be examined, -see @ref{Displaying music expressions}. This may be helpful in +see @rextend{Displaying music expressions}. This may be helpful in determining what may be modified by a @code{\tweak} command. @@ -1737,8 +1737,8 @@ determining what may be modified by a @code{\tweak} command. Learning Manual: @rlearning{Tweaking methods}. -Notation Reference: -@ref{Displaying music expressions}. +Extending: +@rextend{Displaying music expressions}. @knownissues @@ -2914,7 +2914,6 @@ Learning Manual: Notation Reference: @ref{Explaining the Internals Reference}, @ref{Modifying properties}, -@ref{Interfaces for programmers}. Installed Files: @file{scm/@/define@/-grobs@/.scm}. @@ -2922,6 +2921,9 @@ Installed Files: Snippets: @rlsr{Tweaks and overrides}. +Extending: +@rextend{Interfaces for programmers}. + Internals Reference: @rinternals{All layout objects}. diff --git a/Documentation/notation/expressive.itely b/Documentation/notation/expressive.itely index 942dbd7bdf..223bab244f 100644 --- a/Documentation/notation/expressive.itely +++ b/Documentation/notation/expressive.itely @@ -461,7 +461,7 @@ mfEspressDynamic = #(make-dynamic-script mfEspress) @end lilypond The Scheme form of markup mode may be used instead. Its syntax is -explained in @ref{Markup construction in Scheme}. +explained in @rextend{Markup construction in Scheme}. @lilypond[verbatim,quote] moltoF = #(make-dynamic-script @@ -481,13 +481,16 @@ Font settings in markup mode are described in Notation Reference: @ref{Formatting text}, @ref{Selecting font and font size}, -@ref{Markup construction in Scheme}, @ref{What goes into the MIDI output?}, @ref{Controlling MIDI dynamics}. Snippets: @rlsr{Expressive marks}. +Extend: +@rextend{Markup construction in Scheme}, + + @node Curves @subsection Curves diff --git a/Documentation/notation/programming-interface.itely b/Documentation/notation/programming-interface.itely deleted file mode 100644 index dc11ee1a6e..0000000000 --- a/Documentation/notation/programming-interface.itely +++ /dev/null @@ -1,1506 +0,0 @@ -@c -*- coding: utf-8; mode: texinfo; -*- - -@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 - -@c \version "2.12.0" - -@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 -@rlearning{Scheme tutorial}. - -@menu -* Music functions:: -* Programmer interfaces:: -* Building complicated functions:: -* Markup programmer interface:: -* Contexts for programmers:: -* Scheme procedures as properties:: -* Using Scheme code instead of \tweak:: -* Difficult tweaks:: -@end menu - - -@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:: -@end menu - -@node Overview of music functions -@subsection Overview of music functions - -Making a function that 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{vari}... ) - (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) - #@{ - @emph{...music...} - #@}) -@end example - -@noindent -where - -@multitable @columnfractions .33 .66 -@item @var{vari} @tab @var{i}th variable -@item @var{vari-type?} @tab type of @var{i}th variable -@item @var{...music...} @tab normal LilyPond input, using - variables as @code{#$var1}, etc. -@end multitable - -The 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{vari-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} arguments are mandatory, -and are used in some advanced situations. The @code{parser} -argument is used to gain 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] -tempoPadded = #(define-music-function (parser location padding tempotext) - (number? string?) -#{ - \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } -#}) - -\relative c'' { - \tempo \markup { "Low tempo" } - c4 d e f g1 - \tempoPadded #4.0 #"High tempo" - g4 f e d c1 -} -@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 that 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 a variable, - -@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 @command{lilypond} with - -@example -lilypond -d display-bar-numbers FILENAME.ly -@end example - - -@node Programmer interfaces -@section Programmer interfaces - -This section contains information about mixing LilyPond -and Scheme. - -@menu -* Input variables and Scheme:: -* Internal music representation:: -@end menu - - -@node Input variables and Scheme -@subsection Input variables and Scheme - -The input format supports the notion of variables: in the following -example, a music expression is assigned to a variable with the name -@code{traLaLa}. - -@example -traLaLa = @{ c'4 d'4 @} -@end example - -@noindent - -There is also a form of scoping: in the following example, the -@code{\layout} block also contains a @code{traLaLa} variable, which is -independent of the outer @code{\traLaLa}. -@example -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{\layout} blocks are scopes nested inside that -toplevel scope. - -Both variables and scoping are implemented in the GUILE module system. -An anonymous Scheme module is attached to each scope. An assignment of -the form -@example -traLaLa = @{ c'4 d'4 @} -@end example - -@noindent -is internally converted to a Scheme definition -@example -(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} block by means of a second variable -@code{twice}: - -@lilypond[verbatim] -traLaLa = { c'4 d'4 } - -%% 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 - -@c Due to parser lookahead - -In this example, the assignment happens after the 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 - -@example -... -@{ #(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 - - -@knownissues - -Mixing Scheme and LilyPond variables is not possible with the -@code{--safe} option. - - -@node 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. - -A music object has three kinds of types: -@itemize -@item -music name: Each music expression has a name. For example, a note -leads to a @rinternals{NoteEvent}, and @code{\simultaneous} leads to -a @rinternals{SimultaneousMusic}. A list of all expressions -available is in the Internals Reference manual, under -@rinternals{Music expressions}. - -@item -@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 -Internals Reference, under -@rinternals{Music classes}. - -@item -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. -For example, a @rinternals{NoteEvent} has @code{pitch} and -@code{duration} properties that store the pitch and duration of that -note. A list of all properties available can be found in the -Internals Reference, under @rinternals{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 @q{child} -music object in the @code{element} property. For example, -@rinternals{SequentialMusic} has its children in @code{elements}, -and @rinternals{GraceMusic} has its single argument in -@code{element}. The body of a repeat is stored in the @code{element} -property of @rinternals{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 Displaying music expressions -@subsection Displaying music expressions - -@cindex internal storage -@cindex displaying music expressions -@cindex internal representation, displaying -@cindex displayMusic -@funindex \displayMusic - -When writing a music function it is often instructive to inspect how -a music expression is stored internally. This can be done with the -music function @code{\displayMusic} - -@example -@{ - \displayMusic @{ c'4\f @} -@} -@end example - -@noindent -will display - -@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 0 0)) - (make-music - 'AbsoluteDynamicEvent - 'text - "f"))))) -@end example - -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 -lilypond file.ly >display.txt -@end example - -With a bit of reformatting, the above information is -easier to read, - -@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 0 0)) - (make-music 'AbsoluteDynamicEvent - 'text "f"))))) -@end example - -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 -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 @code{display-scheme-music} function is the function used by -@code{\displayMusic} to display the Scheme representation of a music -expression. - -@example -#(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 - -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 - -The note pitch can be changed by setting this @code{'pitch} property, - -@funindex \displayLilyMusic - -@example -#(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 - - -@node Doubling a note with slurs (example) -@subsection Doubling a note with slurs (example) - -Suppose we want to create a function that translates input like -@code{a} into @code{a( a)}. We begin by examining the internal -representation of the desired result. - -@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 -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 that does this. - -A @code{$variable} inside the @code{#@{...#@}} notation is like -a regular @code{\variable} in classical LilyPond notation. We -know that - -@example -@{ \music -. -> @} -@end example - -@noindent -will not work in LilyPond. We could avoid this problem by attaching -the articulation to a fake note, - -@example -@{ << \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 - -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. - -To build this function, we begin with - -@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 - -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!) - -@example -"Add a marcato..." -@end example - -@noindent -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 @code{'elements} -list property. - -@example -(set! place new-value) -@end example - -Here, what we want to set (the @q{place}) is the @code{'elements} -property of @code{result-event-chord} expression. - -@example -(ly:music-property result-event-chord 'elements) -@end example - -@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 @code{'elements} property, with an extra item: the -@code{ArticulationEvent} expression, which we copy from the -@code{\displayMusic} output, - -@example -(cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements)) -@end example - -@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 @code{'elements} property is not important here. - -Finally, once we have added the marcato articulation to its @code{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 -@section Markup programmer interface - -Markups are implemented as special Scheme functions which produce a -@code{Stencil} object given a number of arguments. - -@menu -* Markup construction in Scheme:: -* How markups work internally:: -* New markup command definition:: -* New markup list command definition:: -@end menu - - -@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, -@example -(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") - #:larger #:line ("foo" "bar" "baz"))) -@end example - -@noindent -is equivalent to: -@example -\markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} - \larger \line @{ foo bar baz @} @} -@end example - -@noindent -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{\markup-command} @tab @code{#:markup-command} -@item @code{\variable} @tab @code{variable} -@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} -@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}). - - -@knownissues - -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 (function-that-returns-markups)) -@end lisp - -@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 (function-that-returns-markups))) -@end lisp - - -@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{define-markup-command} Scheme macro. - -@lisp -(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 are - -@table @var -@item argi -@var{i}th command argument -@item argi-type? -a type predicate for the i@var{th} argument -@item layout -the @q{layout} definition -@item props -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 a small caps font. Normally we could select the -small caps font, - -@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 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 -(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., - -@example -(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 -above example: - -@example -(cons (list '(font-shape . caps) ) props) -@end example - -@noindent -The variable @code{props} is a list of alists, and we prepend to it by -cons'ing a list with the extra setting. - - -Suppose that we are typesetting a recitative in an opera and -we would like to define a command that will show character names in a -custom manner. Names should be printed with small caps and moved a -bit up and to the left. We will define a @code{\character} command -which takes into account the necessary translation and uses the newly -defined @code{\smallcaps} command: - -@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 -that this mechanism does not annihilate the vertical effect of our -@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: - -@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 -does not have a small-caps variant. In that case we have to fake -the small caps font by setting a string in uppercase with the -first letter a little larger: - -@example -#(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 -tokens separated by spaces (@code{(string-split str #\Space)}); for -each token, a markup is built with the first letter made large and -upcased (@code{#:large (string-upcase (substring s 0 1))}), and a -second markup built with the following letters made tiny and upcased -(@code{#:tiny (string-upcase (substring s 1))}). As LilyPond -introduces a space between markups on a line, the second markup is -translated to the left (@code{#:translate (cons -0.6 0) ...}). Then, -the markups built for each token are put in a line by -@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{Text markup commands}, for details. - -@knownissues - -Currently, the available combinations of arguments (after the standard -@var{layout} and @var{props} arguments) to a markup command defined with -@code{define-markup-command} are limited as follows. - -@table @asis -@item (no argument) -@itemx @var{list} -@itemx @var{markup} -@itemx @var{markup markup} -@itemx @var{scm} -@itemx @var{scm markup} -@itemx @var{scm scm} -@itemx @var{scm scm markup} -@itemx @var{scm scm markup markup} -@itemx @var{scm markup markup} -@itemx @var{scm scm scm} -@end table - -@noindent -In the above table, @var{scm} represents native Scheme data types like -@q{number} or @q{string}. - -As an example, it is not possible to use a markup command @code{foo} with -four arguments defined as - -@example -#(define-markup-command (foo layout props - num1 str1 num2 str2) - (number? string? number? string?) - ...) -@end example - -@noindent -If you apply it as, say, - -@example -\markup \foo #1 #"bar" #2 #"baz" -@end example - -@cindex Scheme signature -@cindex signature, Scheme -@noindent -@command{lilypond} complains that it cannot parse @code{foo} due to its -unknown Scheme signature. - - -@node New markup list command definition -@subsection New markup list command definition -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 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. -@example -#(define-markup-list-command (paragraph layout props args) (markup-list?) - (let ((indent (chain-assoc-get 'par-indent props 2))) - (interpret-markup-list layout props - (make-justified-lines-markup-list (cons (make-hspace-markup indent) - args))))) -@end example - -Besides the usual @code{layout} and @code{props} arguments, the -@code{paragraph} markup list command takes a markup list argument, named -@code{args}. The predicate for markup lists is @code{markup-list?}. - -First, the function gets the indent width, a property here named -@code{par-indent}, from the property list @code{props}. If the -property is not found, the default value is @code{2}. Then, a -list of justified lines is made using the -@code{make-justified-lines-markup-list} function, which is related -to the @code{\justified-lines} built-in markup list command. A -horizontal space is added at the beginning using the -@code{make-hspace-markup} function. Finally, the markup list is -interpreted using the @code{interpret-markup-list} function. - -This new markup list command can be used as follows: -@example -\markuplines @{ - \paragraph @{ - The art of music typography is called \italic @{(plate) engraving.@} - The term derives from the traditional process of music printing. - Just a few decades ago, sheet music was made by cutting and stamping - the music into a zinc or pewter plate in mirror image. - @} - \override-lines #'(par-indent . 4) \paragraph @{ - The plate would be inked, the depressions caused by the cutting - and stamping would hold ink. An image was formed by pressing paper - to the plate. The stamping and cutting was completely done by - hand. - @} -@} -@end example - -@node Contexts for programmers -@section Contexts for programmers - -@menu -* Context evaluation:: -* Running a function on all layout objects:: -@end menu - -@node Context evaluation -@subsection Context evaluation - -@cindex calling code during interpreting -@funindex \applyContext - -Contexts can be modified during interpretation with Scheme code. The -syntax for this is -@example -\applyContext @var{function} -@end example - -@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: - -@example -\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 -@subsection Running a function on all layout objects - - -@cindex calling code on layout objects -@funindex \applyOutput - - -The most versatile way of tuning an object is @code{\applyOutput}. Its -syntax is -@example -\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 @var{context}, with the following -arguments: -@itemize -@item the layout object itself, -@item the context where the layout object was created, and -@item the context where @code{\applyOutput} is processed. -@end itemize - - -In addition, the cause of the layout object, i.e., the music -expression or object that was responsible for creating it, is in the -object property @code{cause}. For example, for a note head, this is a -@rinternals{NoteHead} event, and for a @rinternals{Stem} object, -this is a @rinternals{NoteHead} object. - -Here is a function to use for @code{\applyOutput}; it blanks -note-heads on the center-line: - -@lilypond[quote,verbatim,ragged-right] -#(define (blanker grob grob-origin context) - (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) - (eq? (ly:grob-property grob 'staff-position) 0)) - (set! (ly:grob-property grob 'transparent) #t))) - -\relative { - e4 g8 \applyOutput #'Voice #blanker b d2 -} -@end lilypond - - -@node Scheme procedures as properties -@section Scheme procedures as properties - -Properties (like @code{thickness}, @code{direction}, etc.) can be -set at fixed values with @code{\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. - - -@node Using Scheme code instead of \tweak -@section Using Scheme code instead of @code{\tweak} - -The main disadvantage of @code{\tweak} is its syntactical -inflexibility. For example, the following produces a syntax error. - -@example -F = \tweak #'font-size #-3 -\flageolet - -\relative c'' @{ - c4^\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. - -@example -F = #(let ((m (make-music 'ArticulationEvent - 'articulation-type "flageolet"))) - (set! (ly:music-property m 'tweaks) - (acons 'font-size -3 - (ly:music-property m 'tweaks))) - m) - -\relative c'' @{ - c4^\F c4_\F -@} -@end example - -@noindent -Here, the @code{tweaks} properties of the flageolet object -@code{m} (created with @code{make-music}) are extracted with -@code{ly:music-property}, a new key-value pair to change the -font size is prepended to the property list with the -@code{acons} Scheme function, and the result is finally -written back with @code{set!}. The last element of the -@code{let} block is the return value, @code{m} itself. - - - -@node Difficult tweaks -@section Difficult tweaks - -There are a few classes of difficult adjustments. - -@itemize - - -@item -One type of difficult adjustment involves the appearance of -spanner objects, such as slurs and ties. Usually, only one -spanner object is created at a time, and it can be adjusted with -the normal mechanism. However, occasionally a spanner crosses a -line break. When this happens, the object is cloned. A separate -object is created for every system in which the spanner appears. -The new objects are clones of the original object and inherit all -properties, including @code{\override}s. - - -In other words, an @code{\override} always affects all pieces of a -broken spanner. To change only one part of a spanner at a line break, -it is necessary to hook into the formatting process. The -@code{after-line-breaking} callback contains the Scheme procedure that -is called after the line breaks have been determined and layout -objects have been split over different systems. - -In the following example, we define a procedure -@code{my-callback}. This procedure - -@itemize -@item -determines if the spanner has been split across line breaks -@item -if yes, retrieves all the split objects -@item -checks if this grob is the last of the split objects -@item -if yes, it sets @code{extra-offset}. -@end itemize - -This procedure is installed into @rinternals{Tie}, so the last part -of the broken tie is repositioned. - -@lilypond[quote,verbatim,ragged-right] -#(define (my-callback grob) - (let* ( - ; have we been split? - (orig (ly:grob-original grob)) - - ; if yes, get the split pieces (our siblings) - (siblings (if (ly:grob? orig) - (ly:spanner-broken-into orig) '() ))) - - (if (and (>= (length siblings) 2) - (eq? (car (last-pair siblings)) grob)) - (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) - -\relative c'' { - \override Tie #'after-line-breaking = - #my-callback - c1 ~ \break c2 ~ c -} -@end lilypond - -@noindent -When applying this trick, the new @code{after-line-breaking} callback -should also call the old one @code{after-line-breaking}, if there is -one. For example, if using this with @code{Hairpin}, -@code{ly:hairpin::after-line-breaking} should also be called. - - -@item Some objects cannot be changed with @code{\override} for -technical reasons. Examples of those are @code{NonMusicalPaperColumn} -and @code{PaperColumn}. They can be changed with the -@code{\overrideProperty} function, which works similar to @code{\once -\override}, but uses a different syntax. - -@example -\overrideProperty -#"Score.NonMusicalPaperColumn" % Grob name -#'line-break-system-details % Property name -#'((next-padding . 20)) % Value -@end example - -Note, however, that @code{\override}, applied to -@code{NonMusicalPaperColumn} and @code{PaperColumn}, still works as -expected within @code{\context} blocks. - -@end itemize - - - - - diff --git a/Documentation/notation/text.itely b/Documentation/notation/text.itely index cab401bb16..81e6ed5d16 100644 --- a/Documentation/notation/text.itely +++ b/Documentation/notation/text.itely @@ -1296,11 +1296,13 @@ An exhaustive list of markup list commands can be found in @seealso Notation Reference: @ref{Text markup list commands}, -@ref{New markup list command definition}. Snippets: @rlsr{Text}. +Extending: +@rextend{New markup list command definition}. + Internals Reference: @rinternals{TextScript}.