lilypond-user
[Top][All Lists]
Advanced

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

Merge Rests Engraver


From: Jay Anderson
Subject: Merge Rests Engraver
Date: Tue, 21 Feb 2012 22:38:06 -0700

I want to open up the conversation about merging rests again (see bug
1228 http://code.google.com/p/lilypond/issues/detail?id=1228). Below
is a first go at a scheme based engraver. It doesn't kill any grobs so
the chance of segfaults is lower. Do overlapping grobs have any other
unintended consequences? I haven't spent much time testing it yet
besides the attached examples and a couple other scores. It seems to
work well enough. Let me know if you see any ways it can be
simplified.

-----Jay

\version "2.15.30"

#(define (grob-name grob)
  (if (ly:grob? grob)
    (assoc-ref (ly:grob-property grob 'meta) 'name)
    #f))

#(define (moment=? a b)
   (and
     (eq? (ly:moment-main-numerator a) (ly:moment-main-numerator b))
     (eq? (ly:moment-main-denominator a) (ly:moment-main-denominator b))))

#(define (mm-rest-length rest)
   (ly:prob-property (ly:grob-property rest 'cause) 'length))

#(define merge-rests-engraver
   (lambda (context)
     (let ((calc-y-offset (lambda (rest)
            (if
              (and
                (eq? (grob-name rest) 'MultiMeasureRest)
                (moment=? (ly:context-property context 'measureLength)
(mm-rest-length rest)))
              1 0)))
           (same-length (lambda (rest-a rest-b)
             (let ((type-a (grob-name rest-a))
                   (type-b (grob-name rest-b)))
               (or
                 (and
                   (eq? type-a 'MultiMeasureRest)
                   (eq? type-b 'MultiMeasureRest)
                   (moment=? (mm-rest-length rest-a) (mm-rest-length rest-b)))
                 (and
                   (eq? type-a 'Rest)
                   (eq? type-b 'Rest)
                   (eq? (ly:grob-property rest-a 'duration-log)
(ly:grob-property rest-b 'duration-log)))))))
           (rest-a #f)
           (rest-b #f))
     `((start-translation-timestep . ,(lambda (trans)
                                        (set! rest-a #f)
                                        (set! rest-b #f)))
       (stop-translation-timestep . ,(lambda (trans)
                                       (if (and rest-a rest-b
(same-length rest-a rest-b))
                                         (let ((offset (calc-y-offset rest-a)))
                                           (begin
                                             (ly:grob-set-property!
rest-a 'Y-offset offset)
                                             (ly:grob-set-property!
rest-b 'Y-offset offset))))))
       (acknowledgers
         (rest-interface . ,(lambda (engraver grob source-engraver)
                              (if rest-a
                                (set! rest-b grob)
                                (set! rest-a grob)))))))))

\score
{
  \new Staff
  <<
    \new Voice \relative c'
    {
      \voiceOne
      e4 r e r |
      R1 |
      r2 e |
    }
    \new Voice \relative c'
    {
      \voiceTwo
      r4 c r r |
      R1 |
      r2 r4 c |
    }
  >>

  \layout { \context { \Staff \consists #merge-rests-engraver } }
}

\score
{
  \new Staff \relative c'
  <<
    {
      \compressFullBarRests
      c4 r r2 |
      R1 |
      r2 r4 r8 r16 r32 r |
      R1*3 |
    }
    \\
    {
      c4 r r r |
      R1 |
      r2 r4 r8 r16 r32 r |
      R1*3 |
    }
  >>
  \layout { \context { \Staff \consists #merge-rests-engraver } }
}



reply via email to

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