Macro with

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Macro with

David Menéndez Hurtado
I am transcribing a piece that is filled with the rhythmic motif "8. 16 8" at different pitches. Being a LaTeX user, I want to write a macro like \myrithm{c a g}. I found the documentation for Scheme functions, and how to edit whole music sections, but nothing on how to insert a fixed number of pitches. As I understand it, ly:music is an arbitrary music expression, so I cannot restrict it to just three pitches.

This is what I managed to put together, but doesn't quite work. Anyone can suggest how to fix it?


/David.

\version "2.19.83"
\language "english"

myrithm =
#(define-music-function
 (parser location first second third)
  (first second third)
  (ly:pitch? ly:pitch? ly:pitch?)
  #{      
    #first 8. #second 16 #third 8
  #})

\score {
  <<
    %\new Staff {\relative do' {\myrithm{c, d, e}}}
    \new Staff  {\time 6/8 \relative c' {c4. c \myrithm a' b e  \myrithm {e d c} c c c }} %Two different ways of calling it, neither works.
  >>
  \layout {
  }
}

Reply | Threaded
Open this post in threaded view
|

Re: Macro with

Malte Meyn-3


Am 14.11.19 um 10:02 schrieb David Menéndez Hurtado:
> I am transcribing a piece that is filled with the rhythmic motif "8. 16
> 8" at different pitches. Being a LaTeX user, I want to write a macro
> like \myrithm{c a g}.

Maybe http://lsr.di.unimi.it/LSR/Item?id=465 or
http://lsr.di.unimi.it/LSR/Item?id=654 is the right thing for you?

Reply | Threaded
Open this post in threaded view
|

Re: Macro with

David Menéndez Hurtado


On Thu, 14 Nov 2019 at 10:05, Malte Meyn <[hidden email]> wrote:
Am 14.11.19 um 10:02 schrieb David Menéndez Hurtado:
> I am transcribing a piece that is filled with the rhythmic motif "8. 16
> 8" at different pitches. Being a LaTeX user, I want to write a macro
> like \myrithm{c a g}.

Maybe http://lsr.di.unimi.it/LSR/Item?id=465 or

That seems to only allow the same note in the pattern.
 
http://lsr.di.unimi.it/LSR/Item?id=654 is the right thing for you?

That looks more flexible, I think it would solve my immediate problem, thank you very much.

The downside is that it looks more complicated, so I would also like to learn to write the function myself. I think the docs can use a few more examples, and I am happy to contribute them.


/David.

P.S.: sorry for the unfinished subject line.
Reply | Threaded
Open this post in threaded view
|

Re: Macro with

Aaron Hill
In reply to this post by David Menéndez Hurtado
On 2019-11-14 1:02 am, David Menéndez Hurtado wrote:

> This is what I managed to put together, but doesn't quite work. Anyone
> can
> suggest how to fix it?
>
> \version "2.19.83"
> \language "english"
>
> myrithm =
> #(define-music-function
>  (parser location first second third)
>   (first second third)
>   (ly:pitch? ly:pitch? ly:pitch?)
>   #{
>     #first 8. #second 16 #third 8
>   #})
>
> \score {
>   <<
>     %\new Staff {\relative do' {\myrithm{c, d, e}}}
>     \new Staff  {\time 6/8 \relative c' {c4. c \myrithm a' b e  
> \myrithm {e
> d c} c c c }} %Two different ways of calling it, neither works.
>   >>
>   \layout {
>   }
> }

Ooh, you are *so* close!

Firstly, you have a spurious expression of (first second third) before
the type predicate list.  This expression is what LilyPond assumes *is*
your type predicate list, so your (ly:pitch? ly:pitch? ly:pitch?) is
being ignored.

You might wonder why are you not getting errors about unbound variables
then.  However, the procedures first, second, and third *are* defined
already by SRFI-1 as short-hand for car, cadr, and caddr, respectively.

Secondly, there's a quirk in variable substitution syntax.  You need to
use the $var form, so the parser will see the ly:pitch? and ly:duration?
tokens as indicating a single note.

Here's the working version:

%%%%
\version "2.19.83"

myRhythm = #(define-music-function
   (first second third)
   (ly:pitch? ly:pitch? ly:pitch?)
   #{ $first 8. $second 16 $third 8 #})

\fixed c' {
   \time 6/8
   \myRhythm g d g
   \myRhythm e d g
   \myRhythm g a b
   \myRhythm c' a b
}
%%%%

Note you no longer need to explicitly specify the parser and location
arguments for a music function.  You can use the global procedures
*parser* and *location* to get those values should you need them.

Also note that I went ahead and kept the parameter names as you had
them.  In this situation, it is okay as we have no need to use the
existing definitions of first, second, and third.  But in the future,
choose parameter names carefully to avoid hiding something you do end up
needing.


-- Aaron Hill

Reply | Threaded
Open this post in threaded view
|

Re: Macro with

David Menéndez Hurtado


On Thu, 14 Nov 2019 at 12:47, Aaron Hill <[hidden email]> wrote:
Secondly, there's a quirk in variable substitution syntax.  You need to
use the $var form, so the parser will see the ly:pitch? and ly:duration?
tokens as indicating a single note.

Ah, right. I understand now the manual means with "normal LilyPond input, using $ (in places where only Lilypond constructs are allowed) or # (to use it as a Scheme value or music function argument or music inside of music lists) to reference arguments (eg. ‘#arg1’)." So, every time the input type is ly:something, it should be with $, right?

Thank you so much, now my source is almost readable, and so much quicker!
Reply | Threaded
Open this post in threaded view
|

Re: Macro with

Urs Liska-3
In reply to this post by David Menéndez Hurtado


Am 14.11.19 um 10:26 schrieb David Menéndez Hurtado:


On Thu, 14 Nov 2019 at 10:05, Malte Meyn <[hidden email]> wrote:
Am 14.11.19 um 10:02 schrieb David Menéndez Hurtado:
> I am transcribing a piece that is filled with the rhythmic motif "8. 16
> 8" at different pitches. Being a LaTeX user, I want to write a macro
> like \myrithm{c a g}.

Maybe http://lsr.di.unimi.it/LSR/Item?id=465 or

That seems to only allow the same note in the pattern.
 
http://lsr.di.unimi.it/LSR/Item?id=654 is the right thing for you?

That looks more flexible, I think it would solve my immediate problem, thank you very much.

The downside is that it looks more complicated, so I would also like to learn to write the function myself. I think the docs can use a few more examples, and I am happy to contribute them.

As you noted, Aaron gave you a very detailed yet concise explanation. If you want to learn more about Scheme in LilyPond you can - as a complement - have a look at my attempt to give slow-paced explanations. It is really far from being complete, but I think what *is* there may be helpful for a better understanding: https://scheme-book.ursliska.de

HTH
Urs




/David.

P.S.: sorry for the unfinished subject line.
Reply | Threaded
Open this post in threaded view
|

Applying a rhythmic pattern (was Re: Macro with)

Aaron Hill
In reply to this post by Aaron Hill
I was inspired by David's post, as I have also encountered patterns in
durations that I wish were less redundant to input.  The snippet Malte
linked to is rather complex, although I suspect it is significantly more
air-tight at handling edge cases.

Here is a simpler (i.e. "one-pager") music function for applying a
specified rhythmic pattern to some music:

%%%%
\version "2.19.83"

applyRhythm = #(define-music-function
   (rhythm notes) (ly:music? ly:music?)
   "Overwrites the durations of a simple music expression with
    those from another, repeating the rhythmic pattern as needed."
   (define (extract-durations music)
     (map (lambda (elem) (ly:music-property elem 'duration))
       (filter (music-type-predicate '(rhythmic-event))
         (ly:music-property music 'elements))))
   (define (apply-duration element duration)
     (let ((subelements (ly:music-property element 'elements)))
       (if (null? subelements)
         (set! (ly:music-property element 'duration) duration))
         (map (lambda (subelement)
             (set! (ly:music-property subelement 'duration) duration))
           subelements)))
   (define (apply-durations durations music)
     (for-each apply-duration
       (filter (music-type-predicate '(rhythmic-event event-chord))
         (ly:music-property music 'elements))
       (apply circular-list durations))
     music)
   #{ #(apply-durations (extract-durations rhythm) notes) #})

\fixed c' {
   \time 6/8
   \applyRhythm { 8. 16 8 } {
     | g\mp a <g b> a-\accent fis g~
     | <g b>\< c' <b d'>
   }
   <fis d'>4\mf r8
   \applyRhythm { 8. 16 8 4. } {
     | <e c'>( b <fis a> <d b^~>
     | <e b>) r <c fis>\f <b, g>\accent
   }
}
%%%%


-- Aaron Hill

rhythmic-pattern.cropped.png (24K) Download Attachment
dak
Reply | Threaded
Open this post in threaded view
|

Re: Macro with

dak
In reply to this post by David Menéndez Hurtado
David Menéndez Hurtado <[hidden email]> writes:

> On Thu, 14 Nov 2019 at 12:47, Aaron Hill <[hidden email]> wrote:
>
>> Secondly, there's a quirk in variable substitution syntax.  You need to
>> use the $var form, so the parser will see the ly:pitch? and ly:duration?
>> tokens as indicating a single note.
>>
>
> Ah, right. I understand now the manual means with "normal LilyPond input,
> using $ (in places where only Lilypond constructs are allowed) or # (to use
> it as a Scheme value or music function argument or music inside of music
> lists) to reference arguments (eg. ‘#arg1’)." So, every time the input type
> is ly:something, it should be with $, right?

Music is ly:music? .  # passes the content verbatim and requires a
particular type to work since it is evaluated _after_ being fitted into
the syntax parsing.  $ creates a copy of some types (such as music) and
can be treated differently in syntax according to its type but since
some syntax constructs require lookahead (and that in turn requires
knowing the type of the token), the evaluation can happen surprisingly
early.

In general, # works with fewer surprises unless it doesn't work at all.

> Thank you so much, now my source is almost readable, and so much
> quicker!

--
David Kastrup

Reply | Threaded
Open this post in threaded view
|

Re: Re: Macro with pitches as parameters

Mats Bengtsson-4
In reply to this post by Aaron Hill

On 2019-11-14 12:46, Aaron Hill wrote:
> On 2019-11-14 1:02 am, David Menéndez Hurtado wrote:
 >> I am transcribing a piece that is filled with the rhythmic motif "8.
16 8" at different pitches. Being a LaTeX user, I want to write a macro
like \myrithm{c a g}. I found the documentation for Scheme functions,
and how to edit whole music sections, but nothing on how to insert a
fixed number of pitches. As I understand it, ly:music is an arbitrary
music expression, so I cannot restrict it to just three pitches.

> ...
> Ooh, you are *so* close!
>
> ...
> Here's the working version:
>
> %%%%
> \version "2.19.83"
>
> myRhythm = #(define-music-function
>   (first second third)
>   (ly:pitch? ly:pitch? ly:pitch?)
>   #{ $first 8. $second 16 $third 8 #})
>
> \fixed c' {
>   \time 6/8
>   \myRhythm g d g
>   \myRhythm e d g
>   \myRhythm g a b
>   \myRhythm c' a b
> }
> %%%%

By coincidence, I encountered the same problem and came up with the same
solution, the other week. I'm surprised that we don't have any such
example in the manual since it really is very useful and at the same
time illustrates the power of combining define-music-function with
embedded LilyPond syntax. In LSR you can actually find a few more
examples that seem relevant, like
http://lsr.di.unimi.it/LSR/Item?id=346, but as far as I can see, the
same could equally well be implemented like your example above without
requiring any Scheme competence. The only LSR example that resembles the
one above is http://lsr.di.unimi.it/LSR/Item?id=302, but it doesn't
illustrate the possibility to include multiple pitches in the pattern.

In my own example, the same pitch is repeated multiple times in the
rhythmic/melodic pattern, like

\version "2.19.82"

myPattern = #(define-music-function (p1 p2 p3 p4)
     (ly:pitch? ly:pitch? ly:pitch? ly:pitch?)
     #{ $p1 4 ( $p2 8 ) \acciaccatura $p2 $p3 $p3 16 $p4 $p3 8 #})

which can be successfully used like

\fixed c' {
   \time 6/8
   \myPattern a c' b ais |
   \myPattern a f' e' dis' |
}

However, it doesn't work in \relative mode, since the octave change is
applied every time the same pitch is repeated. Since I'm used to writing
in \relative mode and since \relative mode is very well suited to this
violin music that spans several octaves but often moves in small
intervals, I would have liked to write the above example using

\relative c'' {
   \time 6/8
   \myPattern a c b ais |
   \myPattern a f' e dis |
}

but since the second pitch of the example is repeated in the pattern,
the second occurrence of f' raises the octave again, which isn't what is
wanted. Searching the mailing list archives and the regression test
examples for 2.19, I finally came up with

\version "2.19.82"

myPattern = #(define-music-function (p1 p2 p3 p4)
           (ly:pitch? ly:pitch? ly:pitch? ly:pitch?)
           (make-relative (p1 p2 p3 p4) (make-event-chord (list p1 p2 p3
p4))
     #{ $p1 4 ( $p2 8 ) \acciaccatura $p2 $p3 $p3 16 $p4 $p3 8 #}))

\relative c'' {
   \time 6/8
   \myPattern a c b ais |
   \myPattern a f' e dis |
}

Adding occasional dynamic indications or articulations could be done
using the standard trick of attaching them to an empty chord at the
suitable location, like

\relative c'' {
   \time 6/8
   <>\f \myPattern_rel  a c b ais |
   <<{\myPattern_rel a f' e dis } {s4. <>^\trill }>>
}

(not extremely convenient but still doable.)

My main remaining problem is how to add a reminder accidental or
cautionary accidental on a pitch. Even if it was possible, you might
only want it on the first occurrence of the note so it's more like an
unsolvable problem. Probably the famous edition engraver can do the job,
but I've never taken the effort to learn how to use that beast, so for
the places where I urgently need a reminder accidental in the middle of
the pattern, I will not use the macro.

     /Mats