Changing slur behavior

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

Changing slur behavior

Br. Samuel Springuel
I’m trying to copy some music (chant) in which slurs are not indicated by bezier curves, but by changing the spacing between the notes (bringing them much closer together).  Now, while I’ve been able to figure out how to get the visual look, I’m not happy with the interface at the moment, as it requires inserting extra commands into the music so to turn on and off the tight spacing.  Furthermore, if I only have the tight spacing, then each note gets its own word when I start adding lyrics with \lyricsto.  What I’d like to do, therefore, is high-jack the existing slur notation so that the source looks “normal” but then instead of the usual curve, my spacing changes are applied instead (or at least in addition to).  Is there a way to accomplish this?

In the MWE below, \starttight and \endtight are my first pass attempts which apply the spacing, but don’t mark the notes as slurred (resulting in the words being applied wrong and messing up the spacing).  \startslur and \endslur apply both my spacing and the usual slur, allowing the lyrics to be assigned right (and the spacing preserved properly when that happens), but also causing the normal bezier curve to show up.

%%%%% MWE

\version "2.19.84"

% remove stems and auto bar lines
chant = {
    \set Score.timing = ##f
    \omit Stem
}

starttight = { \newSpacingSection \override Score.SpacingSpanner.base-shortest-duration = #(ly:make-moment -2) }
endtight = { \newSpacingSection \revert Score.SpacingSpanner.base-shortest-duration }

startslur = #(define-music-function (note) (ly:music?)
                  (set! (ly:music-property note 'articulations)
                      (cons (make-music 'SlurEvent 'span-direction -1)
                          (ly:music-property note 'articulations)
                      )
                  )
                 (make-music 'SequentialMusic 'elements
                     (list
                          #{ \newSpacingSection \override Score.SpacingSpanner.base-shortest-duration = #(ly:make-moment -2) #}
                          note
                     )
                 )
             )

endslur = #(define-music-function (note) (ly:music?)
                (set! (ly:music-property note 'articulations)
                      (cons (make-music 'SlurEvent 'span-direction 1)
                          (ly:music-property note 'articulations)
                      )
                  )
                 (make-music 'SequentialMusic 'elements
                     (list
                          #{ \newSpacingSection \revert Score.SpacingSpanner.base-shortest-duration #}
                          note
                     )
                 )
             )

music = { \chant
  a' g'
  a'( g')
  \starttight a' \endtight g'
  \startslur a' \endslur g'
}

words = \lyricmode { Some words to go under my notes }

\displayMusic \music

\new Staff <<
     \new Voice = "mel" { \music }
     \new Lyrics \lyricsto "mel" { \words }
>>



✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝
Fr. Samuel, OSB
(R. Padraic Springuel)
St. Anselm’s Abbey
4501 South Dakota Ave, NE
Washington, DC, 20017
202-269-2300
(c) 202-853-7036

PAX ☧ ΧΡΙΣΤΟΣ


Reply | Threaded
Open this post in threaded view
|

Re: Changing slur behavior

Kevin Barry
Hi Padraic,

I think the right way to do what you are trying is to write an
engraver that listens for slur events and alters the spacing of the
music. (I would write one if I could, but I'm not at that level yet.)

Until you have one I think you can solve the problem with your own
hack, where unwanted slurs are appearing, with \omit Slur. Does that
work for you?

Kevin

Reply | Threaded
Open this post in threaded view
|

Re: Changing slur behavior

Aaron Hill
On 2020-03-26 2:24 am, Kevin Barry wrote:
> I think the right way to do what you are trying is to write an
> engraver that listens for slur events and alters the spacing of the
> music. (I would write one if I could, but I'm not at that level yet.)

Firstly, know that slurs are not the only way to define melismata.  You
can instruct LilyPond to have a single lyric syllable span multiple
notes using \melisma and \melismaEnd:

%%%%
\version "2.20.0"

\fixed c' { b4( g a2) | b4\melisma g a2\melismaEnd }
\addlyrics { one two }
%%%%

This does not solve the spacing aspect of the original post, but it
shows how you can avoid messing about with slurs.

Assuming you really want to use slurs to adjust spacing, here might be
one way to do it:

%%%%
\version "2.20.0"

Slur_spacing_engraver =
#(lambda (context)
   (let ((slur-event-dir #f))
     (define (change-spacing dir)
       (ly:broadcast
         (ly:context-event-source context)
         (ly:make-stream-event
           (ly:make-event-class 'spacing-section-event)
           '(())))
       (let ((score-context (ly:context-find context 'Score)))
         (for-each
           (lambda (args)
             (apply ly:context-pushpop-property
               score-context 'SpacingSpanner
               (if (< 0 dir) (drop-right args 1) args)))
           `((base-shortest-duration ,(ly:make-moment 8))
             (shortest-duration-space 1)
             (spacing-increment 1)))))
     (make-engraver
       ((start-translation-timestep engraver)
         (set! slur-event-dir #f))
       (listeners
         ((slur-event engraver event)
           (let ((dir (ly:event-property event 'span-direction #f)))
             (set! slur-event-dir dir))))
       ((process-music engraver)
         (if (ly:dir? slur-event-dir)
           (change-spacing slur-event-dir))))))

<< \context Voice = "melody" \with {
      \consists "Melody_engraver"
      \override Stem.neutral-direction = #'()
      \consists \Slur_spacing_engraver
      \omit Slur
    } \fixed c' {
      | b4 f8 g16 c' a2
      | b4( f8 g16 c' a2)
      | b4 f8 g16 c' a2
    }
    \context Lyrics \lyricsto "melody" {
      | "normal spacing" _ _ _ _
      | "tightly-spaced"
      | "normal spacing" _ _ _ _
    } >>
%%%%

The engraver listens for slur-events, injecting a spacing-section-event
and adjusting some context properties as needed.  The logic is very
simple, and there are no safety checks.  Be warned this likely could
fail with more complicated music.


-- Aaron Hill

slur-spacing.cropped.png (23K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Changing slur behavior

Br. Samuel Springuel
> On 26 Mar, 2020, at 9:54 AM, Aaron Hill <[hidden email]> wrote:
>
> On 2020-03-26 2:24 am, Kevin Barry wrote:
>> I think the right way to do what you are trying is to write an
>> engraver that listens for slur events and alters the spacing of the
>> music. (I would write one if I could, but I'm not at that level yet.)
>
> Firstly, know that slurs are not the only way to define melismata.  You can instruct LilyPond to have a single lyric syllable span multiple notes using \melisma and \melismaEnd:
>
> %%%%
> \version "2.20.0"
>
> \fixed c' { b4( g a2) | b4\melisma g a2\melismaEnd }
> \addlyrics { one two }
> %%%%
>
> This does not solve the spacing aspect of the original post, but it shows how you can avoid messing about with slurs.

I’ll have to play with this to see how I like it.  The reason I initially wanted to mess with slurs was on the off chance that I later wanted to take the chant and turn it into a fully modern

> Assuming you really want to use slurs to adjust spacing, here might be one way to do it:
>
> …snip...
>
> The engraver listens for slur-events, injecting a spacing-section-event and adjusting some context properties as needed.  The logic is very simple, and there are no safety checks.  Be warned this likely could fail with more complicated music.
>
>
> -- Aaron Hill

Thanks for this Aaron.  After some playing I’ve adapted this to the way I usually encode chant (where all notes are basically quarters):

\version "2.19.84"

Slur_spacing_engraver =
#(lambda (context)
 (let ((slur-event-dir #f))
   (define (change-spacing dir)
     (ly:broadcast
       (ly:context-event-source context)
       (ly:make-stream-event
         (ly:make-event-class 'spacing-section-event)
         '(())))
     (let ((score-context (ly:context-find context 'Score)))
       (for-each
         (lambda (args)
           (apply ly:context-pushpop-property
             score-context 'SpacingSpanner
             (if (< 0 dir) (drop-right args 1) args)))
         `((base-shortest-duration ,(ly:make-moment -2))
           (shortest-duration-space 2)
           (spacing-increment 0)))))
   (make-engraver
     ((start-translation-timestep engraver)
       (set! slur-event-dir #f))
     (listeners
       ((slur-event engraver event)
         (let ((dir (ly:event-property event 'span-direction #f)))
           (set! slur-event-dir dir))))
     ((process-music engraver)
       (if (ly:dir? slur-event-dir)
         (change-spacing slur-event-dir))))))


\layout {
    \context {
        \Score
        \override SpacingSpanner.shortest-duration-space = 3
        timing = ##f
    }
    \context {
        \Staff
        \consists \Slur_spacing_engraver
        \remove Time_signature_engraver
        \omit Stem
        \omit Slur
    }
}


music = {
  a' g'
  a'( g')
  a'( ges')
  a'( g')
  a' g'
}

words = \lyricmode { Some words to go un -- der notes }

\new Staff  
<<
     \new Voice = "mel" { \music }
     \new Lyrics \lyricsto "mel" { \words }
>>

I’ve found a problem: accidentals inside of slurs end up colliding with preceding notes.  Is it possible to modify the Slur_spacing_engraver so that it doesn’t ignore accidentals and takes them into account when deciding the spacing between the notes?

✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝✝
Fr. Samuel, OSB
(R. Padraic Springuel)
St. Anselm’s Abbey
4501 South Dakota Ave, NE
Washington, DC, 20017
202-269-2300
(c) 202-853-7036

PAX ☧ ΧΡΙΣΤΟΣ