Deutsches Lilypond Forum (Archiv)

Allgemein => Fragen zu Funktionen => Thema gestartet von: stefanhuglfing am Mittwoch, 30. März 2016, 21:26

Titel: Problem mit stemUp und voiceOne (gelöst)
Beitrag von: stefanhuglfing am Mittwoch, 30. März 2016, 21:26
Ich habe mich oft gefragt, was der Unterschied zwischen stemUp und voiceOne ist.
Inzwischen weiß ich kleine Unterschiede:

mit stemUp/Down geraten Pausen unterschiedlicher Länge übereinander:

\version "2.18.0"
 
\score
 {
  \new Staff 
   <<
    \time 3/4
    \new Voice { \stemUp   \relative c' { e4 f r     R2.    r2   f8 r8 } }   
    \new Voice { \stemDown \relative c' { g4 b r     R2.    r4 g b8 r8 } }       
   >>
   
  \layout{}
 }   


voiceOne/Two zusammen mit dem Schnipsel wie im nächsten Code
kann Ganztaktpausen (z.B. R2.) nicht vereinigen:

\version "2.18.0"

%% http://lsr.dsi.unimi.it/LSR/Item?id=336
%% see also http://code.google.com/p/lilypond/issues/detail?id=1228

%% Usage:
%%   \new Staff \with {
%%     \override RestCollision.positioning-done = #merge-rests-on-positioning
%%   } << \somevoice \\ \othervoice >>
%% or (globally):
%%   \layout {
%%     \context {
%%       \Staff
%%       \override RestCollision.positioning-done = #merge-rests-on-positioning
%%     }
%%   }
%%
%% Limitations:
%% - only handles two voices
%% - does not handle multi-measure/whole-measure rests

#(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))))

\score
 {
  \new Staff
  \with { \override RestCollision.positioning-done = #merge-rests-on-positioning }
   << 
    \time 3/4
    \new Voice { \voiceOne \relative c' { e4 f r     R2.    r2   f8 r8 } }   
    \new Voice { \voiceTwo \relative c' { g4 b r     R2.    r4 g b8 r8 } }       
   >>
   
  \layout{}
 }

Ich kann zwar stemUp/Down verwenden und die Pause verschieben:

\version "2.18.0"
 
\score
 {
  \new Staff 
   <<
    \time 3/4
    \new Voice { \stemUp   \relative c' { e4 f r     R2.     r2    f8 r8  } }   
    \new Voice { \stemDown \relative c' { g4 b r     R2.   
                                                  \once \override Rest
                                                  #'extra-offset = #'( 0 . -2.5)
                                                             r4 g  b8 r8  } }       
   >>
   
  \layout{}
 }

aber das erzeugt folgendes Problem:
Ich möchte die selbe Datei für die Partitur verwenden und für Einzelstimmen.
Wenn ich für die Partitur eine Pause manuell verschiebe, ist sie auch in der Einzelstimme verschoben.

Weiß jemand eine Methode, die alles kann:
- Ganztaktpausen vereinigen?
- Pausen unterschiedlicher Länge nicht verschmelzen?
- das ganze automatisch, so dass die Pausen sowohl in der Partitur
  als auch in der Einzelstimme richtig positioniert werden?
Titel: Re: Problem mit stemUp und voiceOne
Beitrag von: harm6 am Mittwoch, 30. März 2016, 22:32
Hallo,

\stemUp und \stemDown sind absolut ungeeignet eine dauerhafte Zweistimmigkeit zu etablieren, siehe folgendes Beispiel:

\version "2.18.2"

\score {
  \new Staff
  <<
    \new Voice {
      \stemUp
      R1*2 R1 e'1-- -1 -"foo"
    }
    \new Voice {
      \stemDown
      \once \override MultiMeasureRest.extra-offset = #'(1 . 1) R1*3
      c'1-- -2 -"bar"
    }
  >>
  \layout { \context { \Score skipBars = ##t } }
}

Die tenutos sind praktisch nicht erkennbar, die Fingersätze werden übereinander gedruckt, die markups sind nicht eindeutig zuzuordnen, die einfachen Pausen werden übereinander gedruckt. Auch die Mehrtaktpausen werden übereinander gedruckt, was der extra-offset-override verdeutlichen sollte.
Mit einem Wort: g-r-a-u-e-n-h-a-f-t.

All das passiert nicht mit \voiceXxx.
Die Pausen werden separat gesetzt, ja, denn eigentlich soll das ja auch so sein. Ansonsten kann man ja \partcombine verwenden:

\version "2.18.2"

mI = { R1*2 R1 r2 r4 r2 r4 r e'1-- -1 -"foo" }

mII = { R1*3 r4 r2 r2 r4 r c'1-- -2 -"bar" }

\partcombine \mI \mII

Wobei hier die markups auch nicht so schön gesetzt werden.


Nun sind aber Fälle denkbar, in denen \voiceXxx sinnvoll ist, man aber doch die (Ganztakt-)Pausen vereint sehen möchte.
Das LSR-snippet kümmert sich um die einfachen Pausen. Für die Ganztaktpausen wurde `merge-multi-measure-rest-on-Y-offset' entwickelt. Kannst ja mal in den Archiven danach suchen...
Mittlerweile gibt es aber engraver dafür.
http://www.mail-archive.com/lilypond-user%40gnu.org/msg69703.html (http://www.mail-archive.com/lilypond-user%40gnu.org/msg69703.html)

\version "2.18.2"

#(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 merge-rests-engraver
   (lambda (context)
     (let ((rest-same-length
             (lambda (rest-a rest-b)
               (eq? (ly:grob-property rest-a 'duration-log)
(ly:grob-property rest-b 'duration-log))))
           (rests '()))
     `((start-translation-timestep . ,(lambda (trans)
                                        (set! rests '())))
       (stop-translation-timestep . ,(lambda (trans)
                                       (if (and (has-at-least-two rests)
                                             (all-equal rests rest-same-length))
                                         (for-each
                                           (lambda (rest)
(ly:grob-set-property! rest 'Y-offset 0))
                                           rests))))
       (acknowledgers
         (rest-interface . ,(lambda (engraver grob source-engraver)
                              (if (eq? 'Rest (assoc-ref
(ly:grob-property grob 'meta) 'name))
                                (set! rests (cons grob rests))))))))))

#(define merge-mmrests-engraver
   (lambda (context)
     (let* ((mmrest-same-length
              (lambda (rest-a rest-b)
                (eq? (ly:grob-property rest-a 'measure-count)
                     (ly:grob-property rest-b 'measure-count))))
            (merge-mmrests
              (lambda (rests)
                (if (all-equal rests mmrest-same-length)
                  (let ((offset
                          (if
                           (eq? (ly:grob-property (car rests) 'measure-count) 1)
                           1 0)))
                    (for-each
                      (lambda (rest)
                        (ly:grob-set-property! rest 'Y-offset offset))
                      rests)))))
            (curr-rests '())
            (rests '()))
     `((start-translation-timestep . ,(lambda (trans)
                                        (set! curr-rests '())))
       (stop-translation-timestep . ,(lambda (trans)
                                       (if (has-at-least-two curr-rests)
                                         (set! rests (cons curr-rests rests)))))
       (finalize . ,(lambda (translator)
                      (for-each merge-mmrests rests)))
       (acknowledgers
         (rest-interface . ,(lambda (engraver grob source-engraver)
                              (if (eq? 'MultiMeasureRest (assoc-ref
(ly:grob-property grob 'meta) 'name))
                                (set! curr-rests (cons grob curr-rests))))))))))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXAMPLE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mI = { R1*2 R1 r2 r4 r2 r4 r e'1-- -1 -"foo" }

mII = { R1*3 r4 r2 r2 r4 r c'1-- -2 -"bar" }

\score {
  \new Staff
  <<
    \new Voice { \voiceOne \mI }
    \new Voice { \voiceTwo \mII }
  >>
  \layout {
    \context {
      \Staff
      \consists #merge-mmrests-engraver
      \consists #merge-rests-engraver
    }
    \context {
      \Score
      \override BarNumber.padding = #3
      skipBars = ##t
    }
  }
}

\mI

\mII

HTH,
  Harm

P.S.
Pausen verschiebt man mittels 'staff-position, 'extra-offset ist absolut last ressort.

\version "2.18.2"

{
  \once \override Rest.staff-position = #8
  r1
  \once \override MultiMeasureRest.staff-position = #-8
  R1
}
Titel: Re: Problem mit stemUp und voiceOne
Beitrag von: stefanhuglfing am Donnerstag, 31. März 2016, 05:52
Danke, das erfüllt mir alle Wünsche!