2

I have a software development background, but I'm new to LilyPond. I'm trying to create a function that will allow me to pass in a number and then return some text depending on which number is passed in.

Example: \getStanza 2

#(define-scheme-function
    (stanza)
    (number?)
  #{
    % conditional code goes here
  #}

I've tried this:

(
  cond ((#stanza 1) \lyricsStanzaOne)
  cond ((#stanza 2) \lyricsStanzaTwo)
  cond ((#stanza 3) \lyricsStanzaThree)
)

And this:

\if (#stanza 1) \lyricsStanzaOne
\if (#stanza 2) \lyricsStanzaTwo
\if (#stanza 3) \lyricsStanzaThree

But I get an "ignoring non-music expression" warning and the lyrics for stanza one are returned, preceded by the word "if" or "cond" depending on which code block I try to use.

The LilyPond documentation doesn't provide much in the way of examples, so it's been a lot of trial and error just to get this far.

1 Answer 1

3

Lilypond somewhat consists of two languages, the Lilypond markup language and guile. These can be somewhat interchanged, as scheme code can be injected in lilypond language code by using # or $ (these have somewhat different meanings!), and lilypond language can be parsed and evaluated in guile using #{ ... #}.

If you use the Lilypond syntax A = B this will also define a scheme binding for A. So you can simply reference these things from scheme code.

Finally a cond in scheme works like this: (cond (condidion1 value1) (condition2 value2) ... (else default-value)) where the conditions are boolean values (and the else part is optional).

So one way to do what you want would be

getStanza =
#(define-scheme-function
    (stanza)
    (number?)
  (cond ((= stanza 1) lyricsStanzaOne)
        ((= stanza 2) lyricsStanzaTwo)
        ((= stanza 3) lyricsStanzaThree)
        (else "")))


lyricsStanzaOne = "abc"
lyricsStanzaTwo = "def"
lyricsStanzaThree = "ghi"

\getStanza 2

Using the conditional markup statements is probably not what you want, as the evaluation happens after parsing during rendering, so it will lead to an overly complicated structure. That one is specific for markups, so it needs to have a \markup statement. The way to do it would be

getStanza = #(define-scheme-function
    (stanza) (number?)
    #{
      \markup {
        \if #(lambda (. args) (= stanza 1)) \lyricsStanzaOne
        \if #(lambda (. args) (= stanza 2)) \lyricsStanzaTwo
        \if #(lambda (. args) (= stanza 3)) \lyricsStanzaThree
      }
    #})

lyricsStanzaOne = "abc"
lyricsStanzaTwo = "def"
lyricsStanzaThree = "ghi"

\getStanza #1
7
  • 1
    You are apparently using LilyPond 2.22. The \if markup command is new in 2.23.
    – jeanas
    Sep 7, 2022 at 11:41
  • 1
    @Scott Previously to that there was a syntax \on-the-fly #fn ... where fn is (markup) function. So equivalently to the \if syntax you could do something like \on-the-fly #(lambda (layout props mu) (if (= stanza 1) (interpret-markup layout props mu) empty-stencil)) \lyricsStanzaOne which also works in 2.22.
    – Lazy
    Sep 7, 2022 at 19:55
  • 1
    @Scott But for reasons already mentioned the first way should be more reasonable to use. To see the difference compare the output of #(display (getStanza 1)) with both methods. With the first one you get abc, while with the second you get (#<procedure line-markup (a b c)> ((#<procedure on-the-fly-markup (a b c d)> #<procedure 7f4d3367aec0 at ice-9/eval.scm:339:13 (a b c)> abc) (#<procedure on-the-fly-markup (a b c d)> #<procedure 7f4d3367a920 at ice-9/eval.scm:339:13 (a b c)> def) (#<procedure on-the-fly-markup (a b c d)> #<procedure 7f4d3367a380 at ice-9/eval.scm:339:13 (a b c)> ghi))).
    – Lazy
    Sep 7, 2022 at 20:00
  • 1
    @Scott Of course the memory addresses of the lambdas will be different each try. But you see that the second method actually delays evaluation of this expression until the markup is actually rendered.
    – Lazy
    Sep 7, 2022 at 20:02
  • 1
    @Scott Lilypond has a development cycle where all even releases are stable releases and all odd releases are development releases (though usually stable and fit for production). This means that the current stable version of Lilypond is 2.22.2, while the development version is 2.23.12. Eventually the 2.23.x version will be released as stable release 2.24.0.
    – Lazy
    Sep 8, 2022 at 10:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.