Guide, node Updating translation committishes..
@end ignore
-@c \version "2.17.11"
+@c \version "2.19.22"
@node Scheme tutorial
@chapter Scheme tutorial
users may simply choose @q{Run} from the Start menu and enter
@q{guile}.
-However, a hands-on Scheme sandbox with all of Lilypond loaded is
+However, a hands-on Scheme sandbox with all of LilyPond loaded is
available with this command line:
@example
lilypond scheme-sandbox
@lisp
guile> (define mypair (cons 123 "hello there")
-... )
+@dots{} )
guile> (car mypair)
123
guile> (cdr mypair)
@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:
(1 2 3 "abc" 17.5)
@end lisp
-As can be seen, a list is displayed in the form of individual elements
-separated by whitespace and enclosed in parentheses. Unlike a pair,
-there is no period between the elements.
+Representing a list as individual
+elements separated by whitespace and enclosed in parentheses
+is actually a compacted rendition of the actual dotted pairs
+constituting the list, where the dot and an immediately following
+starting paren are removed along with the matching closing paren.
+Without this compaction, the output would have been
+@lisp
+(1 . (2 . (3 . ("abc" . (17.5 . ())))))
+@end lisp
-A list can also be entered as a literal list by enclosing its
-elements in parentheses, and adding a quote:
+As with the output, a list can also be entered (after adding a
+quote to avoid interpretation as a function call) as a literal
+list by enclosing its elements in parentheses:
@lisp
guile> '(17 23 "foo" "bar" "bazzle")
@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
@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
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
+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}
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
+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
+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
+consistent with the current LilyPond mode are accepted.
+
+The immediate action of @code{$} can lead to surprises, see
+@ref{Importing Scheme in LilyPond}. 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 $@@
@end example
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
+in a music file, so we add a @code{#} 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
+be combined into a single Scheme expression by use of the
@code{begin} statement:
@example
@end example
@noindent
-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.
+which would result in the number @emph{24} being stored in the LilyPond
+(and Scheme) variable @code{twentyFour}.
+
+Scheme allows modifying complex expressions in-place and LilyPond makes
+use of this @q{in-place modification} when using music functions. But
+when music expressions are stored in variables rather than entered
+directly the usual expectation, when passing them to music functions,
+would be that the original value is unmodified. So when referencing a
+music variable with leading backslash (such as @code{\twentyFour}),
+LilyPond creates a copy of that variable's music value for use in the
+surrounding music expression rather than using the variable's value
+directly.
+
+Therefore, Scheme music expressions written with the @code{#} syntax
+should be used for material that is created @q{from scratch} (or that is
+explicitly copied) rather than being used, instead, to directly
+reference material.
+
+@seealso
+Extending:
+@ref{LilyPond Scheme syntax}.
+
@node Input variables and Scheme
@subsection Input variables and Scheme
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 LilyPond variables and Scheme variables may be freely
been written as
@example
-...
+@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.
+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
written as
@example
-...
+@dots{}
@{ #@@newLa @}
@end example
#(define (nopc)
(ly:set-option 'point-and-click #f))
-...
+@dots{}
#(nopc)
@{ c'4 @}
@end example
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}
+music function @code{\displayMusic}.
@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
-lilypond file.ly >display.txt
+@{
+ \displayMusic #(open-output-file "display.txt") @{ c'4\f @}
+@}
@end example
-With a combined bit of Lilypond and Scheme magic, you can actually
-let Lilypond direct just this output to a file of its own:
-
+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
@{
- #(with-output-to-file "display.txt"
- (lambda () #@{ \displayMusic @{ c'4\f @} #@}))
+ port = #(open-output-file "display.txt")
+ \displayMusic \port @{ c'4\f @}
+ \displayMusic \port @{ d'4 @}
+ #(close-output-port port)
@}
@end example
+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 'NoteEvent
+ (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))))
+ (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 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.
+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
@node Music properties
@subsection Music properties
+@ignore
TODO -- make sure we delineate between @emph{music} properties,
@emph{context} properties, and @emph{layout} properties. These
are potentially confusing.
+@end ignore
Let's look at an example:
@end example
Then the note pitch is accessed through the @code{'pitch} property
-of the @code{NoteEvent} object,
+of the @code{NoteEvent} object.
@example
#(display-scheme-music
(ly:make-pitch 0 0 0)
@end example
-The note pitch can be changed by setting this @code{'pitch} property,
+The note pitch can be changed by setting this @code{'pitch} property.
@funindex \displayLilyMusic
(ly:make-pitch 0 1 0)) ;; set the pitch to d'.
\displayLilyMusic \someNote
===>
-d'
+d'4
@end example
must be added @q{inside} the note (in its @code{articulations}
property).
-Now we examine the input,
+Now we examine the input.
@example
\displayMusic a'
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{EventChords}. For adding to 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?)
+doubleSlur = #(define-music-function (note) (ly:music?)
"Return: @{ note ( note ) @}.
`note' is supposed to be a single note."
(let ((note2 (ly:music-deep-copy note)))
single note inside of a chord which is not possible if we just merge
independent music.
-A @code{$variable} inside the @code{#@{...#@}} notation is like
+A @code{$variable} inside the @code{#@{@dots{}#@}} notation is like
a regular @code{\variable} in classical LilyPond notation. We
know that
@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,
+Scheme. We begin by examining our input and desired output.
@example
% input
too!)
@example
-"Add an accent..."
+"Add an accent@dots{}"
@end example
@noindent
@code{articulations} property, we can return @code{note-event}, hence
the last line of the 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).
+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
+argument).
@example
-addAccent = #(define-music-function (parser location note-event)
+addAccent = #(define-music-function (note-event)
(ly:music?)
"Add an accent ArticulationEvent to the articulations of `note-event',
which is supposed to be a NoteEvent expression."
note-event)
@end example
-We may verify that this music function works correctly,
+We then verify that this music function works correctly:
@example
\displayMusic \addAccent c4
@ignore
@lilypond[quote,verbatim,ragged-right]
-padText = #(define-music-function (parser location padding) (number?)
+padText = #(define-music-function (padding) (number?)
#{
\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
@lilypond[quote,verbatim,ragged-right]
-tempoPadded = #(define-music-function (parser location padding tempotext)
+tempoPadded = #(define-music-function (padding tempotext)
(number? markup?)
#{
\once \override Score.MetronomeMark.padding = #padding
\tempo \markup { \bold #tempotext }
#})
-\relative c'' {
+\relative {
\tempo \markup { "Low tempo" }
- c4 d e f g1
+ c''4 d e f g1
\tempoPadded #4.0 "High tempo"
g4 f e d c1
}
Even music expressions can be passed in:
@lilypond[quote,verbatim,ragged-right]
-pattern = #(define-music-function (parser location x y) (ly:music? ly:music?)
+pattern = #(define-music-function (x y) (ly:music? ly:music?)
#{
#x e8 a b #y b a e
#})