Autor Thema: Bindebögen und Legato  (Gelesen 2219 mal)

DocTaxon

  • Member
Bindebögen und Legato
« am: Dienstag, 7. Mai 2013, 19:13 »
ver 2.16.0

Hallo! Habe zwei Noten mit jeweils 4 Notenköpfen, wobei ich die Notenköpfe alle einzeln mit einem Bogen verbinden will.

das hier funktioniert aber nicht:
<c e( bes'( c>4~ <c f) a) c>8

Und ich habe schon viele andere Kombinationen probiert. Die Bindebögen mit der Tilde werden angezeigt. Aber die Legatobögen zwischen e und f , bes und a funktionieren nicht.

Weiß jemand was?
Danke, Doc Taxon ...

harm6

  • Member
Re: Bindebögen und Legato
« Antwort #1 am: Mittwoch, 8. Mai 2013, 01:02 »
Hallo Doc,

Zitat von: DocTaxon
Hallo! Habe zwei Noten mit jeweils 4 Notenköpfen, wobei ich die Notenköpfe alle einzeln mit einem Bogen verbinden will.
Du meinst sicherlich zwei vierstimmige Akkorde. ;)

Und hast Dir damit ein richtiges Problem eingehandelt.

Grundsätzlich kann man in LilyPond zwei (gleiche) Akkorde mit Haltebögen versehen, sodaß jede einzelne Note einen Haltebogen zur entsprechenden Note des nächsten Akkord bekommt.
Anders sieht die Situation bei legato-Akkorden aus. Hier wird grundsätzlich nur ein Bogen ausgegeben.
Falls man eine Reihe von legato-Akkorden hat ist das auch durchaus sinnvoll.
Falls man nur zwei Akkorde hat, habe ich mir selber schon gewünscht von jeder Note aus einen legato-Bögen setzen zu können.
In Deinem Fall, mit dem Mix aus legato- und Haltebögen will man das auf jeden Fall.

Es gibt zwar das feature doppelte legato-Bögen zu setzen, mittels \set doubleSlurs = ##t, aber es sind nur zwei. Falls man mehr braucht muß man tricksen (zweite Stimme, versteckte Noten, o.ä.)

In Deinem Fall reichen zwei legato-Bögen allerdings, da die beiden andern Noten aus den vierstimmigen Akkorden mit Haltebögen versehen sind.
Jedoch sitzen die legato-Bögen an der falschen Stelle nämlich über bzw unter den Akkorden.
Es gibt zwar die Möglichkeit einzelne Bögen mittels 'control-points (besser jedoch mit der \shape-Funktion) zu verändern, allerdings gibt es keine Möglichkeit die Bögen die mit \set doubleSlurs = ##t geschaffen wurden einzeln anzusprechen,
eigentlich ...

Ich hab' da mal tief in die scheme-Trickkiste gegriffen:

\version "2.16.2"

shapeDoubleSlur =
#(define-music-function (parser location offsets)(list?)
  (_i "Offset control-points of @var{Slur} by @var{offsets}. 
  @var{Slur} is supposed to be invoked by @code{\\once\\set doubleSlurs = ##t}
  The argument is a list of number pairs or list of such lists.  Each element
  of a pair represents an offset to one of the coordinates of a control-point.")

   (define (read-out l1 l2)
     (define (helper ls1 ls2 ls3)
     "Filters all elements of ls1 from ls2 by their grob-name
      and appends it to ls3"
      (let ((grob-name-proc
              (lambda (x) (assq-ref (ly:grob-property x 'meta) 'name))))
       (if (null? ls1)
           ls3
           (helper
             (cdr ls1)
             ls2
             (append ls3
                     (filter (lambda (x) (eq? (car ls1) (grob-name-proc x)))
                             ls2))))))
    (helper l1 l2 '()))

;; Thanks to David Nalesnik for his great shape-functions!!
   (define ((shape-curve offsets) grob)
     (let* ((orig (ly:grob-original grob))
            (siblings (if (ly:spanner? grob)
                          (ly:spanner-broken-into orig) '()))
            (total-found (length siblings))
            (function (assoc-get 'control-points
                                 (reverse (ly:grob-basic-properties grob))))
            (coords (function grob)))
   
       (define (offset-control-points offsets)
         (if (null? offsets)
             coords
             (map
               (lambda (x y) (coord-translate x y))
               coords offsets)))
   
       (define (helper sibs offs)
         (if (pair? offs)
             (if (eq? (car sibs) grob)
                 (offset-control-points (car offs))
                 (helper (cdr sibs) (cdr offs)))
             coords))
   
       ;; we work with lists of lists
       (if (or (null? offsets)
               (not (list? (car offsets))))
           (set! offsets (list offsets)))
   
       (if (>= total-found 2)
           (helper siblings offsets)
           (offset-control-points (car offsets)))))
#{
  \once \set doubleSlurs = ##t
 
  \once\override Slur #'after-line-breaking =
    #(lambda (grob)
      (let* ((sys (ly:grob-system grob))
             (elements-lst
               (ly:grob-array->list (ly:grob-object sys 'all-elements)))
             (grob-name
               (lambda (x) (assq-ref (ly:grob-property x 'meta) 'name)))
             (X-coord (lambda (x) (ly:grob-relative-coordinate x sys X)))
             (slurs (read-out (list 'Slur) elements-lst))
             (slur-X-coord (X-coord grob))
             (relevant-slurs
                 (remove (lambda (slur) (not (= slur-X-coord (X-coord slur))))
                         slurs)))
      (ly:grob-set-property!
        (car relevant-slurs)
        'control-points
        (shape-curve (car offsets)))
      (ly:grob-set-property!
        (cadr relevant-slurs)
        'control-points
        (shape-curve (cadr offsets)))))
#})

     
     
\relative c' {
  c1( d)
  e( f)
  \shapeDoubleSlur
    #'(
       ((0.8 . 1.8) (0.4 . 2.1) (-0.3 . 2.1) (-0.7 . 1.9))
       ((-0.1 . -2.0) (-0.3 . -3.5) (-0.5 . -3.3) (-1.0 . -2.1))
      )
  <c  e bes' c >4~( <c f a c>4)
  c2
  c1( d)
  e( f)
}

HTH,
  Harm

P.S.
Zur Anwendung lese in der NR zur \shape-Funktion nach.
Die anderen Noten aus der Beispielmusik stehen nur da, um zu demonstrieren, daß die Funktion wirklich die richtigen legato-Bögen ausliest.

DocTaxon

  • Member
Re: Bindebögen und Legato
« Antwort #2 am: Mittwoch, 8. Mai 2013, 18:23 »
das ist ja Wahnsinn, und funktioniert auch ganz gut.

Warum baut man sowas nicht in die nächste Lilypond-Version mit ein?

Vielen Dank dafür, -- Doc Taxon ...

harm6

  • Member
Re: Bindebögen und Legato
« Antwort #3 am: Mittwoch, 8. Mai 2013, 22:49 »
Hallo Doc,

freut mich, daß es Dir gefällt.

Zitat
Warum baut man sowas nicht in die nächste Lilypond-Version mit ein?

Dieser Code wird es nicht in die nächste Version schaffen.
Tatsächlich handelt es um einen methodisch sehr umständlichen work-around:Ich lese erst alle grobs einer Zeile aus, filtere dann die Slurs heraus und schmeiße zum Schluß die Slurs raus, die nicht in betracht kommen, um die dann verbleibenden auf ihre 'control-points ansprechen zu können.
Ein guter fix wäre es Code/Methodik/Syntax zu schaffen um diese beiden Slurs direkt ansprechen zu können. Ich fürchte jedoch, daß dazu Arbeit in C++ jenseits meiner Kenntnisse erforderlich wäre.

Der korrekte Platz für meinen Code/workaround ist das LSR.
Jedoch bin ich beim downgraden des Codes auf 2.14.2 (die aktuelle LSR-Version) auf ein mir unerklärliches Problem gestoßen.

Zitat
GNU LilyPond 2.14.2
Processing `shape-double-slurs.ly'
Parsing...
Interpreting music... [8]
Preprocessing graphical objects...
Finding the ideal number of pages...
Fitting music on 1 page...
Drawing systems...ERROR: Unbound variable: remove

Da frag ich gerade auf der internationalen Liste nach.

Je nach Antwort wirds dann bald ein neues Snippet geben, oder auch nicht.


Gruß,
  Harm