Am 02.10.2017 um 01:19 schrieb Davide Liessi:
Is this a bug in the Merge_rests_engraver?
Yes, it seems so. The engraver sets Y-offset instead of staff-position.
Is there a workaround?
Not really, but I fixed the engraver, see attachment (.ily for the
corrected engraver, .ly for a usage example). I’ll try to make a patch
when I’m home in the evening.
#(define-public (Merge_rests_engraver_corrected context)
"Engraver to merge rests in multiple voices on the same staff.
This works by gathering all rests at a time step. If they are all of the same
length and there are at least two they are moved to the correct location as
if there were one voice."
(define (is-single-bar-rest? mmrest)
(eqv? (ly:grob-property mmrest 'measure-count) 1))
(define (mmrest-position mmrest)
"For single measures they should hang from the second line from the top
(staff-position of 2). For longer multimeasure rests they should be centered
on the
middle line (staff-position of 0).
NOTE: For one-line staves full single measure rests should be positioned at
0, but I don't anticipate this engraver's use in that case. No errors are
given in this case."
(if (is-single-bar-rest? mmrest) 2 0))
(define (rest-eqv rest-len-prop)
"Compare rests according the given property"
(define (rest-len rest) (ly:grob-property rest rest-len-prop))
(lambda (rest-a rest-b)
(eqv? (rest-len rest-a) (rest-len rest-b))))
(define (rests-all-unpitched rests)
"Returns true when all rests do not override the staff-position grob
property. When a rest has a position set we do not want to merge rests at
that position."
(every (lambda (rest) (null? (ly:grob-property rest 'staff-position)))
rests))
(define (merge-mmrests rests)
"Move all multimeasure rests to the single voice location."
(if (all-equal rests (rest-eqv 'measure-count))
(merge-rests rests mmrest-position)))
(define (merge-rests rests position-function)
(let ((staff-pos (position-function (car rests))))
(for-each
(lambda (rest) (ly:grob-set-property! rest 'staff-position staff-pos))
rests))
(for-each
(lambda (rest) (ly:grob-set-property! rest 'transparent #t))
(cdr rests)))
(define has-one-or-less (lambda (lst) (or (null? lst) (null? (cdr lst)))))
(define has-at-least-two (lambda (lst) (not (has-one-or-less lst))))
(define (all-equal lst pred)
(or (has-one-or-less lst)
(and (pred (car lst) (cadr lst)) (all-equal (cdr lst) pred))))
(define moment=?
(lambda (a b) (not (or (ly:moment<? a b) (ly:moment<? b a)))))
(let ((curr-mmrests '())
(mmrests '())
(rests '())
(dots '()))
(make-engraver
((start-translation-timestep translator)
(set! rests '())
(set! curr-mmrests '())
(set! dots '()))
(acknowledgers
((dot-column-interface engraver grob source-engraver)
(if (not (ly:context-property context 'suspendRestMerging #f))
(set!
dots
(append (ly:grob-array->list (ly:grob-object grob 'dots))
dots))))
((rest-interface engraver grob source-engraver)
(cond
((ly:context-property context 'suspendRestMerging #f)
#f)
((grob::has-interface grob 'multi-measure-rest-interface)
(set! curr-mmrests (cons grob curr-mmrests)))
(else
(set! rests (cons grob rests))))))
((stop-translation-timestep translator)
(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)))
(if (and
(has-at-least-two rests)
(all-equal durs moment=?)
(rests-all-unpitched rests))
(begin
(merge-rests rests (lambda (r) 0))
;; ly:grob-suicide! works nicely for dots, as opposed to rests.
(if (pair? dots) (for-each ly:grob-suicide! (cdr dots)))))
(if (has-at-least-two curr-mmrests)
(set! mmrests (cons curr-mmrests mmrests)))))
((finalize translator)
(for-each merge-mmrests mmrests)))))
#(ly:register-translator
Merge_rests_engraver_corrected 'Merge_rests_engraver_corrected
'((grobs-created . ())
(events-accepted . ())
(properties-read . (suspendRestMerging))
(properties-written . ())
(description . "\
Engraver to merge rests in multiple voices on the same staff. This works by
gathering all rests at a time step. If they are all of the same length and
there are at least two they are moved to the correct location as if there were
one voice.")))
\version "2.19.65"
\include "mergerestsengraver.ily"
\new Staff \with {
\magnifyStaff #1/2
\consists #Merge_rests_engraver_corrected
} <<
{ \compressFullBarRests R1 r1 R1*14 r2 r4 r }
\\
{ R1 r1 R1*14 r2 r4 r }
>>
\new Staff \with {
\magnifyStaff #1
\consists #Merge_rests_engraver_corrected
} <<
{ \compressFullBarRests R1 r1 R1*14 r2 r4 r }
\\
{ R1 r1 R1*14 r2 r4 r }
>>
\new Staff \with {
\magnifyStaff #2
\consists #Merge_rests_engraver_corrected
} <<
{ \compressFullBarRests R1 r1 R1*14 r2 r4 r }
\\
{ R1 r1 R1*14 r2 r4 r }
>>
_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user