Pregunta

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"
        }
    }

}
¿Fue útil?

Solución

Unfortunatey, it's not possible to stick assignments in a score. You can only put assignments in the following places:

  • the top level,
  • inside \display, \header, and \midi blocks

The 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:

  1. Define 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.
  2. Settle for your approach, though I would pick a prefix or a suffix that makes it clearer which score the define goes with.

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.

Otros consejos

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top