lilypond-user
[Top][All Lists]
Advanced

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

Re: merge-rests engraver doesn't merge dots


From: Thomas Morley
Subject: Re: merge-rests engraver doesn't merge dots
Date: Tue, 8 Nov 2016 23:11:50 +0100

2016-11-08 11:44 GMT+01:00 Urs Liska <address@hidden>:
> Hello all,
>
> On https://github.com/openlilylib/snippets/issues/123 it was reported
> that the engraver merging rests
> (https://github.com/openlilylib/snippets/tree/master/editorial-tools/merge-rests-engraver)
> fails to merge dots of dotted rests. This can be seen here:
> http://lilybin.com/r1jcpm/3
>
> I think this should be quite easy to fix and update, but I don't know
> how to do it in that engraver. So any solution would be welcome. If
> you're an openLilyLib user/contributor you may do this directly as a
> pull request.
>
> Thanks
> Urs


Hi Urs,

how about the code below?
I did some general updating as well.
Just in case I overlooked something, thorough testing is recommended ;)

\version "2.19.49"

#(define merge-rests-engraver
   (lambda (context)
     (let ((rests '())
           (dots '())
           (moment=?
             (lambda (a b) (not (or (ly:moment<? a b) (ly:moment<? b a))))))
       (make-engraver
         ((start-translation-timestep trans)
           ;; reset dots and rests to empty lists for each time-step
           (set! rests '())
           (set! dots '()))
         ((stop-translation-timestep trans)
          (let (;; get a list of the rests 'duration-lengths, 'duration-log does
                ;; not take dots into account
                (durs
                  (map
                    (lambda (g)
                      (ly:duration-length
                        (ly:prob-property
                          (ly:grob-property g 'cause)
                          'duration)))
                    rests)))
           ;; merge rests only when at least two rest with equal duration-length
           ;; are present, by letting them print one upon the other. In this
           ;; case suicide the (possible) dots of all but the first rest.
           (if (and (>= (length rests) 2)
                    (not (any (lambda (x) (not (moment=?(car durs) x))) durs)))
               (begin
                 (for-each
                   (lambda (rest) (ly:grob-set-property! rest 'Y-offset 0))
                  rests)
                (if (pair? dots)
                    (for-each ly:grob-suicide! (cdr dots)))))))
         (acknowledgers
          ;; We go for 'dot-column-interface to catch the dots, because we're
          ;; interested in the dots _in_ the column, not single dots per Voice.
          ((dot-column-interface engraver grob source-engraver)
           (set!
             dots
             (append (ly:grob-array->list (ly:grob-object grob 'dots)) dots)))
          ((rest-interface engraver grob source-engraver)
            ;; we go for grob::name, because 'rest-interface would probably
            ;; catch MMRS as well.
            ;; n.b. grob::name is not present in 2.18.2, use instead
            ;(if (eq? 'Rest (assoc-ref (ly:grob-property grob 'meta) 'name))
            (if (eq? (grob::name grob) 'Rest)
                (set! rests (cons grob rests)))))))))

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Example
%%%%%%%%%%%%%%%%%%%%%%%%%%%

\score
{
  \new Staff
  <<
    \new Voice { \voiceOne r4. \oneVoice r4. \voiceOne r4.   r4 }
    \new Voice { \voiceTwo r4.           s4.           r4 s8 r4. }
  >>
  \layout {
    \context { \Staff \consists #merge-rests-engraver } % merges non-whole rests
  }
}


Cheers,
  Harm



reply via email to

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