lilypond-user
[Top][All Lists]
Advanced

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

Re: Notes or chords sustained with a pedal


From: Aaron Hill
Subject: Re: Notes or chords sustained with a pedal
Date: Sat, 21 Dec 2019 22:05:54 -0800
User-agent: Roundcube Webmail/1.3.8

On 2019-12-21 9:15 am, Kieren MacMillan wrote:
Here is my attempt at hacking the BarLine stencil to add overlapping ties:

This is so cool. Is there an easy way to make the function determine
the "current" set of LVs (i.e., the LV configuration from the most
recent LV-ed chord) and automagically apply it to the subsequent
barlines (e.g., with a \temporary, to be \reverted manually)?

Things get trickier if you need to keep track of past events. But here is another approach that uses a Scheme engraver to do the bulk of the work:

%%%%
\version "2.19.83"

#(begin
  (set-object-property! 'activeLaissezVibrer 'translation-type? list?)
  (set-object-property! 'activeLaissezVibrer 'translation-doc
    "A list of LaissezVibrerTies which should span BarLines.")
  (set! all-translation-properties
    (cons 'activeLaissezVibrer all-translation-properties)))

#(define (SpanLaissezVibrer_engraver context)
  (define (spanLaissezVibrer? grob)
    (let* ((cause (ly:grob-property grob 'cause))
           (class (ly:event-property cause 'class '()))
           (span? (ly:event-property cause 'span #f)))
      (and (memq 'laissez-vibrer-event class) span?)))
  (define (past-events tie)
    (ly:moment<? (car tie) (ly:context-now context)))
  (define (rescale-control-points cp xex)
    (let* ((xmin (apply min (map car cp)))
           (xmax (apply max (map car cp)))
           (xmid (/ (+ xmin xmax) 2))
           (xhw (/ (- xmax xmin) 2)))
      (map (lambda (pt) pt
        (let ((t (/ (- (car pt) xmid) xhw)))
          (cons (interval-index xex t) (cdr pt)))) cp)))
  (define ((stencil-proc ties) grob)
    (let* ((bd (ly:item-break-dir grob))
           (orig (ly:bar-line::print grob))
           (xex (ly:stencil-extent orig X))
           (x (interval-index xex 0))
           (w (+ 0.8 (/ (interval-length xex) 2)))
           (tie-xex (cons (- x w) (+ x w))))
      (ly:stencil-add (ly:bar-line::print grob)
        (apply ly:stencil-add
          (map (lambda (tie)
            (let* ((cp-orig (ly:grob-property tie 'control-points))
                   (cp-temp (rescale-control-points cp-orig tie-xex))
                   (sten '()) (xex '()) (yex '()))
              (ly:grob-set-property! tie 'control-points cp-temp)
              (set! sten (ly:tie::print tie))
              (ly:grob-set-property! tie 'control-points cp-orig)
              (set! xex (ly:stencil-extent sten X))
              (set! yex (ly:stencil-extent sten Y))
              (ly:make-stencil (ly:stencil-expr sten)
                (cons (car xex) (if (> 0 bd) x (cdr xex))) yex)))
            (map cdr ties))))))
  (make-engraver
    (acknowledgers
      ((bar-line-interface engraver grob source-engraver)
        (let ((ties (ly:context-property context
                      'activeLaissezVibrer '())))
          (set! ties (filter past-events ties))
          (if (not (null? ties)) (ly:grob-set-property!
            grob 'stencil (stencil-proc ties)))))
      ((semi-tie-interface engraver grob source-engraver)
        (if (spanLaissezVibrer? grob)
          (ly:context-set-property! context 'activeLaissezVibrer
            (cons (cons (ly:context-now context) grob)
              (ly:context-property context
                'activeLaissezVibrer '()))))))))

spanLaissezVibrer = #(make-music 'LaissezVibrerEvent 'span #t)

stopSpanLaissezVibrers = \applyContext #(lambda (context)
  (ly:context-set-property! (ly:context-find context 'Staff)
    'activeLaissezVibrer '()))

Upper = {
  | r2 r8 g'8 b' c''
  | <g' b' c''>1\spanLaissezVibrer
  | R1 \stopSpanLaissezVibrers \bar "||"
  | r8 a' g' e' c'2 \bar "|."
}
Lower = {
  | <a, d>1\spanLaissezVibrer
  | R1
  | g8 b <g b>2.^\spanLaissezVibrer
  | R1 \stopSpanLaissezVibrers
}
\score {
  \new PianoStaff <<
    \new Staff { \clef "treble" \Upper }
    \new Staff { \clef "bass" \Lower }
  >>
  \layout { \context { \Staff
    \consists \SpanLaissezVibrer_engraver } }
}
%%%%

This is quite different from my previous manual approach, but this has advantages of exactly matching the vertical positioning of LV ties without needing manual intervention.


-- Aaron Hill

Attachment: lv-bar-auto.cropped.png
Description: PNG image


reply via email to

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