I compile a large song book, and for that I would like to have many local definitions of functions, that will, in the end, be in an \include
d file, but that makes no difference here. For this, I need to define the functions inside \score{ ... }
scope. However, LilyPond keeps throwing errors.
The non-working example:
\version "2.17.26"
\book {
\header {
title = "This is a book"
}
\score {
xyz = { a' b' c'' }
abc = #(define-music-function
( parser location musicnotes )
( ly:music? )
#{
c' $musicnotes e'
#}
)
{ \abc { d' } f' \xyz }
\header {
piece = "First piece"
opus = "op. 1024"
}
}
\score {
xyz = { a' a' a' }
abc = #(define-music-function
( parser location musicnotes )
( ly:music? )
#{
e' $musicnotes c'
#}
)
{ \abc { d' } f' \xyz }
\header {
piece = "Second piece"
opus = "op. 1025"
}
}
}
Throws an error:
test.ly:10:17: error: unrecognized string, not in text script or \lyricmode xyz = { a' b' c'' }
The following works, however, I have to give the functions unique names, which is frowned upon.
\version "2.17.26"
xyz = { a' b' c'' }
abc = #(define-music-function
( parser location musicnotes )
( ly:music? )
#{
c' $musicnotes e'
#}
)
xxyz = { a' a' a' }
aabc = #(define-music-function
( parser location musicnotes )
( ly:music? )
#{
e' $musicnotes c'
#}
)
\book {
\header {
title = "This is a book"
}
\score {
{ \abc { d' } f' \xyz }
\header {
piece = "First piece"
opus = "op. 1024"
}
}
\score {
{ \aabc { d' } f' \xxyz }
\header {
piece = "Second piece"
opus = "op. 1025"
}
}
}
Unfortunatey, it's not possible to stick assignments in a score. You can only put assignments in the following places:
\display
, \header
, and \midi
blocksThe LilyPond grammar makes this quite clear, even if the rest of the manual is a bit evasive about it. (Look at http://lilypond.org/doc/v2.17/Documentation/contributor/lilypond-grammar , and look for where the assignment
rule gets used).
Assuming your assignments are not appropriate for the blocks listed above (which is definitely the case in this example), and assuming that you don't want to do something exotic like go and define your own Scheme modules and figure out how to use them in your LilyPond file, you have two choices:
xyz
and abc
, then define the music that will go into the first score. Then redefine xyz
and abc
before defining the music for the next score. This works because assignments overwrite whatever was previously there, and because LilyPond defines are generally processed in order. However, if you want some of your defines to be used in both scores and to be the same, you may get confused.The first option would look something like this:
\version "2.18.0"
xyz = { a' b' c'' }
abc = #(define-music-function (parser location musicnotes)
(ly:music?)
#{ c' $musicnotes e' #})
smus_a = { \abc { d' } f' \xyz }
xyz = { a' a' a' }
abc = #(define-music-function (parser location musicnotes)
(ly:music?)
#{ e' $musicnotes c' #})
smus_b = { \abc { d' } f' \xyz }
\book {
\header {
title = "A Book!"
}
\score {
\smus_a
\header { piece = "First piece" }
}
\score {
\smus_b
\header { piece = "Second piece" }
}
}
This also works if the music-defining parts are refactored out into separate LilyPond source files.
It is possible! But you have to define a command to define the variable or command:
parserDefine =
#(define-void-function (parser location name val)(symbol? scheme?)
(ly:parser-define! parser name val))
This is a void-function and can be called almost anywhere:
\score {
{
% you have to be in your music-expression
\parserDefine xyz { a' a' a' }
% There must be something between parserDefine and the call!
c'' \xyz
\parserDefine abc #(define-music-function
( parser location musicnotes )
( ly:music? )
#{
c' $musicnotes e'
#}
)
a' \abc d'
}
}
If the command is defined, you can call inside your music expressions. After you have done so, the parser needs a little lookahead, so that the variable really is available - here its the c''. You can optionally wrap the expression in another pair of curly braces.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With