Deutsches Lilypond Forum (Archiv)
Allgemein => Fragen zu Funktionen => Thema gestartet von: merula am Sonntag, 1. Januar 2012, 11:59
-
Hallo,
ich tippe oft einen SATB Chorsatz mit zwei Stimmen in einem Notensystem. Wenn dort beide Stimmen gleichzeitig Pause haben, setzt Lilypond für jede Stimme ein Pausenzeichen. In etwa so:
\version "2.14.2"
one = \relative c' { e f r g }
two = \relative c '{ c d r e }
score {
\new ChoirStaff <<
\new Staff <<
\new Voice { \voiceOne \one }
\new Voice { \voiceTwo \two }
>>
>>
}
Ich möchte an der Stelle aber nur ein Pausenzeichen haben. Das bekommen ich hin, indem ich an der Stelle den zweistimmigen Kontext ausschalte, dann in der ersten Stimme die Pause in der zweiten Stimme eine stille Pause einsetze und danach den zweistimmigen Kontext wieder einschalten. So hier:
\version "2.14.2"
one = \relative c' { e f \oneVoice r \voiceOne g }
two = \relative c '{ c d \oneVoice s \voiceTwo e }
score {
\new ChoirStaff <<
\new Staff <<
\new Voice { \voiceOne \one }
\new Voice { \voiceTwo \two }
>>
>>
}
Das ist aber immer ganz schön viel Tipparbeit für ein einzelnes Zeichen und außerdem ist die Gefahr groß, dass man irgendwas davon vergisst. Schön wäre, wenn Lilypond selbständig erkennen würde, dass an der Stelle ein Pausenzeichen genügt. Gibt es dafür nicht evtl. eine elegante Option, die ich ein- bzw. ausschalten kann?
Grüße
Lars
-
Hallo Lars,
Du kennst vielleicht LSR-Snippet 336 (http://lsr.dsi.unimi.it/LSR/Item?id=336).
Es wirkt aber nicht bei MultiMeasureRest. Die verschiedenen Versionen bringen auch noch jeweils eigene Probleme mit sich.
Diskussion hierzu:
http://code.google.com/p/lilypond/issues/detail?id=1228 (http://code.google.com/p/lilypond/issues/detail?id=1228)
http://codereview.appspot.com/4005046/ (http://codereview.appspot.com/4005046/)
http://lists.gnu.org/archive/html/bug-lilypond/2011-03/msg00291.html (http://lists.gnu.org/archive/html/bug-lilypond/2011-03/msg00291.html)
zuletzt:
http://lists.gnu.org/archive/html/lilypond-user/2011-11/msg00275.html (http://lists.gnu.org/archive/html/lilypond-user/2011-11/msg00275.html)
dort habe ich schon folgende Version gepostet:
\version "2.14.2"
%\version "2.15.20"
#(define (rest-score r)
(let ((score 0)
(yoff (ly:grob-property-data r 'Y-offset))
(sp (ly:grob-property-data r 'staff-position)))
(if (number? yoff)
(set! score (+ score 2))
(if (eq? yoff 'calculation-in-progress)
(set! score (- score 3))))
(and (number? sp)
(<= 0 2 sp)
(set! score (+ score 2))
(set! score (- score (abs (- 1 sp)))))
score))
#(define (merge-rests-on-positioning grob)
(let* ((can-merge #f)
(elts (ly:grob-object grob 'elements))
(num-elts (and (ly:grob-array? elts)
(ly:grob-array-length elts)))
(two-voice? (= num-elts 2)))
(if two-voice?
(let* ((v1-grob (ly:grob-array-ref elts 0))
(v2-grob (ly:grob-array-ref elts 1))
(v1-rest (ly:grob-object v1-grob 'rest))
(v2-rest (ly:grob-object v2-grob 'rest)))
(and
(ly:grob? v1-rest)
(ly:grob? v2-rest)
(let* ((v1-duration-log (ly:grob-property v1-rest 'duration-log))
(v2-duration-log (ly:grob-property v2-rest 'duration-log))
(v1-dot (ly:grob-object v1-rest 'dot))
(v2-dot (ly:grob-object v2-rest 'dot))
(v1-dot-count (and (ly:grob? v1-dot)
(ly:grob-property v1-dot 'dot-count -1)))
(v2-dot-count (and (ly:grob? v2-dot)
(ly:grob-property v2-dot 'dot-count -1))))
(set! can-merge
(and
(number? v1-duration-log)
(number? v2-duration-log)
(= v1-duration-log v2-duration-log)
(eq? v1-dot-count v2-dot-count)))
(if can-merge
;; keep the rest that looks best:
(let* ((keep-v1? (>= (rest-score v1-rest)
(rest-score v2-rest)))
(rest-to-keep (if keep-v1? v1-rest v2-rest))
(dot-to-kill (if keep-v1? v2-dot v1-dot)))
;; uncomment if you're curious of which rest was chosen:
;;(ly:grob-set-property! v1-rest 'color green)
;;(ly:grob-set-property! v2-rest 'color blue)
(ly:grob-suicide! (if keep-v1? v2-rest v1-rest))
(if (ly:grob? dot-to-kill)
(ly:grob-suicide! dot-to-kill))
(ly:grob-set-property! rest-to-keep 'direction 0)
(ly:rest::y-offset-callback rest-to-keep)))))))
(if can-merge
#t
(ly:rest-collision::calc-positioning-done grob))))
#(define merge-multi-measure-rest-on-Y-offset
;; Call this to get the 'Y-offset of a MultiMeasureRest.
;; It keeps track of other MultiMeasureRests in the same NonMusicalPaperColumn
;; and StaffSymbol. If two are found, make transparent one and return 1 for Y-offset of
;; the other one.
(let ((table (make-weak-key-hash-table)))
(lambda (grob)
(let* ((ssymb (ly:grob-object grob 'staff-symbol))
(nmcol (ly:grob-parent grob X))
(ssymb-hash (begin
(if (not (hash-ref table ssymb))
(hash-set! table ssymb (make-hash-table 1)))
(hash-ref table ssymb)))
(othergrob (hash-ref ssymb-hash nmcol))
(measure-count (if (ly:grob? grob)
(ly:grob-property grob 'measure-count)
0)))
(if (ly:grob? othergrob)
(begin
;; Make merged rest transparent instead of suiciding
;; in case it supports text/counter
(set! (ly:grob-property othergrob 'transparent) #t)
(hash-remove! ssymb-hash nmcol)
(if (<= (string->number (cadr (string-split (lilypond-version) #\.))) 14)
0
(if (< 1 measure-count)
0
1))
)
(begin
;; Just save this grob and return the default value
(hash-set! ssymb-hash nmcol grob)
(ly:staff-symbol-referencer::callback grob)))
))))
mergeRestsOn = {
\override Staff.RestCollision #'positioning-done = #merge-rests-on-positioning
\override Staff.MultiMeasureRest #'Y-offset = #merge-multi-measure-rest-on-Y-offset
}
mergeRestsOff = {
\revert Staff.RestCollision #'positioning-done
\revert Staff.MultiMeasureRest #'Y-offset
}
mergeRests = \with {
\override RestCollision #'positioning-done = #merge-rests-on-positioning
\override MultiMeasureRest #'Y-offset = #merge-multi-measure-rest-on-Y-offset
}
mmrtr = \override Voice.MultiMeasureRestNumber #'transparent = ##t
%------ Test
\score {
\new Score <<
\new Staff \with {
} <<
s4-\markup{ "LilyPond default, Rests in both voices." }
\relative c'' { c4 d e r | r2 e4 g | R1 } \\
\relative c'' { c4 b a r | r a g2 | R1 }
>>
\new Staff \with { \mergeRests }
<<
s4-\markup{ "Merge Rests and MultiMeasureRests in both voices." }
\relative c'' { c4 d e r | r2 e4 g | R1 \mmrtr\compressFullBarRests R1*9 } \\
\relative c'' { c4 b a r | r a g2 | R1 \compressFullBarRests R1*9 }
>>
>>
\layout {}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%
% Dein Beispiel
%%%%%%%%%%%%%%%%%%%%%%%%%%
one = \relative c' { e4 f r g }
two = \relative c '{ c d r e }
\score {
\new ChoirStaff <<
\new Staff \with { \mergeRests }
<<
\new Voice { \voiceOne \one }
\new Voice { \voiceTwo \two }
>>
>>
}
Gleichzeitige Pausen (MultiMeasureRests) werden auf eine reduziert.
Wenn an der MultiMeasureRest ein Text angehängt wird (MultiMeasureRestNumber, Text, Fermata etc) so muß man selbst noch entscheiden, welchen Text man haben möchte, den anderen macht man dann unsichtbar. Neil Puttock hatte das so vorgeschlagen (s.o. links) und da ein Text verloren geht, wenn man anders vorgeht habe ich es so umgesetzt.
Das ganze funktioniert mit jeder Version von "2.14.x" bis hin zu "2.15.20". (Das ist die neueste Version, die auf dem Rechner habe. Es sollte auch darüber hinaus arbeiten, aber das kann ich dann im Moment nicht testen)
Neil hatte zwar ebenso angeregt das ganze über einen engraver zu regeln, aber das übersteigt meine Kenntnisse.
Frohes Neues Jahr,
Harm
P.S.
außerdem ist die Gefahr groß, dass man irgendwas davon vergisst.
Z.B. den backslash vor score. ;)