X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fextending%2Fscheme-tutorial.itely;h=eaffe70a4824d83ea6fff1954f351f5b0c441ca7;hb=d36171e34d236d890f5dc511b895037188c6c7cb;hp=7ad67f66fd65b778cff3d72cd306e6c1bc115214;hpb=579274a935b22567ac15b3651a9d651474f88ec4;p=lilypond.git diff --git a/Documentation/extending/scheme-tutorial.itely b/Documentation/extending/scheme-tutorial.itely index 7ad67f66fd..eaffe70a48 100644 --- a/Documentation/extending/scheme-tutorial.itely +++ b/Documentation/extending/scheme-tutorial.itely @@ -8,12 +8,11 @@ Guide, node Updating translation committishes.. @end ignore -@c \version "2.12.0" +@c \version "2.19.21" @node Scheme tutorial @chapter Scheme tutorial -@funindex # @cindex Scheme @cindex GUILE @cindex Scheme, in-line code @@ -28,9 +27,9 @@ Scheme. If you want to know more about Scheme, see @uref{http://@/www@/.schemers@/.org}. LilyPond uses the GNU Guile implementation of Scheme, which is -based on the Scheme @qq{R5RS} standard. If you are learning Scheme +based on the Scheme @qq{R5RS} standard. If you are learning Scheme to use with LilyPond, working with a different implementation (or -referring to a different standard) is not recommended. Information +referring to a different standard) is not recommended. Information on guile can be found at @uref{http://www.gnu.org/software/guile/}. The @qq{R5RS} Scheme standard is located at @uref{http://www.schemers.org/Documents/Standards/R5RS/}. @@ -67,19 +66,31 @@ The LilyPond installation includes the Guile implementation of Scheme. On most systems you can experiment in a Scheme sandbox by opening a terminal window and typing @q{guile}. On some systems, notably Windows, you may need to set the environment variable -@code{GUILE_LOAD_PATH} to the directory @code{../usr/shr/guile/1.8} -in the LilyPond installation. For the full path to this directory +@code{GUILE_LOAD_PATH} to the directory @code{../usr/share/guile/1.8} +in the LilyPond installation. For the full path to this directory see @rlearning{Other sources of information}. Alternatively, Windows users may simply choose @q{Run} from the Start menu and enter @q{guile}. -Once the guile sandbox is running, you will receive a guile prompt: +However, a hands-on Scheme sandbox with all of Lilypond loaded is +available with this command line: +@example +lilypond scheme-sandbox +@end example + +@noindent +Once the sandbox is running, you will receive a guile prompt: @lisp guile> @end lisp -You can enter Scheme expressions at this prompt to experiment with Scheme. +You can enter Scheme expressions at this prompt to experiment with +Scheme. If you want to be able to use the GNU readline library for +nicer editing of the Scheme command line, check the file +@file{ly/scheme-sandbox.ly} for more information. If you already have +enabled the readline library for your interactive Guile sessions outside +of LilyPond, this should work in the sandbox as well. @node Scheme variables @subsection Scheme variables @@ -148,7 +159,7 @@ and False is @code{#f}. @item Numbers Numbers are entered in the standard fashion, -@code{1} is the (integer) number one, while @code{-1.5} is a +@code{1} is the (integer) number one, while @w{@code{-1.5}} is a floating point number (a non-integer number). @item Strings @@ -198,7 +209,15 @@ For a complete listing see the Guile reference guide, There are also compound data types in Scheme. The types commonly used in LilyPond programming include pairs, lists, alists, and hash tables. -@subheading Pairs +@menu +* Pairs:: +* Lists:: +* Association lists (alists):: +* Hash tables:: +@end menu + +@node Pairs +@unnumberedsubsubsec Pairs The foundational compound data type of Scheme is the @code{pair}. As might be expected from its name, a pair is two values glued together. @@ -239,7 +258,7 @@ Scheme procedures @code{car} and @code{cdr}, respectively. @lisp guile> (define mypair (cons 123 "hello there") -... ) +@dots{} ) guile> (car mypair) 123 guile> (cdr mypair) @@ -253,11 +272,13 @@ Note: @code{cdr} is pronounced "could-er", according Sussman and Abelson, see @uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133} -@subheading Lists +@node Lists +@unnumberedsubsubsec Lists -A very common Scheme data structure is the @emph{list}. Formally, a -list is defined as either the empty list (represented as @code{'()}, -or a pair whose @code{cdr} is a list. +A very common Scheme data structure is the @emph{list}. Formally, +a @q{proper} list is defined to be either the empty list with its +input form @code{'()} and length@tie{}0, or a pair whose +@code{cdr} in turn is a shorter list. There are many ways of creating lists. Perhaps the most common is with the @code{list} procedure: @@ -283,7 +304,8 @@ Lists are a central part of Scheme. In, fact, Scheme is considered a dialect of lisp, where @q{lisp} is an abbreviation for @q{List Processing}. Scheme expressions are all lists. -@subheading Association lists (alists) +@node Association lists (alists) +@unnumberedsubsubsec Association lists (alists) A special type of list is an @emph{association list} or @emph{alist}. An alist is used to store data for easy retrieval. @@ -307,7 +329,8 @@ guile> Alists are widely used in LilyPond to store properties and other data. -@subheading Hash tables +@node Hash tables +@unnumberedsubsubsec Hash tables A data structure that is used occasionally in LilyPond. A hash table is similar to an array, but the indexes to the array can be any type @@ -477,7 +500,14 @@ Scheme procedures are executable scheme expressions that return a value resulting from their execution. They can also manipulate variables defined outside of the procedure. -@subheading Defining procedures +@menu +* Defining procedures:: +* Predicates:: +* Return values:: +@end menu + +@node Defining procedures +@unnumberedsubsubsec Defining procedures Procedures are defined in Scheme with define @@ -503,7 +533,8 @@ guile> (average 3 12) 15/2 @end lisp -@subheading Predicates +@node Predicates +@unnumberedsubsubsec Predicates Scheme procedures that return boolean values are often called @emph{predicates}. By convention (but not necessity), predicate names @@ -517,7 +548,13 @@ guile> (less-than-ten? 15) #f @end lisp -@subheading Return values +@node Return values +@unnumberedsubsubsec Return values + +Scheme procedures always return a return value, which is the value +of the last expression executed in the procedure. The return +value can be any valid Scheme value, including a complex data +structure or a procedure. Sometimes the user would like to have multiple Scheme expressions in a procedure. There are two ways that multiple expressions can be @@ -538,14 +575,20 @@ statement in the let block: @lisp guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4)) -... (+ (* x y) (/ z x))) +@dots{} (+ (* x y) (/ z x))) 508 @end lisp @node Scheme conditionals @subsection Scheme conditionals -@subheading if +@menu +* if:: +* cond:: +@end menu + +@node if +@unnumberedsubsubsec if Scheme has an @code{if} procedure: @@ -565,14 +608,15 @@ guile> (if (> a b) "a is greater than b" "a is not greater than b") "a is not greater than b" @end lisp -@subheading cond +@node cond +@unnumberedsubsubsec cond Another conditional procedure in scheme is @code{cond}: @example (cond (test-expression-1 result-expression-sequence-1) (test-expression-2 result-expression-sequence-2) - ... + @dots{} (test-expression-n result-expression-sequence-n)) @end example @@ -595,6 +639,7 @@ guile> (cond ((< a b) "a is less than b") * LilyPond Scheme syntax:: * LilyPond variables:: * Input variables and Scheme:: +* Importing Scheme in LilyPond:: * Object properties:: * LilyPond compound variables:: * Internal music representation:: @@ -602,21 +647,77 @@ guile> (cond ((< a b) "a is less than b") @node LilyPond Scheme syntax @subsection LilyPond Scheme syntax +@funindex $ +@funindex # -In a music file, snippets of Scheme code are introduced with the hash -mark @code{#}. So, the previous examples translated to LilyPond are +The Guile interpreter is part of LilyPond, which means that +Scheme can be included in LilyPond input files. There are several +methods for including Scheme in LilyPond. + +The simplest way is to use a hash mark@tie{}@code{#} before a Scheme +expression. + +Now LilyPond's input is structured into tokens and expressions, much +like human language is structured into words and sentences. LilyPond +has a lexer that recognizes tokens (literal numbers, strings, Scheme +elements, pitches and so on), and a parser that understands the syntax, +@rcontrib{LilyPond grammar}. Once it knows that a particular syntax rule +applies, it executes actions associated with it. + +The hash mark@tie{}@code{#} method of embedding Scheme is a natural fit +for this system. Once the lexer sees a hash mark, it calls the Scheme +reader to read one full Scheme expression (this can be an identifier, an +expression enclosed in parentheses, or several other things). After the +Scheme expression is read, it is stored away as the value for an +@code{SCM_TOKEN} in the grammar. Once the parser knows how to make use +of this token, it calls Guile for evaluating the Scheme expression. +Since the parser usually requires a bit of lookahead from the lexer to +make its parsing decisions, this separation of reading and evaluation +between lexer and parser is exactly what is needed to keep the execution +of LilyPond and Scheme expressions in sync. For this reason, you should +use the hash mark@tie{}@code{#} for calling Scheme whenever this is +feasible. + +Another way to call the Scheme interpreter from LilyPond is the use of +dollar@tie{}@code{$} instead of a hash mark for introducing Scheme +expressions. In this case, Lilypond evaluates the code right after the +lexer has read it. It checks the resulting type of the Scheme +expression and then picks a token type (one of several +@code{xxx_IDENTIFIER} in the syntax) for it. It creates a @emph{copy} +of the value and uses that for the value of the token. If the value of +the expression is void (Guile's value of @code{*unspecified*}), nothing +at all is passed to the parser. + +This is, in fact, exactly the same mechanism that Lilypond employs when +you call any variable or music function by name, as @code{\name}, with +the only difference that the name is determined by the Lilypond lexer +without consulting the Scheme reader, and thus only variable names +consistent with the current Lilypond mode are accepted. + +The immediate action of @code{$} can lead to surprises, @ref{Input +variables and Scheme}. Using @code{#} where the parser supports it +is usually preferable. Inside of music expressions, expressions +created using @code{#} @emph{are} interpreted as music. However, +they are @emph{not} copied before use. If they are part of some +structure that might still get used, you may need to use +@code{ly:music-deep-copy} explicitly. + +@funindex $@@ +@funindex #@@ +There are also @q{list splicing} operators @code{$@@} and @code{#@@} +that insert all elements of a list in the surrounding context. + +Now let's take a look at some actual Scheme code. Scheme procedures can +be defined in LilyPond input files: @example -##t ##f -#1 #-1.5 -#"this is a string" -#"this -is -a string" +#(define (average a b c) (/ (+ a b c) 3)) @end example Note that LilyPond comments (@code{%} and @code{%@{ %@}}) cannot -be used within Scheme code. Comments in Guile Scheme are entered +be used within Scheme code, even in a LilyPond input file, because +the Guile interpreter, not the LilyPond lexer, is reading +the Scheme expression. Comments in Guile Scheme are entered as follows: @example @@ -629,9 +730,13 @@ as follows: !# @end example -Multiple consecutive scheme expressions in a music file can be -combined using the @code{begin} operator. This permits the number -of hash marks to be reduced to one. +For the rest of this section, we will assume that the data is entered +in a music file, so we add@tie{}@code{#}s at the beginning of each Scheme +expression. + +All of the top-level Scheme expressions in a LilyPond input file can +be combined into a single Scheme expression by the use of the +@code{begin} statement: @example #(begin @@ -639,38 +744,43 @@ of hash marks to be reduced to one. (define bar 1)) @end example -@c todo -- # introduces a scheme *expression* -@c need the concept of an expression - -If @code{#} is followed by an opening parenthesis, @code{(}, as in -the example above, the parser will remain in Scheme mode until -a matching closing parenthesis, @code{)}, is found, so further -@code{#} symbols to introduce a Scheme section are not required. - -For the rest of this section, we will assume that the data is entered -in a music file, so we add @code{#}s everywhere. @node LilyPond variables @subsection LilyPond variables - -TODO -- make this read right - -A similar thing happens with variables. After defining a variable +LilyPond variables are stored internally in the form of Scheme +variables. Thus, @example twelve = 12 @end example @noindent -variables can also be used in expressions, here +is equivalent to + +@example +#(define twelve 12) +@end example + +This means that LilyPond variables are available +for use in Scheme expressions. For example, we could use @example -twentyFour = (* 2 twelve) +twentyFour = #(* 2 twelve) @end example @noindent -the number 24 is stored in the variable @code{twentyFour}. +which would result in the number 24 being stored in the +LilyPond (and Scheme) variable @code{twentyFour}. + +The usual way to refer to Lilypond variables, @ref{LilyPond Scheme +syntax}, is to call them using a backslash, i.e., @code{\twentyFour}. +Since this creates a copy of the value for most of LilyPond's internal +types, in particular music expressions, music functions don't usually +create copies of material they change. For this reason, music +expressions given with @code{#} should usually not contain material that +is not either created from scratch or explicitly copied rather than +directly referenced. @node Input variables and Scheme @subsection Input variables and Scheme @@ -688,10 +798,12 @@ traLaLa = @{ c'4 d'4 @} 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 @@ -699,18 +811,20 @@ 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 +the form: + @example traLaLa = @{ c'4 d'4 @} @end example @noindent -is internally converted to a Scheme definition +is internally converted to a Scheme definition: + @example -(define traLaLa @var{Scheme value of `@code{... }'}) +(define traLaLa @var{Scheme value of `@code{@dots{}}'}) @end example -This means that input variables and Scheme variables may be freely +This means that LilyPond 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 @@ -719,46 +833,80 @@ imported in a @code{\score} block by means of a second variable @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 } +\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. +This is actually a rather interesting example. The assignment will only +take place after the parser has ascertained that nothing akin to +@code{\addlyrics} follows, so it needs to check what comes next. It +reads @code{#} and the following Scheme expression @emph{without} +evaluating it, so it can go ahead with the assignment, and +@emph{afterwards} execute the Scheme code without problem. + +@node Importing Scheme in LilyPond +@subsection Importing Scheme in LilyPond +@funindex $ +@funindex # 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 +placing it after @code{$}, 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))) @} +@dots{} +$(make-sequential-music newLa) +@end example + +You can use @code{$} with a Scheme expression anywhere you could use +@code{\@var{name}} after having assigned the Scheme expression to a +variable @var{name}. This replacement happens in the @q{lexer}, so +Lilypond is not even aware of the difference. + +One drawback, however, is that of timing. If we had been using @code{$} +instead of @code{#} for defining @code{newLa} in the above example, the +following Scheme definition would have failed because @code{traLaLa} +would not yet have been defined. For an explanation of this timing +problem, @ref{LilyPond Scheme syntax}. + +@funindex $@@ +@funindex #@@ +A further convenience can be the @q{list splicing} operators @code{$@@} +and @code{#@@} for inserting the elements of a list in the surrounding +context. Using those, the last part of the example could have been +written as + +@example +@dots{} +@{ #@@newLa @} +@end example + +Here, every element of the list stored in @code{newLa} is taken in +sequence and inserted into the list, as if we had written + +@example +@{ #(first newLa) #(second 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 +Now in all of these forms, the Scheme code is evaluated while the +input is still being consumed, either in the lexer or in the parser. +If you need it to be executed at a later point of time, check out +@ref{Void scheme functions}, or store it in a procedure: @example #(define (nopc) (ly:set-option 'point-and-click #f)) -... +@dots{} #(nopc) @{ c'4 @} @end example @@ -766,24 +914,28 @@ define some Scheme code in a macro (to be called later), use @knownissues Mixing Scheme and LilyPond variables is not possible with the -@code{--safe} option. - - +@option{--safe} option. @node Object properties @subsection Object properties -This syntax will be used very frequently, since many of the layout -tweaks involve assigning (Scheme) values to internal variables, for -example +Object properties are stored in LilyPond in the form of alist-chains, +which are lists of alists. Properties are set by adding values at +the beginning of the property list. Properties are read by retrieving +values from the alists. + +Setting a new value for a property requires assigning a value to +the alist with both a key and a value. The LilyPond syntax for doing +this is: @example -\override Stem #'thickness = #2.6 +\override Stem.thickness = #2.6 @end example -This instruction adjusts the appearance of stems. The value @code{2.6} -is put into the @code{thickness} variable of a @code{Stem} +This instruction adjusts the appearance of stems. An alist entry +@code{'(thickness . 2.6)} is added to the property list of the +@code{Stem} object. @code{thickness} is measured relative to the thickness of staff lines, so these stem lines will be @code{2.6} times the width of staff lines. This makes stems almost twice as thick as their @@ -791,7 +943,7 @@ normal size. To distinguish between variables defined in input files (like @code{twentyFour} in the example above) and variables of internal objects, we will call the latter @q{properties} and the former @q{variables.} So, the stem object has a @code{thickness} property, -while @code{twentyFour} is an variable. +while @code{twentyFour} is a variable. @cindex properties vs. variables @cindex variables vs. properties @@ -803,41 +955,93 @@ while @code{twentyFour} is an variable. @node LilyPond compound variables @subsection LilyPond compound variables -@subheading Offsets +@menu +* Offsets:: +* Fractions:: +* Extents:: +* Property alists:: +* Alist chains:: +@end menu + +@node Offsets +@unnumberedsubsubsec Offsets -Two-dimensional offsets (X and Y coordinates) as well as object sizes -(intervals with a left and right point) are entered as @code{pairs}. A -pair@footnote{In Scheme terminology, the pair is called @code{cons}, -and its two elements are called @code{car} and @code{cdr} respectively.} -is entered as @code{(first . second)} and, like symbols, they must be quoted, +Two-dimensional offsets (X and Y coordinates) are stored as @emph{pairs}. +The @code{car} of the offset is the X coordinate, and the @code{cdr} is +the Y coordinate. @example -\override TextScript #'extra-offset = #'(1 . 2) +\override TextScript.extra-offset = #'(1 . 2) @end example -This assigns the pair (1, 2) to the @code{extra-offset} property of the +This assigns the pair @code{(1 . 2)} to the @code{extra-offset} +property of the TextScript object. These numbers are measured in staff-spaces, so this command moves the object 1 staff space to the right, and 2 spaces up. -@subheading Extents +Procedures for working with offsets are found in @file{scm/lily-library.scm}. -todo -- write something about extents +@node Fractions +@unnumberedsubsubsec Fractions -@subheading Property alists +Fractions as used by LilyPond are again stored as @emph{pairs}, this +time of unsigned integers. While Scheme can represent rational numbers +as a native type, musically @samp{2/4} and @samp{1/2} are not the same, +and we need to be able to distinguish between them. Similarly there are +no negative @q{fractions} in LilyPond's mind. So @code{2/4} in LilyPond +means @code{(2 . 4)} in Scheme, and @code{#2/4} in LilyPond means +@code{1/2} in Scheme. -todo -- write something about property alists +@node Extents +@unnumberedsubsubsec Extents -@subheading Alist chains +Pairs are also used to store intervals, which represent a range of numbers +from the minimum (the @code{car}) to the maximum (the @code{cdr}). +Intervals are used to store the X- and Y- extents of printable objects. +For X extents, the @code{car} is the left hand X coordinate, and the +@code{cdr} is the right hand X coordinate. For Y extents, the @code{car} +is the bottom coordinate, and the @code{cdr} is the top coordinate. -todo -- write something about alist chains +Procedures for working with intervals are found in +@file{scm/lily-library.scm}. These procedures should be used when possible +to ensure consistency of code. + +@node Property alists +@unnumberedsubsubsec Property alists + +A property alist is a LilyPond data structure that is an alist whose +keys are properties and whose values are Scheme expressions that give +the desired value for the property. + +LilyPond properties are Scheme symbols, such as @code{'thickness}. + +@node Alist chains +@unnumberedsubsubsec Alist chains + +An alist chain is a list containing property alists. + +The set of all properties that will apply to a grob is typically +stored as an alist chain. In order to find the value for a particular +property that a grob should have, each alist in the chain is searched in +order, looking for an entry containing the property key. The first alist +entry found is returned, and the value is the property value. + +The Scheme procedure @code{chain-assoc-get} is normally used to get +grob property values. @node Internal music representation @subsection Internal music representation +Internally, music is represented as a Scheme list. The list contains +various elements that affect the printed output. Parsing is the process +of converting music from the LilyPond input representation to the +internal Scheme 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. +it takes up time. The time it takes up is called its @emph{duration}. +Durations are expressed as a rational number that measures the length +of the music object in whole notes. A music object has three kinds of types: @itemize @@ -917,70 +1121,113 @@ will display 'SequentialMusic 'elements (list (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) - (make-music 'AbsoluteDynamicEvent 'text - "f"))))) + "f")) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 0 0)))) @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. +the results of @code{\display@{STUFF@}}, you can specify an optional +output port to use: + +@example +@{ + \displayMusic #(open-output-file "display.txt") @{ c'4\f @} +@} +@end example +This will overwrite a previous output file whenever it is called; if you +need to write more than one expression, you would use a variable for +your port and reuse it: @example -lilypond file.ly >display.txt +@{ + port = #(open-output-file "display.txt") + \displayMusic \port @{ c'4\f @} + \displayMusic \port @{ d'4 @} + #(close-output-port port) +@} @end example -With a bit of reformatting, the above information is easier to read, +Guile's manual describes ports in detail. Closing the port is actually +only necessary if you need to read the file before Lilypond finishes; in +the first example, we did not bother to do so. + +A bit of reformatting makes the above information 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"))))) + 'elements (list + (make-music 'NoteEvent + 'articulations (list + (make-music 'AbsoluteDynamicEvent + 'text + "f")) + 'duration (ly:make-duration 2 0 1/1) + 'pitch (ly:make-pitch 0 0 0)))) @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. +A @code{@{ @dots{} @}} 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 a +@code{NoteEvent} object (storing the duration and pitch properties) with +attached information (in this case, an @code{AbsoluteDynamicEvent} with +a @code{"f"} text property) stored in its @code{articulations} property. +@funindex{\void} +@code{\displayMusic} returns the music it displays, so it will get +interpreted as well as displayed. To avoid interpretation, write +@code{\void} before @code{\displayMusic}. @node Music properties @subsection Music properties -The @code{NoteEvent} object is the first object of the -@code{'elements} property of @code{someNote}. +TODO -- make sure we delineate between @emph{music} properties, +@emph{context} properties, and @emph{layout} properties. These +are potentially confusing. + +Let's look at an example: @example someNote = c' \displayMusic \someNote ===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 0 0)) +@end example + +The @code{NoteEvent} object is the representation of @code{someNote}. +Straightforward. How about putting c' in a chord? + +@example +someNote = +\displayMusic \someNote +===> (make-music 'EventChord 'elements (list (make-music 'NoteEvent 'duration - (ly:make-duration 2 0 1 1) + (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)))) @end example +Now the @code{NoteEvent} object is the first object of the +@code{'elements} property of @code{someNote}. + The @code{display-scheme-music} function is the function used by @code{\displayMusic} to display the Scheme representation of a music expression. @@ -991,7 +1238,7 @@ expression. (make-music 'NoteEvent 'duration - (ly:make-duration 2 0 1 1) + (ly:make-duration 2 0 1/1) 'pitch (ly:make-pitch 0 0 0)) @end example @@ -1017,7 +1264,7 @@ The note pitch can be changed by setting this @code{'pitch} property, (ly:make-pitch 0 1 0)) ;; set the pitch to d'. \displayLilyMusic \someNote ===> -d' +d'4 @end example @@ -1025,7 +1272,7 @@ d' @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 +@code{a} into @code{@{ a( a) @}}. We begin by examining the internal representation of the desired result. @example @@ -1035,70 +1282,65 @@ representation of the desired result. 'SequentialMusic 'elements (list (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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))) + -1)) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 5 0)) (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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))))) + 1)) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch 0 5 0)))) @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). +must be added @q{inside} the note (in its @code{articulations} +property). Now we examine the input, @example +\displayMusic 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)))))) + '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}. +So in our function, we need to clone this expression (so that we have +two notes to build the sequence), add a @code{SlurEvent} to the +@code{'articulations} property of each one, and finally make a +@code{SequentialMusic} with the two @code{NoteEvent} elements. For adding to a +property, it is useful to know that an unset property is read out as +@code{'()}, the empty list, so no special checks are required before we +put another element at the front of the @code{articulations} property. @example doubleSlur = #(define-music-function (parser location note) (ly:music?) "Return: @{ note ( note ) @}. - `note' is supposed to be an EventChord." + `note' is supposed to be a single note." (let ((note2 (ly:music-deep-copy note))) - (set! (ly:music-property note 'elements) + (set! (ly:music-property note 'articulations) (cons (make-music 'SlurEvent 'span-direction -1) - (ly:music-property note 'elements))) - (set! (ly:music-property note2 'elements) + (ly:music-property note 'articulations))) + (set! (ly:music-property note2 'articulations) (cons (make-music 'SlurEvent 'span-direction 1) - (ly:music-property note2 'elements))) + (ly:music-property note2 'articulations))) (make-music 'SequentialMusic 'elements (list note note2)))) @end example @@ -1107,11 +1349,14 @@ doubleSlur = #(define-music-function (parser location note) (ly:music?) @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 +expressions into one context. +However, suppose that we want to write a music function that does this. +This will have the additional advantage that we can use that music +function to add an articulation (like a fingering instruction) to a +single note inside of a chord which is not possible if we just merge +independent music. + +A @code{$variable} inside the @code{#@{@dots{}#@}} notation is like a regular @code{\variable} in classical LilyPond notation. We know that @@ -1121,10 +1366,10 @@ know that @noindent will not work in LilyPond. We could avoid this problem by attaching -the articulation to a fake note, +the articulation to an empty chord, @example -@{ << \music s1*0-.-> @} +@{ << \music <> -. -> >> @} @end example @noindent @@ -1136,140 +1381,147 @@ Scheme. We begin by examining our input and 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)))) + 'NoteEvent + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch -1 0 0)))) ===== % desired output \displayMusic c4-> ===> (make-music - 'EventChord - 'elements + 'NoteEvent + 'articulations (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"))) + "accent")) + 'duration + (ly:make-duration 2 0 1/1) + 'pitch + (ly:make-pitch -1 0 0)) @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. +We see that a note (@code{c4}) is represented as an @code{NoteEvent} +expression. To add an accent articulation, an @code{ArticulationEvent} +expression must be added to the @code{articulations} property of the +@code{NoteEvent} 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)) +(define (add-accent note-event) + "Add an accent ArticulationEvent to the articulations of `note-event', + which is supposed to be a NoteEvent expression." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) @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 +name is @code{add-accent}, and has one variable called +@code{note-event}. 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..." +"Add an accent@dots{}" @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. +You may wonder why we modify the note event directly instead of working +on a copy (@code{ly:music-deep-copy} can be used for that). The reason +is a silent contract: music functions are allowed to modify their +arguments: they are either generated from scratch (like user input) or +are already copied (referencing a music variable with @samp{\name} or +music from immediate Scheme expressions @samp{$(@dots{})} provides a +copy). Since it would be inefficient to create unnecessary copies, the +return value from a music function is @emph{not} copied. So to heed +that contract, you must not use any arguments more than once, and +returning it counts as one use. + +In an earlier example, we constructed music by repeating a given music +argument. In that case, at least one repetition had to be a copy of its +own. If it weren't, strange things may happen. For example, if you use +@code{\relative} or @code{\transpose} on the resulting music containing +the same elements multiple times, those will be subjected to +relativation or transposition multiple times. If you assign them to a +music variable, the curse is broken since referencing @samp{\name} will +again create a copy which does not retain the identity of the repeated +elements. + +Now while the above function is not a music function, it will normally +be used within music functions. So it makes sense to heed the same +contract we use for music functions: the input may be modified for +producing the output, and the caller is responsible for creating copies +if it still needs the unchanged argument itself. If you take a look at +LilyPond's own functions like @code{music-map}, you'll find that they +stick with the same principles. + +Where were we? Now we have a @code{note-event} we may modify, not +because of using @code{ly:music-deep-copy} but because of a long-winded +explanation. We add the accent to its @code{'articulations} 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. +Here, what we want to set (the @q{place}) is the @code{'articulations} +property of @code{note-event} expression. @example -(ly:music-property result-event-chord 'elements) +(ly:music-property note-event 'articulations) @end example @code{ly:music-property} is the function used to access music properties -(the @code{'elements}, @code{'duration}, @code{'pitch}, etc, that we +(the @code{'articulations}, @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 +former @code{'articulations} 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)) + 'articulation-type "accent") + (ly:music-property result-event-chord 'articulations)) @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. +@code{cons} is used to add an element to the front of 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{'articulations} 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. +Finally, once we have added the accent articulation to its +@code{articulations} property, we can return @code{note-event}, hence +the last line of the function. -Now we transform the @code{add-marcato} function into a music -function, +Now we transform the @code{add-accent} function into a music +function (a matter of some syntactic sugar and a declaration of the type +of its sole @q{real} argument). @example -addMarcato = #(define-music-function (parser location event-chord) +addAccent = #(define-music-function (parser location note-event) (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)) + "Add an accent ArticulationEvent to the articulations of `note-event', + which is supposed to be a NoteEvent expression." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) @end example We may verify that this music function works correctly, @example -\displayMusic \addMarcato c4 +\displayMusic \addAccent c4 @end example @@ -1286,7 +1538,7 @@ We may verify that this music function works correctly, We have seen how LilyPond output can be heavily modified using commands like -@code{\override TextScript #'extra-offset = ( 1 . -1)}. But +@code{\override TextScript.extra-offset = ( 1 . -1)}. But we have even more power if we use Scheme. For a full explanation of this, see the @ref{Scheme tutorial}, and @ref{Interfaces for programmers}. @@ -1302,11 +1554,11 @@ TODO Find a simple example @lilypond[quote,verbatim,ragged-right] padText = #(define-music-function (parser location padding) (number?) #{ - \once \override TextScript #'padding = #$padding + \once \override TextScript.padding = #padding #}) -\relative c''' { - c4^"piu mosso" b a b +\relative { + c'''4^"piu mosso" b a b \padText #1.8 c4^"piu mosso" d e f \padText #2.6 @@ -1324,16 +1576,16 @@ We can use it to create new commands: @lilypond[quote,verbatim,ragged-right] tempoPadded = #(define-music-function (parser location padding tempotext) - (number? string?) + (number? markup?) #{ - \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } + \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" + \tempoPadded #4.0 "High tempo" g4 f e d c1 } @end lilypond @@ -1344,7 +1596,7 @@ Even music expressions can be passed in: @lilypond[quote,verbatim,ragged-right] pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) #{ - $x e8 a b $y b a e + #x e8 a b #y b a e #}) \relative c''{