X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fextending%2Fprogramming-interface.itely;h=7b1637e564ba4ceeb4c78f63ecff15d5aabf73f7;hb=d7c0f4263534307616c82d9b2ce6fdef9472456f;hp=1bf87c7fd5559a23bec398d38b8f7ada80fbaeeb;hpb=3dd9b13331489a191d0e901245cc98476e5fcac1;p=lilypond.git diff --git a/Documentation/extending/programming-interface.itely b/Documentation/extending/programming-interface.itely index 1bf87c7fd5..7b1637e564 100644 --- a/Documentation/extending/programming-interface.itely +++ b/Documentation/extending/programming-interface.itely @@ -30,133 +30,85 @@ not familiar with Scheme, you may wish to read our @node Music functions @section Music functions -Music functions are scheme functions that are used to -automatically create music expressions. They can be used to -greatly simplify the input file. +@emph{Music functions} are scheme procedures that can create music +expressions automatically, and can be used to greatly simplify the +input file. @menu * Music function syntax:: * Simple substitution functions:: * Intermediate substitution functions:: * Mathematics in functions:: -* Void functions:: * Functions without arguments:: +* Void functions:: @end menu + @node Music function syntax @subsection Music function syntax -The general syntax of a music function is: +The general form for music functions is: @example -myFunction = -#(define-music-function (parser location @var{var_1} @var{var_2}...@var{var_n}) - (@var{var_1-type?} @var{var_2-type?}...@var{var_n-type?}) - @var{...valid music expression...}) +function = +#(define-music-function + (parser location @var{arg1} @var{arg2} @dots{}) + (@var{type1?} @var{type2?} @dots{}) + @var{music}) @end example @noindent where @multitable @columnfractions .33 .66 -@item @var{var_i} @tab @var{i}th variable -@item @var{var_i-type?} @tab type of @var{i}th variable -@item @var{...valid music expression...} @tab expression that returns -valid music, generally in the form of a Scheme expression. There is -also special syntax that allows LilyPond input code in this music -expression. -@end multitable +@item @code{@var{argN}} +@tab @var{n}th argument -The variable type checkers are scheme procedures that will return -@code{#t} if a variable is of a given type. Some common types -are shown in the table below. Other types can be found in the files -@file{lily/music-scheme.cc} and @file{scm/c++.scm}. +@item @code{@var{typeN?}} +@tab a scheme @emph{type predicate} for which @code{@var{argN}} +must return @code{#t}. + +@item @code{@var{music}} +@tab A music expression, optionally written in scheme, with any +LilyPond code enclosed in hashed braces +(@tie{}@w{@code{#@{@dots{}#@}}}@tie{}). Within LilyPond code +blocks, use @code{$} to reference function arguments (eg., +@samp{$arg1}) or to start an inline scheme expression containing +function arguments (eg., @w{@samp{$(cons arg1 arg2)}}). -@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. -The @code{parser} argument is used in the body of the function -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. +@noindent +For a list of available type predicates, see +@ruser{Predefined type predicates}. User-defined type predicates +are also allowed. -@node Simple substitution functions -@subsection Simple substitution functions -A simple substitution function is a music function whose output music -expression is written in LilyPond code, but with an input variable -substituted into the LilyPond code. The general form of these functions is +@seealso -@example -myFunction = -#(define-music-function (parser location @var{var1}) - (@var{var1-type?}) - #@{ - @emph{... LilyPond input code with} @code{#$var1} @emph{for substition ...} - #@}) -@end example +Notation Reference: +@ruser{Predefined type predicates}. -Note that the special characters @code{#@{} and @code{#@}} surround the -LilyPond music. +Installed Files: +@file{lily/music-scheme.cc}, +@file{scm/c++.scm}, +@file{scm/lily.scm}. -@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 - -For example, a function can be defined that simplifies -setting the padding of a TextScript: -@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 +@node Simple substitution functions +@subsection Simple substitution functions -In addition to numbers, we can use music expressions such -as notes for arguments to music functions: +Simple substitution functions are music functions whose output +music expression is written in LilyPond format and contains +function arguments in the output expression. They are described +in @ruser{Substitution function examples}. -@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 - #}) -@end lilypond @node Intermediate substitution functions @subsection Intermediate substitution functions -Slightly more complicated than simple substitution function, -intermediate substitution functions involve a mix of Scheme code and -LilyPond code in the music expression to be -returned. +Intermediate substitution functions involve a mix of Scheme code +and LilyPond code in the music expression to be returned. Some @code{\override} commands require an argument consisting of a pair of numbers (called a @code{cons cell} in Scheme). @@ -164,20 +116,19 @@ a pair of numbers (called a @code{cons cell} in Scheme). The pair can be directly passed into the music function, using a @code{pair?} variable: -@quotation @example manualBeam = -#(define-music-function (parser location beg-end) - (pair?) -#@{ - \once \override Beam #'positions = #$beg-end -#@}) - -\relative @{ +#(define-music-function + (parser location beg-end) + (pair?) + #@{ + \once \override Beam #'positions = $beg-end + #@}) + +\relative c' @{ \manualBeam #'(3 . 6) c8 d e f @} @end example -@end quotation Alternatively, the numbers making up the pair can be passed as separate arguments, and the Scheme code @@ -186,13 +137,14 @@ music expression: @lilypond[quote,verbatim,ragged-right] manualBeam = -#(define-music-function (parser location beg end) - (number? number?) -#{ - \once \override Beam #'positions = #(cons $beg $end) -#}) - -\relative { +#(define-music-function + (parser location beg end) + (number? number?) + #{ + \once \override Beam #'positions = $(cons beg end) + #}) + +\relative c' { \manualBeam #3 #6 c8 d e f } @end lilypond @@ -205,61 +157,50 @@ 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) +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))) #}) + $(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 } +\relative c' { + c2 \AltOn #0.5 c4 c + \AltOn #1.5 c c \AltOff c2 +} @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) +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))) + $(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) $music \revert Stem #'length - \revert NoteHead #'font-size #}) + \revert NoteHead #'font-size + #}) -{ c'2 \withAlt #0.5 {c'4 c'} - \withAlt #1.5 {c' c'} c'2 } +\relative c' { + c2 \withAlt #0.5 { c4 c } + \withAlt #1.5 { c c } c2 +} @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 @@ -276,7 +217,9 @@ without arguments, @example displayBarNum = -#(define-music-function (parser location) () +#(define-music-function + (parser location) + () (if (eq? #t (ly:get-option 'display-bar-numbers)) #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} #@{#@})) @@ -290,6 +233,32 @@ lilypond -d display-bar-numbers FILENAME.ly @end example +@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 +@w{@code{(make-music @dots{})}}. 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 Markup functions @section Markup functions @@ -449,59 +418,26 @@ If the command uses properties from the @var{props} arguments, the @code{#:properties} keyword can be used, to specify which properties are used, and their default values. -@knownissues -There are restrictions on the possible arguments to a markup command. - -Arguments are distingued according to their type: +Arguments are distinguished according to their type: @itemize @item a markup, corresponding to type predicate @code{markup?}; -@item a list of markup, corresponding to type predicate +@item a list of markups, corresponding to type predicate @code{markup-list?}; @item any other scheme object, corresponding to type predicates such as @code{list?}, @code{number?}, @code{boolean?}, etc. @end itemize -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{markup-list} -@itemx @var{markup} -@itemx @var{markup markup} -@itemx @var{scheme} -@itemx @var{scheme markup} -@itemx @var{scheme scheme} -@itemx @var{scheme scheme markup} -@itemx @var{scheme scheme markup markup} -@itemx @var{scheme markup markup} -@itemx @var{scheme scheme scheme} -@end table - -@noindent -This means that it is not possible to define with e.g. three scheme -arguments and a markup arguments, like: - -@example -#(define-markup-command (foo layout props - num1 num2 a-list a-markup) - (number? number? list? markup?) - ...) -@end example - -@noindent -If you apply it as, say, - -@example -\markup \foo #1 #2 #'(bar baz) Blah -@end example +There is no limitation on the order of arguments (after the standard +@var{layout} and @var{props} arguments). However, markup functions +taking a markup as their last argument are somewhat special as you can +apply them to a markup list, and the result is a markup list where the +markup function (with the specified leading arguments) has been applied +to every element of the original markup list. -@cindex Scheme signature -@cindex signature, Scheme -@noindent -@command{lilypond} complains that it cannot parse @code{foo} due to its -unknown Scheme signature. +Since replicating the leading arguments for applying a markup function +to a markup list is cheap mostly for Scheme arguments, you avoid +performance pitfalls by just using Scheme arguments for the leading +arguments of markup functions that take a markup as their last argument. @node On properties @unnumberedsubsubsec On properties @@ -599,7 +535,7 @@ and the text. So we will introduce a new property, @code{box-padding} will be used for the inner padding. The new code is now as follows: -@lisp +@lisp #(define-markup-command (double-box layout props text) (markup?) #:properties ((inter-box-padding 0.4) (box-padding 0.6)) @@ -683,7 +619,7 @@ Then, a property for setting the gap between two lines is added, called @lisp (define-markup-command (draw-double-line layout props dest) (number-pair?) - #:properties ((thickness 1) + #:properties ((thickness 1) (line-gap 0.6)) "..documentation.." ... @@ -695,8 +631,8 @@ stencils are combined using @code{ly:stencil-add}: @lilypond[quote,verbatim,ragged-right] #(define-markup-command (my-draw-line layout props dest) - (number-pair?) - #:properties ((thickness 1) + (number-pair?) + #:properties ((thickness 1) (line-gap 0.6)) "..documentation.." (let* ((th (* (ly:output-def-lookup layout 'line-thickness) @@ -846,7 +782,7 @@ note-heads on the center-line: (eq? (ly:grob-property grob 'staff-position) 0)) (set! (ly:grob-property grob 'transparent) #t))) -\relative { +\relative c' { e4 g8 \applyOutput #'Voice #blanker b d2 } @end lilypond @@ -922,6 +858,13 @@ The inner @code{ly:make-simple-closure} supplies the grob as argument to @var{proc}, the outer ensures that result of the function is returned, rather than the @code{simple-closure} object. +From within a callback, the easiest method for evaluating a markup is +to use grob-interpret-markup. For example: + +@example +my-callback = #(lambda (grob) + (grob-interpret-markup grob (markup "foo"))) +@end example @node Inline Scheme code @section Inline Scheme code @@ -1015,33 +958,36 @@ 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)) + (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 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))))) + (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 + 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. +should also call the old one, if such a default exists. For example, +if using this with @code{Hairpin}, @code{ly:spanner::kill-zero-spanned-time} +should also be called. -@item Some objects cannot be changed with @code{\override} for +@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