trick, you might need to revert to immediate Scheme expressions using
@code{$}, for example as @samp{$music}.
-If your function returns a music expression, it is cloned and given the
-correct @code{origin}.
+If your function returns a music expression, it is given a useful value
+of @code{origin}.
@end multitable
@noindent
functions: is @samp{-3} a fingering postevent or a negative number? Is
@code{"a" 4} in lyric mode a string followed by a number, or a lyric
event of duration @code{4}? Lilypond decides by asking the predicates.
-That means that a lenient predicate like @code{scheme?} might be good
-for surprising interpretations.
+That means that you should avoid permissive predicates like
+@code{scheme?} if you have a particular use in mind instead of a general
+purpose function.
For a list of available predefined type predicates, see
@ruser{Predefined type predicates}.
@node Music function usage
@subsection Music function usage
-Music functions may currently be used in three places. Depending on
+Music functions may currently be used in several places. Depending on
where they are used, restrictions apply in order to be able to parse
them unambiguously. The result a music function returns must be
compatible with the context in which it is called.
@itemize
@item
-At top level in a music expression. There are no special restrictions
-on the argument list.
+At top level in a music expression. No restriction apply here.
@item
As a post-event, explicitly started with a direction indicator (one of
-@code{-}, @code{^}, @w{and @code{_}}). All trailing arguments of the
-music function with the predicate @code{ly:music?} will get parsed also
-as post-events (if the last argument is a scheme function, this will
-hold for trailing @code{ly:music?} arguments of the scheme function
-instead). Note that returning a post-event will be acceptable for music
-functions called as normal music, leading to a result roughly equivalent
-to
+@code{-}, @code{^}, @w{and @code{_}}). Note that returning a post-event
+will be acceptable for music functions called as normal music, leading
+to a result roughly equivalent to
@example
s 1*0-\fun
@end example
+In this case, you can't use an @emph{open} music expression as the last
+argument, one that would end with a music expression able to accept
+additional postevents.
+
@item
-As a chord constituent. All trailing arguments of the music function
-with the predicate @code{ly:music?} will get parsed also as chord
-constituents.
+As a chord constituent. The returned expression must be of
+@code{rhythmic-event} type, most likely a @code{NoteEvent}.
@end itemize
@noindent
@node Inline Scheme code
@section Inline Scheme code
+TODO: the example for this section is ill-chosen since
+@example
+F = -\tweak #'font-size #-3 -\flageolet
+@end example
+(note the @samp{-} marking it as a post event) will actually work fine
+for the stated purpose. Until this section gets a rewrite, let's
+pretend we don't know.
+
The main disadvantage of @code{\tweak} is its syntactical
inflexibility. For example, the following produces a syntax error.
@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.
@subheading Offsets
-Two-dimensional offsets (X and Y coordinates) are stored as @code{pairs}.
+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.
Procedures for working with offsets are found in @file{scm/lily-library.scm}.
+@subheading Fractions
+
+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.
+
@subheading Extents
Pairs are also used to store intervals, which represent a range of numbers
'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
@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.
+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
@emph{context} properties, and @emph{layout} properties. These
are potentially confusing.
-The @code{NoteEvent} object is the first object of the
-@code{'elements} property of @code{someNote}.
+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 = <c'>
+\displayMusic \someNote
+===>
(make-music
'EventChord
'elements
(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.
@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
'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 a @code{SlurEvent} 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{EventChords}. 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
@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.
+expressions into one context, as explained in @ruser{Creating contexts}.
+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{#@{...#@}} notation is like
a regular @code{\variable} in classical LilyPond notation. We
\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..."
@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
@funindex \tweak
@funindex tweak
-The final tweaking command which is available is @code{\tweak}.
-This should be used to change the properties of objects which
-occur at the same musical moment, such as the notes within a
-chord. Using @code{\override} would affect all the notes
-within a chord, whereas @code{\tweak} affects just the following
+The final tweaking command which is available is @code{\tweak}. This
+should be used when several objects occur at the same musical moment,
+but you only want to change the properties of selected ones, such as a
+single note within a chord. Using @code{\override} would affect all the
+notes within a chord, whereas @code{\tweak} affects just the following
item in the input stream.
Here's an example. Suppose we wish to change the size of the
it is effective only on objects which are created directly from
the input stream, essentially note heads and articulations;
objects such as stems and accidentals are created later and
-cannot be tweaked in this way. Furthermore, when it is applied
-to note heads these @emph{must} be within a chord, i.e., within
-single angle brackets, so to tweak a single note the @code{\tweak}
-command must be placed inside single angle brackets with the
-note.
+cannot be tweaked in this way.
So to return to our example, the size of the middle note of
a chord would be changed in this way:
@end lilypond
@noindent
-Note that the @code{\tweak} command must be preceded by an
-articulation mark as if it were an articulation itself.
+Note that the @code{\tweak} command must be preceded by an articulation
+mark since the tweaked expression needs to be applied as an articulation
+itself. In case of multiple direction overrides (@code{^} or @code{_}),
+the leftmost override wins since it is applied last.
@cindex tuplets, nested
@cindex triplets, nested
}
VerseTwo = \lyricmode {
- O | \emphasize Christ, \normal whose voice the | wa -- ters heard,
+ O | \once \emphasize Christ, whose voice the | wa -- ters heard,
}
VerseThree = \lyricmode {
@lilypond[quote,verbatim,ragged-right]
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #{ \markup { \hspace #0
+ \translate #'(5 . 0)
+ \line { \dynamic "mp"
+ \text \italic "dolce" } }
+ #})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #{ ^\markup \bold \box #string #})
\relative c'' {
\tempo 4=50
%%% save this to a file called "definitions.ily"
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #@{ \markup @{ \hspace #0
+ \translate #'(5 . 0)
+ \line @{ \dynamic "mp"
+ \text \italic "dolce" @} @}
+ #@})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #@{ ^\markup \bold \box #string #@})
@end example
We will refer to this file using the @code{\include} command near
@lilypond[quote,ragged-right]
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #{ \markup { \hspace #0
+ \translate #'(5 . 0)
+ \line { \dynamic "mp"
+ \text \italic "dolce" } }
+ #})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #{ ^\markup \bold \box #string #})
\relative c'' {
\tempo 4=50
%%% definitions.ily
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #@{ \markup @{ \hspace #0
+ \translate #'(5 . 0)
+ \line @{ \dynamic "mp"
+ \text \italic "dolce" @} @}
+ #@})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #@{ ^\markup \bold \box #string #@})
\layout@{
\context @{
@lilypond[quote,ragged-right]
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #{ \markup { \hspace #0
+ \translate #'(5 . 0)
+ \line { \dynamic "mp"
+ \text \italic "dolce" } }
+ #})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #{ ^\markup \bold \box #string #})
\layout{
\context {
%%% definitions.ily
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #@{ \markup @{ \hspace #0
+ \translate #'(5 . 0)
+ \line @{ \dynamic "mp"
+ \text \italic "dolce" @} @}
+ #@})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #@{ ^\markup \bold \box #string #@})
#(set-global-staff-size 23)
@lilypond[quote,ragged-right]
mpdolce =
#(make-dynamic-script
- (markup #:hspace 0
- #:translate '(5 . 0)
- #:line (#:dynamic "mp"
- #:text #:italic "dolce")))
+ #{ \markup { \hspace #0
+ \translate #'(5 . 0)
+ \line { \dynamic "mp"
+ \text \italic "dolce" } }
+ #})
inst =
#(define-music-function
(parser location string)
(string?)
- (make-music
- 'TextScriptEvent
- 'direction UP
- 'text (markup #:bold (#:box string))))
+ #{ ^\markup \bold \box #string #})
#(set-global-staff-size 23)