lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Defining a function that passes contents between braces to a markup


From: David Kastrup
Subject: Re: Defining a function that passes contents between braces to a markup
Date: Tue, 19 Jul 2016 14:36:06 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux)

Mojca Miklavec <address@hidden> writes:

> Dear David,
>
> On 16 July 2016 at 09:31, David Kastrup wrote:
>> Mojca Miklavec writes:
>>>
>>> I've learnt some basics of scheme and managed to write some simple
>>> functions, but I'm unable to figure out how to write a function that
>>> would take all the contents between braces as an argument and return a
>>> markup.
>>>
>>> I would be grateful even if I get just the simplified version
>>> working, so that
>>>
>>>     \A {<foo>}
>>>
>>> would be translated into
>>>
>>>     \markup { \small \override #'(direction . 1) { \dir-column { <foo> } } }
>>
>> Well, first thing to note is that scheme/music functions do not switch
>> modes for their arguments.  So you either need to write something like
>>
>> \A \markup <foo>
>>
>> here to get something in markup mode, or be in lyrics mode (which
>> interprets <foo> as lyrics), \A should be a markup command and are
>> already in markup mode, like \markup \A <foo> .
>>
>>> I would use this markup as part of the lyrics as in
>>>
>>>     \lyricsto "melody" {
>>>         \A {foo bar}
>>>         \A {three short lines}
>>>         \A {one}
>>>     }
>>
>> Ah, we are in lyrics mode already.  That simplifies things.  Your
>> arguments will then be of type ly:music? and you'll pick off the
>> respective markup from the 'text field of the lyrics.
>
> I'm no more confused than I was before :(

Well, let's put this in perspective.  I've been throwing stuff at you
without the slightest attempt of toning it down to beginners' level,
basically expecting you to ask back where required.  I cannot remember
any list newcomer ingest stuff at that rate and level and pump out new
iterations.  Either our documentation has improved a lot over time or
you are just good at picking stuff up and secondguessing system design.
Knowing your background, it's likely more of the latter.

So to come back to your question/confusion: a nice debugging tool is
preceding a music expression with \displayMusic.

> How could I simplify the input in attachment?
>
>>> In a slightly more advanced version it would be nice to be able to type
>>>
>>>     \lyricsto "melody" {
>>>       % \command { array of values }
>>>       %            each entry can have an optional "-<number>"
>>>       \A {A1-1}
>>>       \A {A1-1 C2-2}
>>>       \A {A1-1 C2-2 E2-3}
>>>       \A {C2 E2-3}
>>>       \A {E2}
>>>     }

Now let's just make \A equal to \displayMusic and see where this gets
us (also, let's call \displayMusic on the finished expression):

A = #displayMusic

\displayMusic
     \lyricsto "melody" {
       % \command { array of values }
       %            each entry can have an optional "-<number>"
       \A {A1-1}
       \A {A1-1 C2-2}
       \A {A1-1 C2-2 E2-3}
       \A {C2 E2-3}
       \A {E2}
     }

-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Tue Jul 19 14:17:07

lilypond /tmp/mo.ly
GNU LilyPond 2.19.44
Processing `/tmp/mo.ly'
Parsing...
(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'LyricEvent
          'text
          "A"
          'duration
          (ly:make-duration 0))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 0))))


(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'LyricEvent
          'text
          "A"
          'duration
          (ly:make-duration 0))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 0))
        (make-music
          'LyricEvent
          'text
          "C"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 1))))


/tmp/mo.ly:9:25: error: not a duration
       \A {A1-1 C2-2 E2-
                        3}

(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'LyricEvent
          'text
          "A"
          'duration
          (ly:make-duration 0))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 0))
        (make-music
          'LyricEvent
          'text
          "C"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "E"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 0))))

/tmp/mo.ly:10:18: error: not a duration
       \A {C2 E2-
                 3}

(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'LyricEvent
          'text
          "C"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "E"
          'duration
          (ly:make-duration 1))
        (make-music
          'LyricEvent
          'text
          "-"
          'duration
          (ly:make-duration 0))))


(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'LyricEvent
          'text
          "E"
          'duration
          (ly:make-duration 1))))


(make-music
  'LyricCombineMusic
  'associated-context-type
  '()
  'associated-context
  "melody"
  'element
  (make-music
    'SequentialMusic
    'elements
    (list (make-music
            'SequentialMusic
            'elements
            (list (make-music
                    'LyricEvent
                    'text
                    "A"
                    'duration
                    (ly:make-duration 0))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 0))))
          (make-music
            'SequentialMusic
            'elements
            (list (make-music
                    'LyricEvent
                    'text
                    "A"
                    'duration
                    (ly:make-duration 0))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 0))
                  (make-music
                    'LyricEvent
                    'text
                    "C"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 1))))
          (make-music
            'SequentialMusic
            'elements
            (list (make-music
                    'LyricEvent
                    'text
                    "A"
                    'duration
                    (ly:make-duration 0))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 0))
                  (make-music
                    'LyricEvent
                    'text
                    "C"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "E"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 0))))
          (make-music
            'SequentialMusic
            'elements
            (list (make-music
                    'LyricEvent
                    'text
                    "C"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "E"
                    'duration
                    (ly:make-duration 1))
                  (make-music
                    'LyricEvent
                    'text
                    "-"
                    'duration
                    (ly:make-duration 0))))
          (make-music
            'SequentialMusic
            'elements
            (list (make-music
                    'LyricEvent
                    'text
                    "E"
                    'duration
                    (ly:make-duration 1))))
          (make-music (quote CompletizeExtenderEvent)))))

/tmp/mo.ly:1: warning: no \version statement found, please add

\version "2.19.44"

for future compatibility
Interpreting music...
/tmp/mo.ly:4:25: warning: argument of \lyricsto should contain Lyrics context
     \lyricsto "melody" 
                        {

[...]

So, uh, in short I messed up completely here.  Mainly because numbers in
lyrics mode by default are durations rather than text unless enclosed in
quote marks for strings.  The basic idea was that every "syllable" in
lyricsmode gets turned into a LyricEvent and can be picked off from
there, but the way in which numbers are treated in lyrics makes at least
your input proposal unfeasible.  Sorry, got that wrong.


>> Lyrics mode does not really take text scripts I think.  All of A1-1 will
>> likely end up one lyrics syllable.

Yeah, wrong.  Sorry.

>>> So far I came up with a function definition
>>>
>>> M = #(define-scheme-function (parser location aFinger aButton) (markup? 
>>> markup?)
>>>   #{ \markup{ \small \bold \with-color #(rgb-color 0.5 0 0) #aFinger
>>> \small \with-color #(rgb-color 0 0 0.5) #aButton } #}
>>> )
>>> that can handle input like
>>>     \M "1" "A1"
>>> and then I would enter multiple lines of lyrics, but this is tedious
>>> to write, even more so when the number of lines varies from one pitch
>>> to the other.
>>
>> Strings are the most simple form of markup, but I guess that pretty much
>> everything else needs to be explicitly preceded by \markup.  You could
>> work here with an optional finger argument as a number:
>>
>> M =
>> #(define-scheme-function (parser location aFinger aButton) ((number?) 
>> markup?)
>>    (if afinger
>>        #{ \markup{ \small \bold \with-color #(rgb-color 0.5 0 0) #aFinger
>>        \small \with-color #(rgb-color 0 0 0.5) #aButton } #}
>>        ;; #{ \markup whatever you want here when no finger is given #}
>>        ))
>>
>> which can handle then both
>>     \M 1 "A1"
>> as well as
>>     \M "A1"
>
> This doesn't seem to work properly. The number is always treated as
> the second argument (markup). See the attachment.

Omitting the attachment.  The reason here is that you call that function
in markup mode rather than, as proposed, lyrics mode.  In markup mode,
not even numbers turn into anything but strings, so the number?
predicate is never matched.  This function would only work in the
described manner in lyrics mode or normal music mode.

Now I am still digging through the parser looking for how it could best
be tweaked so that one can create a good way of inputting the desired
information.  I was hoping to buy me some time by throwing you some
bones to chew on but you were pretty fast to digest them.

I expect to have to work a bit on the parser in order to have some
reasonably nice way of extending the syntax fall out and the parser (in
lily/parser.yy) is notoriously different to tweak.  You'd need to know
exactly where you want to go when generalizing existing functionality
(regarding both existing design/framework and fitting extension) and how
to keep within the confines of the LALR(1) framework as implemented by
Bison.  I don't consider it realistic to throw bones from the parser at
you because it's just not feasible to work sustainably on the parser
without a good overview.  It's one thing to recklessly throw stuff at
power user level at you, but it's pointless to throw stuff at wizarding
level at anyone without a good grounding.

So basically I'm looking into how and where to best bury the kind of
input you want to be working with while trying not to let you run dry in
the mean time.

-- 
David Kastrup



reply via email to

[Prev in Thread] Current Thread [Next in Thread]