Autor Thema: Legatobogen horizontal ausdehnen  (Gelesen 3933 mal)

Enternix

  • Member
Legatobogen horizontal ausdehnen
« am: Montag, 21. November 2011, 04:03 »
Die Endpunkte von Legatobögen lassen sich vertikal einfach mit Slur#'positions verändern. Aber manchmal sind mir die Bögen etwas zu kurz und ich möchte die Endpunkte auch horizontal verändern:

Daher habe ich eine Scheme-Funktion geschrieben, denke aber, dass das bestimmt irgendwie einfacher geht:
\version "2.14.2"

extendSlur =
#(define-music-function
   (parser location x)
   (pair?)
#{
\once \override Slur #'stencil = #(lambda (grob)
(let* ((slur-start (car (ly:stencil-extent (ly:slur::print grob) 0)))
   (slur-end (cdr (ly:stencil-extent (ly:slur::print grob) 0)))
   (length-input (+ slur-end slur-start))
   (length-output (+ length-input (- (cdr $x)(car $x))))
   (scale-factor (/ length-output length-input))
   (x-shift (car $x)))
(ly:stencil-translate
   (ly:stencil-scale (ly:slur::print grob) scale-factor 1)
   (cons x-shift 0))))
#})

\relative c'' {
   % Der Anfangspunkt desBogens soll um 2 Staffspaces nach links,
   % der Endpunkt um 2 nach rechts verschoben werden:
   \extendSlur #'(-2 . 2) f( e d f)
}

Kurze Erklärung:
ly:stencil-extent berechnet die Länge des Bogens vor der Veränderung (length-input). Dann addiere ich die Verlängerung des Bogens hinzu: ergibt length-output. Der Quotient daraus ergibt den Skalierungsfaktor für ly:stencil-scale. Das Ganze wird schließlich mit ly:stencil-translate verschoben.
Soweit funktioniert es zwar, aber der Umweg über den Skalierungsfaktor stört mich etwas: Wenn der Bogen sehr lang ist und die Verlängerung nach links und rechts gering sein soll, dürfte es sehr ungenau werden (101 / 100 ≈ 1).
Kennt jemand eine andere Lösung?
« Letzte Änderung: Montag, 21. November 2011, 06:45 von Enternix »

ewipond

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #1 am: Dienstag, 22. November 2011, 15:04 »
Hallo Enternix,

du kennst vielleicht auch die funktion \shapeSlur von Dmytro O. Redchuk & David Nalesnik mit der man alle 4 Kontrollpunkte eines Bogens verändern kann.
Das Prinzip:  \shapeSlur #'(x1 y1   x2 y2   x3 y3    x4 y4).
Hier eine  Kopie:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% http://lsr.dsi.unimi.it/LSR/Snippet?id=639 :
% http://lists.gnu.org/archive/html/lilypond-user/2007-08/msg00539.html
% http://lists.gnu.org/archive/html/lilypond-user/2009-09/msg00495.html
% By Dmytro O. Redchuk, incorporating a function written by David Nalesnik
% Thanks, Neil, for your help!!

#(define ((s-alter-curve offsets) grob)
   ;; get default control-points
   (let ((coords (ly:slur::calc-control-points grob)))
     ;; add offsets to default coordinates
     (define (add-offsets coords offsets)
       (if (null? coords)
       '()
       (cons
         (cons (+ (caar coords) (car offsets))
               (+ (cdar coords) (cadr offsets)))
         (add-offsets (cdr coords) (cddr offsets)))))

     (if (null? offsets)
         coords
         (add-offsets coords offsets))))

#(define ((t-alter-curve offsets) grob)
   ;; get default control-points
   (let ((coords (ly:tie::calc-control-points grob)))
     ;; add offsets to default coordinates
     (define (add-offsets coords offsets)
       (if (null? coords)
       '()
       (cons
         (cons (+ (caar coords) (car offsets))
               (+ (cdar coords) (cadr offsets)))
         (add-offsets (cdr coords) (cddr offsets)))))

     (if (null? offsets)
         coords
         (add-offsets coords offsets))))         


#(define ((shape-slur offsets) grob)
   (let* (
          ;; have we been split?
          (orig (ly:grob-original grob))
          ;; if yes, get the split pieces (our siblings)
          (siblings (if (ly:grob? orig)
                        (ly:spanner-broken-into orig) '() ))
          (total-found (length siblings)))
     (if (>= total-found 2)
         ;; shape BROKEN
         ;; walk through siblings, find index in list
         ;; and apply offsets from list of offsets:
         (let loop ((n 0))
                   (if (eq? (list-ref siblings n) grob)
                       ;; return altered:
                       ((s-alter-curve (list-ref offsets n)) grob)
                       (if (< n total-found)
                           (loop (1+ n))
                           ;; end of list -- none found?!
                           ;; return defaults:
                           ((s-alter-curve '()) grob))))
         ;;
         ;; shape UNBROKEN
         ((s-alter-curve offsets) grob))))

#(define ((shape-tie offsets) grob)
   (let* (
          ;; have we been split?
          (orig (ly:grob-original grob))
          ;; if yes, get the split pieces (our siblings)
          (siblings (if (ly:grob? orig)
                        (ly:spanner-broken-into orig) '() ))
          (total-found (length siblings)))
     (if (>= total-found 2)
         ;; shape BROKEN
         ;; walk through siblings, find index in list
         ;; and apply offsets from list of offsets:
         (let loop ((n 0))
                   (if (eq? (list-ref siblings n) grob)
                       ;; return altered:
                       ((t-alter-curve (list-ref offsets n)) grob)
                       (if (< n total-found)
                           (loop (1+ n))
                           ;; end of list -- none found?!
                           ;; return defaults:
                           ((t-alter-curve '()) grob))))
         ;;
         ;; shape UNBROKEN
         ((t-alter-curve offsets) grob))))         

shapeSlur =
#(define-music-function (parser location offsets)
                        (list?)
  #{
    \once \override Slur #'control-points = #(shape-slur $offsets)
  #})

shapeTie =
#(define-music-function (parser location offsets)
                        (list?)
  #{
    \once \override Tie #'control-points = #(shape-tie $offsets)
  #}) 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%EXAMPLES
 % \shapeSlur #'(0 -2.5 -1 3.5 0 0 0 -2.5)
 % d4( d' b g g,8 f' e d c2)
 
  %% including () means "do not touch" and has the same effect as (0 0 0 0 0 0 0 0)
 % \shapeSlur #'((0 -2.5 0 1.5 0 1 0 -1) ())
 
 
  %% borh halves of the slur are modified
 % \shapeSlur #'((0 -2.5 0 1.5 0 1 0 -1) (1 2 0 1 0 1 0 0))
 




Ich finde diese sehr hilfreich - man kann auch über einen Systemumbruch geteilte Bögen getrennt bearbeiten Es gibt dabei nur einen Haken: man muss vorher wissen, ob dabei ein Umbruch auftritt, sonst gibt's eine Fehlermeldung.

Beste Grüße

harm6

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #2 am: Dienstag, 22. November 2011, 22:08 »
Hallo Enternix,

Zitat von: Enternix
Daher habe ich eine Scheme-Funktion geschrieben, denke aber, dass das bestimmt irgendwie einfacher geht

Die Setzung von Bögen ist eine äußerst komplizierte Angelegenheit, insofern wird es wohl nicht einfacher gehen.

Zu Deiner Funktion:
Die Berechnung der Original-Länge ist nicht ganz korrekt: Du hättest die Differenz und nicht die Summe von slur-end und slur-start benutzen sollen. Dafür gibts dann auch eine vorgefertigte Definition: interval-length.
Der Unterschied ist allerdings so gering, daß er für mich auch bei höchster Vergrößerung nicht wahrnehmbar ist. Ich dachte, ich weise Dich doch mal drauf hin, da es bei anderen Projekten durchaus wichtig werden kann.

Ansonsten macht Deine Funktion genau was sie soll, mehr kann man von einer guten Funktion nicht erwarten!

Anders geht es AFAIK nur mit dem Weg über die 'control-points. Das sehr unhandliche Verfahren mit \override Slur #'control-points = ... wird durch die von ewipond erwähnten Funktionen erheblich erleichtert. Man braucht allerdings eine Liste mit acht Zahlen, dafür sind diese Funktionen dann auch erweiterbar um mit dem Zeilensprung umgehen zu können.

Im angehängten file findest Du zunächst meine Fassung Deiner Funktion. (Die noch nicht erwähnten Änderungen dort sind eher Stilfragen.)
Dann noch mal die Funktionen/Definitionen wie bei ewipond (Wir scheinen eine unterschiedliche Quelle zu benutzen, denn die Benennungen sind leicht unterschiedlich. Zusätzlich ist dieser Abschnitt des files um eine Funktion erweitert um PhrasingSlurs zu bearbeiten. Der Test-Teil ist recht groß, denn ich hab' da ein bißchen rumgespielt :) )
Am Schluß noch eine Funktion (extendSlurII), die diese Definitionen benutzt, sich aber nur um die rechts/links-Ausdehnung kümmert. Dadurch gelingt es die benötigten Variablen auf ein Zahlenpaar zu reduzieren. extendSlurII funktioniert nicht beim Zeilensprung ist aber vielleicht eine Alternative zu Deinem extendSlur.

Gruß,
  Harm


Enternix

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #3 am: Mittwoch, 23. November 2011, 02:58 »
Vielen Dank für die Antworten! Super Hilfe! Eine echt gute Community hier in dem Forum!
Eine Anmerkung zu der Berechnung der Original-Länge: Zunächst hatte ich auch die Differenz gewählt. Dann ging der Bogen aber immer zu weit nach rechts raus. Daher habe ich geraten, dass möglicherweise ein anderes Koordinatensystem benutzt wurde. z.B.:

Zumindest war der Bogen bei mir nur dann richtig, wenn ich nicht subtrahiert, sondern car und cdr addiert habe. Ich nehme also an, dass die Originallänge hier tatsächlich durch Addition ermittelt wird (auch wenn ich das etwas schräg finde). Ist aber eigentlich nur geraten...  ;)

harm6

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #4 am: Mittwoch, 23. November 2011, 13:28 »
Hallo Enternix,

Zitat von: Enternix
Ist aber eigentlich nur geraten...

ich rate so ungern...  ;)

Also habe ich eine Test-funktion geschrieben, um den Sachverhalt zu klären und zu veranschaulichen:

  • Zunächst habe ich die Länge des Slur ermittelt mit Subtraktion von cdr und car (length-harm) und auch durch Addition von cdr und car (length-enternix)
  • Diese Längen habe ich dann benutzt um eine Linie zu zeichnen: line-harm bzw line-enternix.
  • Diese Linien dann zum Slur via ly:stencil-combine-at-edge hinzugefügt. (Die sonstigen Verschiebungen sind nur der leichteren Vergleichbarkeit wegen eingefügt)

\version "2.14.2"

testSlurLength =
#(define-music-function (parser location) ()
#{
        \once  \override Slur #'stencil = #(lambda (grob)
(let* ((slur-stencil (ly:slur::print grob))
       (slur-ext (ly:stencil-extent slur-stencil X))
       (length-harm (- (cdr slur-ext)(car slur-ext)))
       (length-enternix (+ (cdr slur-ext)(car slur-ext)))
       (line-harm (grob-interpret-markup grob
        (markup #:draw-line (cons length-harm 0)
                #:fontsize -5 "harm (cdr minus car)")))
       (line-enternix (grob-interpret-markup grob
        (markup #:draw-line (cons length-enternix 0)
                #:fontsize -5 "Enternix (cdr plus car)"))))
       
(ly:stencil-translate-axis
  (ly:stencil-combine-at-edge
    (ly:stencil-combine-at-edge
      slur-stencil
      Y
      DOWN
      (ly:stencil-translate-axis
        line-harm
        0.65 X)
      1)
    Y
    DOWN
    line-enternix
    1)
4 Y)
       ))
#})

\relative c'' {
        \set Staff.instrumentName = \markup \fontsize #-2 "testSlurLength "
   
        \testSlurLength  f (e d f)
}

Fazit: Die durch Addition ermittelte Linie ist zu lang.

In Deiner Original-Funktion (extendSlur) wird diese (falsche) Länge aber auch bei der Berechnung der neuen Länge, sowie bei der Berechnung des scale-factor benutzt. Dadurch sinkt die Ungenauigkeit unter die Wahrnehmungsgrenze.

Wenn der Bogen zunächst zu weit nach rechts ging (bei cdr/car-Subtraktion) lag das möglicherweise an anderen Setzungen.

Gruß,
  Harm

Enternix

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #5 am: Donnerstag, 24. November 2011, 06:43 »
Vielen Dank Harm! Du hast mal wieder recht!  :)
Nur was mache ich dann falsch?
\version "2.14.2"

% Summe:
extendSlurI =
#(define-music-function
   (parser location x)
   (pair?)
   #{
      \once \override Slur #'stencil = #(lambda (grob)
              (let* ((slur-start (car (ly:stencil-extent (ly:slur::print grob) 0)))
                     (slur-stencil (ly:slur::print grob))
                     (slur-ext (ly:stencil-extent slur-stencil X))
                     (slur-length (interval-length slur-ext))
                     (slur-end (cdr (ly:stencil-extent (ly:slur::print grob) 0)))
                     (length-input (+ slur-end slur-start)) ; scheint zu stimmen: "+"
                     (length-output (+ length-input (- (cdr $x)(car $x))))
                     (scale-factor (/ length-output length-input))
                     (x-shift (car $x)))
                    (ly:stencil-translate
                       (ly:stencil-scale (ly:slur::print grob) scale-factor 1)
                       (cons x-shift 0))))
#})

% Differenz:
extendSlurII =
#(define-music-function (parser location x) (pair?)
   #{
      \once  \override Slur #'stencil = #(lambda (grob)
              (let* ((slur-stencil (ly:slur::print grob))
                     (slur-ext (ly:stencil-extent slur-stencil X))
                     (slur-length (interval-length slur-ext))
                     (new-slur-length (+ slur-length (- (cdr $x)(car $x))))
                     (scale-factor (/ new-slur-length slur-length))
                     (x-shift (car $x)))
                   
                    (ly:stencil-translate-axis
                       (ly:stencil-scale slur-stencil scale-factor 1)
                       x-shift
                       X)))
#})

\header {
   tagline = ""
}

\relative c'' {
   \time 6/4
   \extendSlurI #'(-2 . 2)
   f( f)
   r
   \extendSlurII #'(-2 . 2)
   f( f)
   r
}
Ich kann leider einen deutlichen Fehler sehen (bei langen Bögen fällt es nicht so auf). Der Bogen sollte doch eigentlich zentriert sein...  :o
Ich glaube, ich habe da mit meinem Fehler der Längenberechnung einfach einen anderen Fehler überdeckt. Denn, wie ich erst jetzt sehe, ist die Skalierung bei mir (Summe) viel zu klein: Das sind niemals 2 Staffspaces nach rechts und links, auch wenn es so schön zentriert scheint. Bei der Differenz ist die Skalierung in Ordnung (grob geschätzt), aber mit der Verschiebung haut es irgendwie nicht hin... (Die Skalierung skaliert möglicherweise auch den leeren Raum vor dem Bogen (car von ly:stencil-extent), so dass man den noch zusätzlich verschieben muss?)
« Letzte Änderung: Donnerstag, 24. November 2011, 14:44 von Enternix »

harm6

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #6 am: Donnerstag, 24. November 2011, 22:34 »
Hallo Enternix,

Du hast die Lösung eigentlich schon beschrieben:

Zitat
Die Skalierung skaliert möglicherweise auch den leeren Raum vor dem Bogen (car von ly:stencil-extent), so dass man den noch zusätzlich verschieben muss?

Das hatte ich übersehen.
Um es zu testen habe ich mir eine Reihe von Werten anzeigen lassen. Man sieht dann, daß in slur-ext der car-Wert mitskaliert wird.
Also habe ich x-corr eingebaut mit dem ich den neuen Slur auf den alten Wert zurückverschiebe und dann erst mit x-shift verschiebe.
Jetzt sollte es funktionieren (ist aber nur wenig getestet).

Ich habe im Code die ganzen display-Befehle erstmal auskommentiert, falls die Funktion jetzt wie gewünscht arbeitet kannst Du sie ja löschen. Den PhrasingSlur habe ich als Vergleich noch dringelassen.

\version "2.14.2"

extendSlurRev =
#(define-music-function (parser location x) (pair?)
#{
        \once  \override Slur #'stencil = #(lambda (grob)
(let* ((slur-stencil (ly:slur::print grob))
       (slur-ext (ly:stencil-extent slur-stencil X))
       (slur-length (interval-length slur-ext))
       (new-slur-length (+ slur-length (- (cdr $x)(car $x))))
       (scale-factor (/ new-slur-length slur-length))
       (new-slur-stencil (ly:stencil-scale slur-stencil scale-factor 1))
       (new-slur-ext (ly:stencil-extent new-slur-stencil X))
;;        (new-slur-length (interval-length new-slur-ext))
       (x-corr (- (car slur-ext) (car new-slur-ext)))
       (x-shift (car $x))
       )
       
;; (begin
;;   (newline)
;;   (display slur-ext)(newline)
;;   (display slur-length)(newline)
;;   (display new-slur-ext)(newline)
;;   (display new-slur-length)
  (ly:stencil-translate-axis
     new-slur-stencil
     (+ x-corr x-shift)
     X)
;;      )
   ))
#})

\relative c'' {
        \set Staff.instrumentName = "extendSlurRev "
   % Der Anfangspunkt desBogens soll um 2 Staffspaces nach links,
   % der Endpunkt um 2 nach rechts verschoben werden:
   r \extendSlurRev #'(-2 . 2) f ( \(f \) ) r
}

Gruß,
  Harm

P.S. Der Ansatz den Slur zu skalieren hat natürlich eine grundsätzliche Schwäche: Die höchste Erhebung des Slur wird je nach gewählter Ausdehnung mit verschoben. Beispielsweise bei \extendSlurRev #'(0 . 4).
Beim Ansatz über die control-points könnte man für ein wenig Ausgleich sorgen.
« Letzte Änderung: Freitag, 25. November 2011, 00:28 von harm6 »

Enternix

  • Member
Re: Legatobogen horizontal ausdehnen
« Antwort #7 am: Sonntag, 27. November 2011, 11:02 »
Vielen Dank für deine Hilfe, Harm! Jetzt scheint Alles zu funktionieren. Ich werde in Zukunft natürlich den flexibleren Weg über die Kontrollpunkte mit shapeSlur wählen. Aber die Hauptsache ist, dass ich was dazugelernt habe! Danke!  :)