[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