Autor Thema: Phrasierungsbögen an Text ausrichten / Custom TextSpannerEngraver  (Gelesen 4229 mal)

xr

  • Gast
Phrasierungsbögen an Text ausrichten / Custom TextSpannerEngraver
« am: Samstag, 18. Februar 2017, 11:46 »
EDIT: DER THREADTITEL WURDE GEÄNDERT
ursprünglicher Titel: vom Grob NoteColumn einen Lyrics Grob finden

Hi,

ich versuche, Phrasierungsbögen statt unter die Noten unter die Lyrics zu setzen. Das klappt soweit (siehe Beispiel Code).
Allerdings werden die Bögen bisher nur von Note zu Note gesetzt. Ich würde sie allerdings gern vom Wortanfang bis zum Wortende, die der jeweiligen Note zugehören, setzen.

Was ich finden kann, ist den Grob der Spalte, in der der Phrasierungsbogen gesetzt wird. Weiß jemand, wie ich von dessem Parent ( Grob NoteColumn ) zu dem Grob gelangen kann, der den Lyrics Text setzt?

Hier mal mein Code:
\version "2.18.2"

%%%%%%%--------------------
% HELFER
%%%%%%%--------------------
#(define (disp vals) 
     (newline)
     (display vals)
     )

#(define (loop vals)
     (define n 0)
    (for-each (lambda (x)
                  (display n)
                  (if (list? n) (loop n) n)
                  (newline)
                  (set! n (+ 1 n))
                 (display x)
                 (newline)
                 )
        vals )
    )

#(define (nth n l)
  (if (or (> n (length l)) (< n 0))
    (error "Index out of bounds.")
    (if (eq? n 0)
      (car l)
      (nth (- n 1) (cdr l)))))
     
#(define zaehler 0)
#(define zaehler-b "0")

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


#(define (shape-slur grob)
     
     (define xy (ly:slur::calc-control-points grob))
     
     (define first-sib 0)
     (define second-sib 0)
     (define third-sib 0)
     
     (define props-a 0)
     (define props-b 0)
     (define props-c 0)

     (define newY 0)
     
         
     
   (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))                 
         
          )
       
       (disp "-------------------------------------------------") 


       
        (ly:grob-set-nested-property! grob (list 'details 'spanner-id ) zaehler)
        (ly:grob-set-property! grob  'annotation (number->string zaehler))
               
        (disp zaehler-b)
        (set! zaehler (+ zaehler 1))
        (set! zaehler-b (number->string zaehler))
       
       
        (disp  (ly:grob-parent grob 0))

       
        (cond
          ((= 0 total-found)
            (disp "");0 gefunden" )
            )
          ((= 1 total-found)
            (disp "");(disp "1 gefunden" )
            )
          ((= 2 total-found)
            (disp "");(disp "2 gefunden" )
            )
          ((= 3 total-found)
            (disp "3 gefunden" )
           
           
            (set! first-sib  (nth 0 siblings))
            (set! second-sib (nth 1 siblings))
            (set! third-sib (nth 2 siblings))
           
            (set! props-a (ly:slur::calc-control-points first-sib))
            (set! props-b (ly:slur::calc-control-points second-sib))
            (set! props-c (ly:slur::calc-control-points third-sib))
           
            (cond
                ((equal? xy props-a)
                    (disp "ist 0")
                    )
                ((equal? xy props-b)
                    (disp "ist 1")
                    )
                ((equal? xy props-c)
                    (disp "ist 2")
                    )
                (else (disp "nicht gefunden ###"))
                )
           
            (disp xy)
            (disp props-a)
            (disp props-b)
            (disp props-c)
           
            )
          (else (disp "nicht gefunden"))
            )
                   
    (disp "")
    )
    xy

)


shapeSlur =
#(define-music-function (parser location )
    () 
   
  #{       
      \override Staff.PhrasingSlur.cross-staff = ##t
      \override Staff.PhrasingSlur.outside-staff-priority = ##f
      \override Staff.PhrasingSlur.extra-offset  = #'(0 . -5)     
     
      \override PhrasingSlur.direction = #DOWN     
      \override PhrasingSlur.control-points = #shape-slur
     
  #})




\paper {
  indent = 0
  ragged-right = ##t
}


\score {
  <<
    \new Staff = "staff" {
      \new Voice = "melody" {
        \relative c'' {
              \shapeSlur
              b4\( b b2\) 
              b4 \( b b2
              b b  \break
              b b
              b b \break
              b b \) 
              b4 \( b b \) b
               
              \( b2 b
              b b \) \break
              b \( b
              b b \) 
              b \( b \break
              b b \)
             
            }
      }
    }
    \new Lyrics
    %\with { alignAboveContext = "staff" }
    {
      \lyricsto "melody" {
          Lorem ipsum dolor sit amet, consectetur adipisici elit,
          sed eiusmod tempor incidunt ut labore et dolore magna aliqua.
          Ut enim ad minim veniam, quis nostrud exercitation ullamco
          laboris nisi ut aliquid ex ea commodi consequat. Quis aute
          iure reprehenderit in voluptate velit esse cillum dolore eu
          fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non
          proident, sunt in culpa qui officia deserunt mollit anim id
          est laborum.
      }
    }
  >>
}


\layout {
  \context {
      \Score
      \remove "Bar_number_engraver"     
    }
  \context {
      \Staff
      \override Stem.direction = #UP
  }
}

Grüße,
Xaver
« Letzte Änderung: Mittwoch, 1. März 2017, 12:47 von xr »

harm6

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #1 am: Samstag, 18. Februar 2017, 23:49 »
Hallo,

hier meine Gedanken dazu (zahlreiche Kommentare inline):

\version "2.19.52"

#(define (get-bounding-lyrics-from-note-columns note-columns)
  (let* ((bound-left (car note-columns))
         (bound-right (last note-columns))
         ;; get PaperColumns
         (pap-col-left (ly:grob-parent bound-left X))
         (pap-col-right (ly:grob-parent bound-right X))
         ;; get PaperColumns 'elements
         (pap-col-elts-left
           (ly:grob-array->list
             (ly:grob-object pap-col-left 'elements)))
         (pap-col-elts-right
           (ly:grob-array->list
             (ly:grob-object pap-col-right 'elements)))
         ;; filter for LyricText via 'lyric-syllable-interface
         (lyr-txt-left
           (filter
             (lambda (e) (grob::has-interface e 'lyric-syllable-interface))
             pap-col-elts-left))
         (lyr-txt-right
           (filter
             (lambda (e) (grob::has-interface e 'lyric-syllable-interface))
             pap-col-elts-right)))
  ;; return a pair with the found grobs, if any. Otherwise return #f
  (if (and (pair? lyr-txt-left) (pair? lyr-txt-right))
      (cons
        (car lyr-txt-left)
        (car lyr-txt-right))
      #f)))

phrasingSlurLyricsExtent =
\override PhrasingSlur.after-line-breaking =
#(lambda (grob)
   (let* (;; If 'padding' (see below) is set to a procedure th following might
          ;; be needed, hence it's only commented.
          ;(orig (ly:grob-original grob))
          ;(siblings (if (ly:grob? orig)
          ;              (ly:spanner-broken-into orig)
          ;              '()))
          (orig-cps (ly:slur::calc-control-points grob))
          (ncs (ly:grob-array->list (ly:grob-object grob 'note-columns)))
          (lyric-bounds
            (get-bounding-lyrics-from-note-columns ncs)))
           
     ;; Go further only if LyricTexts was found
     (if lyric-bounds
         (let* ((lyr-txt-left (car lyric-bounds))
                (lyr-txt-right (cdr lyric-bounds))
                (lyr-txt-left-length
                  (interval-length
                    (ly:grob-extent lyr-txt-left lyr-txt-left X)))
                (lyr-txt-right-length
                  (interval-length
                    (ly:grob-extent lyr-txt-right lyr-txt-right X)))
                (bow-x-length
                  (- (car (last orig-cps)) (car (car orig-cps))))
                ;; 'lyr-average' is the attempt to get a reasonable value for
                ;; setting 2nd and 3rd control-point x-value.
                ;; TODO find a better method/calculation
                ;;      With the calculation below, overrides/tweaks for
                ;;      PhrasingSlur will mostly be ignored...
                (lyr-average
                  (min
                    2
                    (/ bow-x-length 3)
                    (/ (+ lyr-txt-left-length lyr-txt-right-length) 2)))
                ;; TODO
                ;; 'padding' could take a procedure returning different values
                ;; whether the PhrasingSlur is broken or not and for first/last
                ;; control-points.
                (padding -0.5))
                             
         ;; set the bounds of PhrasingSlur to the found LyricText-grobs
         (ly:spanner-set-bound! grob LEFT lyr-txt-left)
         (ly:spanner-set-bound! grob RIGHT lyr-txt-right)
       
         ;; Get the new calculated control-points to base the calculation of the
         ;; final ones on this.
         ;; Actually, there's no need for it, but it makes the following
         ;; calculation  much easier.
         (let* ((cps (ly:slur::calc-control-points grob))
                (first-cp (car cps))
                (fourth-cp (fourth cps)))
       
         ;; The final control-points are calculated assuming an always flat
         ;; PrasingSlur
         (if (and (ly:grob? lyr-txt-left) (ly:grob? lyr-txt-right))
             (ly:grob-set-property! grob 'control-points
               (list
                 (cons
                   (- (car first-cp) lyr-txt-left-length padding)
                   (cdr (car orig-cps)))
                 (cons
                   (- (car first-cp) lyr-txt-left-length (- lyr-average))
                   (cdr (second orig-cps)))
                 (cons
                   (+ (car fourth-cp) lyr-txt-right-length (- lyr-average))
                   (cdr (second orig-cps)))
                 (cons
                   (+ (car fourth-cp) lyr-txt-right-length padding)
                   (cdr (car orig-cps)))))))))))

\paper {
  indent = 0
  ragged-right = ##t
}

\score {
  <<
    \new Staff = "staff" {
      \new Voice = "melody" {
        \relative c'' {
          \phrasingSlurLyricsExtent
          %% The 'extra-offset is still needed ofcourse
          %% No clue how to implement Slurs _into_ Lyrics
          \override PhrasingSlur.extra-offset = #'(0 . -4.8)
          b4\( b b2\)
          b4\( b b2
          b b  \break
          b b
          b b \break
          b2 b \)
          b4 \( b b \) b
          \( b2 b
          b b \) \break
          b \( b
          b b \)
          b \( b \break
          b b \)
        }
      }
    }
    \new Lyrics
    %\with { alignAboveContext = "staff" }
    {
      \lyricsto "melody" {
          Lorem ipsum dolor sit amet, consectetur adipisici elit,
          sed eiusmod tempor incidunt ut labore et dolore magna aliqua.
          Ut enim ad minim veniam, quis nostrud exercitation ullamco
          laboris nisi ut aliquid ex ea commodi consequat. Quis aute
          iure reprehenderit in voluptate velit esse cillum dolore eu
          fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non
          proident, sunt in culpa qui officia deserunt mollit anim id
          est laborum.
      }
    }
  >>
}

\layout {
  \context {
      \Score
      \remove "Bar_number_engraver"     
    }
  \context {
      \Staff
      \override Stem.direction = #UP
  }
}

Ein paar Worte zu Deinem Beispiel-code.

Es wird allgemein als schlechter Stil betrachtet (define whatever ...) (set! whatever ...) für lokale Variablen zu verwenden. Dafür gibts let und Verwandte.
Bitte beachte eine sinnvolle indentation und füge Kommentare ein.

All das nicht nur um es potenziellen Helfern leichter zu machen Deinen Code zu bearbeiten, sondern auch für Dich selbst.
Nach einem Jahr hast Du ansonsten dieselben Schwierigkeiten Deinen Code erneut zu verstehen wie ich anfänglich ;)

HTH,
  Harm

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #2 am: Sonntag, 19. Februar 2017, 09:18 »
Herzlichen Dank für deinen ausführlichen Code. Sehr hilfreich! Da muss ich jetzt erstmal durchschauen.

Eins verstehe ich aber auf Anhieb nicht:
Wieso überschreibst du after-line-breaking (\override PhrasingSlur.after-line-breaking), obwohl doch eigentlich die Control Points bearbeitet und auch zurückgegeben werden?


Was Kommentare angeht, gebe ich dir recht. Mein Code ist auch noch sehr zusammenkopiert und ich suche noch nach einem für mich einheitlichen Stil.
Diese endlosen Klammerschlüsse, die ich überall in Lily-Code sehe, finde ich allerdings sehr unübersichtlich  z.B. (cdr (car orig-cps))))))))))) . Wenn man zum ersten Mal auf den Code schaut, weiß man nie, was alles geschlossen wird. Und wenn mal eine Klammer fehlt, ist auch nicht klar welche. Daher versuche ich eine schließende Klammer für weit auseinanderliegende Ereignisse vereinzelt und auf die gleiche Einrückebene zu setzen wie ihren Anfang.

Gruß,
Xaver
« Letzte Änderung: Sonntag, 19. Februar 2017, 09:22 von xr »

harm6

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #3 am: Montag, 20. Februar 2017, 00:24 »
Zitat
Wieso überschreibst du after-line-breaking (\override PhrasingSlur.after-line-breaking), obwohl doch eigentlich die Control Points bearbeitet und auch zurückgegeben werden?

Das after-line-breaking-property ist ein Eintrittspunkt zu dem man eine Funktion ins Geschehen werfen kann, genauso wie before-line-breaking (dies allerdings zu einem früheren Zeitpunkt).
Nicht jedes property erlaubt eine procedure, manchmal ist man auch Beschränkungen unterworfen, die sich daraus ergeben wann dieses property bearbeitet wird.

So habe ich mir angewöhnt zuerst über after-line-breaking zu gehen. Es sei denn mein code würde dann zu spät bearbeitet, dann wechsel ich auf before-line-breaking. Bis auf seltene Ausnahmen klappt das immer. Für diese Ausnahmen gibts idR aber auch Lösungen...
Meistens teste ich dann allerdings, ob das eigentlich gemeinte property direkt angegangen werden kann.
Das habe ich in diesem Fall schlichtweg vergessen ...
Allerdings setzt die procedure ja nicht nur die control-points, sondern auch left- bzw right-bound des PhrasingSlurs. Ob das beim direkten override der control-points auch noch klappt habe ich nicht probiert. ;)
Aber in diesem Fall müsste man
(ly:grob-set-property! grob 'control-points MEINELISTE)
durch
MEINELISTE
ersetzen.

Zitat
Was Kommentare angeht, gebe ich dir recht. Mein Code ist auch noch sehr zusammenkopiert und ich suche noch nach einem für mich einheitlichen Stil.

Eigentlich geht es nicht um einen für Dich akzeptablen Stil, sondern um einen für die Öffentlichkeit akzeptablen Stil ;)
siehe: http://community.schemewiki.org/?scheme-style Aus dem CG kopiert.

Zitat
Diese endlosen Klammerschlüsse, die ich überall in Lily-Code sehe, finde ich allerdings sehr unübersichtlich  z.B. (cdr (car orig-cps))))))))))) .

Das ist nicht ly-code, sondern scheme, genauer guile.

Zitat
Wenn man zum ersten Mal auf den Code schaut, weiß man nie, was alles geschlossen wird. Und wenn mal eine Klammer fehlt, ist auch nicht klar welche. Daher versuche ich eine schließende Klammer für weit auseinanderliegende Ereignisse vereinzelt und auf die gleiche Einrückebene zu setzen wie ihren Anfang.

So geht es mit mit anderen Programmiersprachen. Bei all den fehlenden Klammern weiß ich nie wo was anfängt bzw tatsächlich aufhört.
Ich denke, daß ist eine Frage der Gewöhnung.


Gruß,
  Harm

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #4 am: Dienstag, 21. Februar 2017, 10:08 »
Zitat
Das after-line-breaking-property ist ein Eintrittspunkt zu dem man eine Funktion ins Geschehen werfen kann,
Das ist ein guter Tip! - Habe ich aber noch nicht umgesetzt.

Zitat
Eigentlich geht es nicht um einen für Dich akzeptablen Stil, sondern um einen für die Öffentlichkeit akzeptablen Stil ;)
:) :) :)

Ich bin in meiner Version doch erstmal dabei geblieben, die Control Points zu setzen. - Während dein Code via (ly:spanner-set-bound! grob LEFT lyr-txt-left) die Spanner setzt.
Vielleicht ist letzteres auch die bessere Idee, denn bei mir ragt die rechte Seite einer abschließenden Klammer immer noch über das Wort hinaus. Bei mir werden die Extensions via (ext  (ly:grob-extent lyr-txt note-column X)) berechnet. Vielleicht sind das noch nicht die richtigen Bezugspunkte?

Allerdings will ich noch die Form der Klammer ändern. Bei einer sich in der nächsten Zeile fortsetzenden Klammern soll sich der Bogen am Ende der Zeile nicht so stark schließen. Gleiches bei einer aus der Vorzeile kommenden Klammer. Auch hätte ich gern stärkere Bögen am Anfang und am Ende, so daß die Klammern mehr in den Text hineingreifen.
Für diese Tweaks gibt es wahrscheinlich mehrere Möglichkeiten. Muss ich noch was experementieren.

Mein Code erzeugt auch noch Fehler, wenn kein Text vorhanden ist. Klammern sollten aber auch bei fehlendem Text gesetzt werden. Diese Implementierung fehlt noch.

Hier mal mein neuer Code:
\version "2.18.2"

#(define (get-contr-pts-of-txt note-column)
     
    (let* (               
        ;; get PaperColumns
        (pap-col (ly:grob-parent note-column X))               
        ;; get PaperColumns 'elements
        (pap-col-elements (ly:grob-array->list (ly:grob-object pap-col 'elements)))               
        ;; filter for LyricText by searching for name LyricText in meta alist
        (lyr-txt
            (car (filter
                (lambda (e) (equal? 'LyricText (cdr (assoc 'name (ly:grob-property e 'meta)))))
                pap-col-elements
            ))
        )
        ;; get text extensions
        (ext  (ly:grob-extent lyr-txt note-column X))
        ;; get text
        ;(txt (ly:grob-property lyr-txt 'text))
        )
        ext
    )
)


#(define* (set-controlPoint grob nr xy-values)
     (cond
         ((= 0 nr)
              (set-car! grob xy-values))
         ((= 1 nr)
              (set-car! (cdr grob) xy-values))
         ((= 2 nr)
              (set-car! (cddr grob) xy-values))
         ((= 3 nr)
              (set-car! (cdddr grob) xy-values))
     )
)

 
#(define (set-start-point grob ncs cps)
     ;; Calculates Start-Point in splitted and in single-line slurs
     (let* (
         (ctrl-pts (get-contr-pts-of-txt (first ncs))))
         (set-controlPoint cps 0 (cons  (car ctrl-pts) -1))
     )
)

#(define (set-end-point grob ncs cps)
     ;; Calculates End-Point in splitted and in single-line slurs
     (let* (
          (ctrl-pts2 (get-contr-pts-of-txt (last ncs)))
          (val (+ (cdr ctrl-pts2) (car (last cps))))
         )
         (set-controlPoint cps 3 (cons  val -1) )
     )
)

#(define (shape-single-slur grob ncs cps)
     ;; Sets unsplitted single-line slur
     (set-start-point grob ncs cps)
     (set-end-point grob ncs cps)
)

#(define (shape-start-slur grob ncs cps)
     (set-start-point grob ncs cps)
     ;; Height of Third-Point is written to Fourth-Point
     (set-controlPoint cps 3 (cons  (car (fourth cps))  (cdr (third cps) )))
)

#(define (shape-middle-slur grob ncs cps)
     ;; doesn't do anything
     ;; TODO: what looks an empty procedure like?
     (let (( x 0)) (set! x 1)))

#(define (shape-last-slur grob ncs cps)
    (set-end-point grob ncs cps)
    ;; ;; Height of Second-Point is written to First-Point
    (set-controlPoint cps 0 (cons  (car (first cps))  (cdr (second cps))))
)
     

#(define (shape-slurs grob)
   
    (let* (
            ;; original ControlPoints
            (cps (ly:slur::calc-control-points grob))
            ;; get NoteColumns
            (ncs (ly:grob-array->list (ly:grob-object grob 'note-columns)))
           
            ;; 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)
                    '()))
           
            ;; Find control-points and map with enumeration to list.
            ;; The mapped enumeration helps to find the
            ;; position of a sibling inside a splitted slur.
            (n -1)
            (sib-points (map
               (lambda (gr)
                  (begin
                  (set! n (+ 1 n))
                  (list n (ly:slur::calc-control-points gr))
                  )
               )
               siblings))
           
            ;; Find position if slur is splitted.
            ;; Compares control points of actual calculated grob
            ;; to the control points of the siblings of the original grob.
            ;; Returns an empty list if slur is not splitted.
            (orig-pts (ly:slur::calc-control-points grob))
            (slur-position
                (filter
                    (lambda (e) (equal? (cadr e) orig-pts))
                    sib-points)) 
        )
        ;; call procedures to set cps positions
        (cond
            ((equal? slur-position '())
                (shape-single-slur grob ncs cps))
            ((equal? 0 (caar slur-position ))
                (shape-start-slur grob ncs cps))
            ((equal? (- (length siblings) 1) (caar slur-position ))
                (shape-last-slur grob ncs cps))
            (else
                (shape-middle-slur grob ncs cps))
        )
        cps
    )
   
)


shapeSlur =
#(define-music-function (parser location )
    ()
   
  #{       
      \override Staff.PhrasingSlur.cross-staff = ##t
      \override Staff.PhrasingSlur.outside-staff-priority = ##f
      \override Staff.PhrasingSlur.extra-offset  = #'(0 . -5)     
     
      \override PhrasingSlur.direction = #DOWN     
      \override PhrasingSlur.control-points = #shape-slurs
  #})


\paper {
  indent = 0
  ragged-right = ##t
}


\score {
  <<
    \new Staff = "staff" {
      \new Voice = "melody" {
        \relative c'' {
              \shapeSlur
             
                b4 b b2
              b4  b \( b2
              b b  \break
              b b
              b b
              b b \break
              b b \)
              b4  b \( b  b \)
               
               b2 b
              b b  \break
              b \( b
              b b
              b  b \break
              b \)  b
             
            }
      }
    }
    \new Lyrics
    %\with { \override LyricText.color = #test }
    {
      \lyricsto "melody" {
          Lorem ipsum dolor sit amet, consectetur adipisici elit,
          sed eiusmod tempor incidunt ut labore et doloredolore magna aliqua.
          Ut enim ad minim veniam, quis nostrud exercitation ullamco
          laboris nisi ut aliquid ex ea commodi consequat. Quis aute
          iure reprehenderit in voluptate velit esse cillum dolore eu
          fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non
          proident, sunt in culpa qui officia deserunt mollit anim id
          est laborum.
      }
    }
  >>
}


\layout {
  \context {
      \Score
      \remove "Bar_number_engraver"     
    }
  \context {
      \Staff
      \override Stem.direction = #UP
  }
}


harm6

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #5 am: Dienstag, 21. Februar 2017, 12:06 »
Hallo,

leider muss ich mich gleich um meinen regulären Job kümmern, insoweit kann ich mich jetzt nicht mit Deinen Fragen bzw Deinem Code auseinandersetzen.
Doch hier:
Zitat
Auch hätte ich gern stärkere Bögen am Anfang und am Ende, so daß die Klammern mehr in den Text hineingreifen.
weiß ich schlichtweg nicht was Du meinst.
Kannst Du das ausführlicher beschreiben bzw ein Bild davon posten (evtl. gefaked mit einem Grafik-Programm)?

Gruß,
  Harm

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #6 am: Mittwoch, 22. Februar 2017, 11:42 »
Ich habe nun erstmal Anfänge und Enden des Bogens händisch eingefügt. Das erzeugt allerdings Probleme - siehe letzte Zeile beim Wort "commodi".
Um Verhältnisse zu berechnen, müßte ich an den linken bzw rechten Nachbarn der aktuellen PaperColumn kommen. Dafür kann ich aber leider keinen Zugang finden.
Vergleiche auch das zweite Bild im Anhang, das die Columns nummeriert (6,7,9,11). Kann man diese Nummern auslesen?

Mittels (ly:grob-parent grob X) bekomme ich den Parent. Wie aber bekomme ich mögliche Kinder?
Und welcher Grob enthält alle horizontalen Objekte?
(Ich habe mal ein Snippet aus der Snippet Repository eingefügt, das die Hierarchie eines Grobs anzeigt.)

Im Übrigen habe ich den Score so geändert, das man sieht, wofür meine Einstellung eigentlich gebraucht wird: Um Sprache rhythmisch zu setzen. Die Bögen sollen später zusammengehörige Phrasen verdeutlichen und auch noch zwischen weiteren Stimmen hin und hergehen.

\version "2.18.2"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% HELFER
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (disp vals)
     (newline)
     (display vals)
     )

#(define (dloop vals)
    (define n 0)
    (for-each
        (lambda (x)
            (newline)
            (display n)
            (if (list? n) (loop n) n)
            (newline)
            (set! n (+ 1 n))
            (display x)
           
        )
        vals
    )
)

#(define (nth n l)
    (if
        (or (> n (length l)) (< n 0))       
        (error "Index out of bounds.")
        (if
            (eq? n 0)
            (car l)
            (nth (- n 1) (cdr l))
        )
    )
)
     
#(define zaehler 0)
#(define (draw-annotation grob)
    ;; for debugging:
    ;; draws a number to the grob
    (ly:grob-set-nested-property! grob (list 'details 'spanner-id ) zaehler)
    (ly:grob-set-property! grob  'annotation (number->string zaehler))     
    (disp '----------------- )
    (disp zaehler)
    (set! zaehler (+ zaehler 1))
)
#(define (props grob)
     (dloop  (ly:grob-properties grob ) )
     )
#(define (bprops grob)
     (dloop  (ly:grob-basic-properties grob ) )
     )
     
     
     
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% from the snippet repository http://lsr.di.unimi.it/LSR/Item?id=622
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#(define (grob::name grob)
  (assq-ref (ly:grob-property grob 'meta) 'name))

#(define (get-ancestry grob)
  (if (not (null? (ly:grob-parent grob X)))
      (list (grob::name grob)
            (get-ancestry (ly:grob-parent grob X))
            (get-ancestry (ly:grob-parent grob Y)))
      (grob::name grob)))

#(define (format-ancestry lst padding)
   (string-append
    (symbol->string (car lst))
    "\n"
    (let ((X-ancestry
           (if (list? (cadr lst))
               (format-ancestry (cadr lst) (+ padding 3))
               (symbol->string (cadr lst))))
          (Y-ancestry
           (if (list? (caddr lst))
               (format-ancestry (caddr lst) (+ padding 3))
               (symbol->string (caddr lst)))))
      (if (equal? X-ancestry Y-ancestry)
          (string-append
           (format #f "~&")
           (make-string padding #\space)
           "X,Y: "
           (if (list? (cadr lst))
               (format-ancestry (cadr lst) (+ padding 5))
               (symbol->string (cadr lst))))
          (string-append
           (format #f "~&")
           (make-string padding #\space)
           "X: " X-ancestry
           "\n"
           (make-string padding #\space)
           "Y: " Y-ancestry
           (format #f "~&"))))
    (format #f "~&")))

#(define (display-ancestry grob)
   (format (current-error-port)
      "~3&~a~2%~a~&"
      (make-string 36 #\-)
      (if (ly:grob? grob)
          (format-ancestry (get-ancestry grob) 0)
          (format #f "~a is not a grob" grob))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (get-cp cps nr xy)   
    (define wert
        (lambda (x)
            (cond
                ((= xy 0)
                     (car x))
                ((= xy 1)
                     (cdr x))
            )
        )
    )
         
      (cond
          ((= 0 nr)
               (wert (car cps)))
          ((= 1 nr)
               (wert (cadr cps)))
          ((= 2 nr)
               (wert (caddr cps)))
          ((= 3 nr)
               (wert (cadddr cps)))
      )
)



#(define (get-contr-pts-of-txt note-column)
     
    (let* (               
        ;; get PaperColumns
        (pap-col (ly:grob-parent note-column X))               
        ;; get PaperColumns 'elements
        (pap-col-elements (ly:grob-array->list (ly:grob-object pap-col 'elements)))               
        ;; filter for LyricText by searching for name LyricText in meta alist
        (lyr-txt
             (filter
                (lambda (e) (equal? 'LyricText (cdr (assoc 'name (ly:grob-property e 'meta)))))
                pap-col-elements
            )
        )
        ;; set default Extensions in case
        ;; no lyrics are present
        (ext (cons -1 1))
        ;; optional: for displaying the text belonging to the slur
        (txt '-)
        (parent (ly:grob-parent pap-col Y))
        )
       
        (if (= 1 (length lyr-txt))
            (begin
                (set! lyr-txt (car lyr-txt))
                ;; get text extensions
                (set! ext  (ly:grob-extent lyr-txt note-column X))
                ;; optional: for displaying the text belonging to the slur
                (set! txt (ly:grob-property lyr-txt 'text))
                ;(disp txt) 
               
               
                ;; DEBUGGING
               
                (if (equal? txt "amet," )
                    (display-ancestry note-column))
               
                ;(display-ancestry note-column)
                ;(set! txt (ly:grob-parent note-column Y))
                ;(set! txt (ly:grob-parent txt X))
                ;(set! txt ( ly:grob- note-column ))
                ;(display-ancestry txt)
                ;(props txt )
                ;(set! txt ( ly:axis-group-interface::calc-pure-y-common pap-col))
                ;(bprops txt)
               
            )
        )
        ext
    )
)


#(define* (set-controlPoint grob nr xy-values)
     (cond
         ((= 0 nr)
              (set-car! grob xy-values))
         ((= 1 nr)
              (set-car! (cdr grob) xy-values))
         ((= 2 nr)
              (set-car! (cddr grob) xy-values))
         ((= 3 nr)
              (set-car! (cdddr grob) xy-values))
     )
)


 
#(define (set-start-point grob ncs cps)
     ;; Calculates Start-Point in splitted and in single-line slurs
     ;; TODO: exact calculation of 1st and 2nd ControlPoint
     (let* (
         (ctrl-pts (get-contr-pts-of-txt (first ncs)))
         
         (oldX1 (car (second cps)))
         (oldY1 (cdr (second cps)))
         
         (newX0 (- (car ctrl-pts) 1) )
         (newX1 newX0);(/ (+ (* newX0 7) oldX1) 8 ))
         (newY1 (- oldY1 1))
         )
         (set-controlPoint cps 0 (cons  newX0 .5))
         (set-controlPoint cps 1 (cons  newX1 newY1))
         
     )
)

#(define (set-end-point grob ncs cps)
     ;; Calculates End-Point in splitted and in single-line slurs
     ;; TODO: exact calculation of 3rd and 4th ControlPoint
     (let* (
          (ctrl-pts (get-contr-pts-of-txt (last ncs)))
         
          (oldX2 (car (third cps)))
          (oldY2 (cdr (third cps)))
         
          (newX3 (+ (+ (cdr ctrl-pts) (car (last cps))) .5 ))
          (newX2 newX3); (/ (+ (* newX3 7) oldX2) 8 ))         
          (newY2 (- oldY2 1))
         )
         (set-controlPoint cps 3 (cons  newX3 .5) )
         (set-controlPoint cps 2 (cons  newX2 newY2))
     )
)



#(define (shape-single-slur grob ncs cps)
     ;; Sets unsplitted single-line slur
     (set-start-point grob ncs cps)
     (set-end-point grob ncs cps)
)

#(define (shape-start-slur grob ncs cps)
     (set-start-point grob ncs cps)
     ;; Height of Third-Point is written to Fourth-Point
     (set-controlPoint cps 3 (cons  (car (fourth cps))  (cdr (third cps) )))
)

#(define (shape-middle-slur grob ncs cps)
     ;; Y of 1st and 4th ControilPoint are calculated for
     ;; flattening the slur
     (let* (
          (oldY0 (cdr (first cps)))
          (oldX0 (car (first cps)))
          (oldY1 (cdr (second cps)))
          (oldY2 (cdr (third cps)))
          (oldX3 (car (fourth cps)))
          (oldY3 (cdr (fourth cps)))
         
          (newY0 (/ (+ oldY0 oldY1) 2) )
          (newY3 (/ (+ oldY2 oldY3) 2) )
         )
         (set-controlPoint cps 0 (cons  oldX0 newY0) )
         (set-controlPoint cps 3 (cons  oldX3 newY3))
     )
)

#(define (shape-last-slur grob ncs cps)
    (set-end-point grob ncs cps)
    ;; ;; Height of Second-Point is written to First-Point
    (set-controlPoint cps 0 (cons  (car (first cps))  (cdr (second cps))))
)
     

#(define (shape-slurs grob)
   
    (let* (
            ;; original ControlPoints
            (cps (ly:slur::calc-control-points grob))
            ;; get NoteColumns
            (ncs (ly:grob-array->list (ly:grob-object grob 'note-columns)))
            ;; 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)
                    '()))
           
            ;; Find control-points and map with enumeration to list.
            ;; The mapped enumeration helps to find the
            ;; position of a sibling inside a splitted slur.
            (n -1)
            (sib-points (map
               (lambda (gr)
                  (begin
                  (set! n (+ 1 n))
                  (list n (ly:slur::calc-control-points gr))
                  )
               )
               siblings))
           
            ;; Find position if slur is splitted.
            ;; Compares control points of actual calculated grob
            ;; to the control points of the siblings of the original grob.
            ;; Returns an empty list if slur is not splitted.
            (orig-pts (ly:slur::calc-control-points grob))
            (slur-position
                (filter
                    (lambda (e) (equal? (cadr e) orig-pts))
                    sib-points)) 
        )
       
        ;; call procedures to set cps positions
        (cond
            ((equal? slur-position '())
                (shape-single-slur grob ncs cps))
            ((equal? 0 (caar slur-position ))
                (shape-start-slur grob ncs cps))
            ((equal? (- (length siblings) 1) (caar slur-position ))
                (shape-last-slur grob ncs cps))
            (else
                (shape-middle-slur grob ncs cps))
        )
        cps
    )   
)


shapeSlur =
#(define-music-function (parser location )
    ()
   
  #{       
      \override Staff.PhrasingSlur.cross-staff = ##t
      \override Staff.PhrasingSlur.outside-staff-priority = ##f
      %% extra-offset might be set inside #shape-slurs
      \override Staff.PhrasingSlur.extra-offset  = #'(0 . -3.6)     
      %\override Staff.PhrasingSlur.details.free-head-distance = #1
      \override PhrasingSlur.direction = #DOWN     
      \override PhrasingSlur.control-points = #shape-slurs
  #})


\paper {
  indent = 0
  %ragged-right = ##t
  ragged-last = ##t
  system-system-spacing.basic-distance = #18 
}


notes = {
    b4 b b2
    b4 b \( b2
    b b
    b b \break
    b b
    b b
    b b \break
    b b \)
    b4 b
    \( b  b \)   
    b2 b
    b b \break
    b b \(
    b b
    b b \break
    b \) b   
}


\score {
  <<
    \new Staff = "staff" {
       
      \new Voice = "melody" {
         
        \relative c'' {
              \shapeSlur
              \notes
            }
      }
    }
    \new Lyrics

    {
      \lyricsto "melody" {
          Lorem ipsum dolor sit amet, consectetur adipisici elit,
          sed eiusmod tempor incidunt ut labore et doloredolore magna aliqua.
          Ut enim ad minim veniam, quis nostrud exercitation ullamco
          laboris nisi ut aliquid ex ea commodi consequat. Quis aute
          iure reprehenderit in voluptate velit esse cillum dolore eu
          fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non
          proident, sunt in culpa qui officia deserunt mollit anim id
          est laborum.
      }
    }
  >>
}


\layout {
   
  \context {
      \Score
      \remove "Bar_number_engraver" 
    }
  \context {
      \Staff
      \override Stem.direction = #UP
      \remove "Time_signature_engraver"
      \remove "Clef_engraver"
      \override StaffSymbol.line-count = #1
  }

  \context {
      \Lyrics
       \override VerticalAxisGroup.
       nonstaff-relatedstaff-spacing = #'((basic-distance . 3.5))
  }
}


Noch eine allgemeine Frage zu Scheme:
Gibt es eine Möglichkeit, Variablen wie in Python zu bestimmen, z.B.
x,y = 0,1 ( dann ist x = 0 und y =1)
Das fände ich praktisch, da man es bei Koordinaten oft mit pairs zu tun hat.

« Letzte Änderung: Mittwoch, 22. Februar 2017, 12:13 von xr »

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #7 am: Mittwoch, 22. Februar 2017, 21:49 »
Wie man die Nachbarn einer PaperColumn findet, weiss ich inzwischen: Über die Elemente des System Grobs.
Der Befehl sähe etwa so aus:
(Nachbarn-einer-PaperColumn (ly:grob-array->list (ly:grob-object system-grob 'elements)))

harm6

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #8 am: Freitag, 24. Februar 2017, 22:08 »
Hallo,

was mich an der ganzen Sache stört ist der nach wie vor nötige override für extra-offset. Das geht fürchterlich schnell krachen.
Insoweit habe ich versucht den PhrasingSlur tatsächlich innerhalb von Lyrics ans laufen zu bekommen, allerdings ohne Erfolg.
Aber einen TextSpanner bekommt man hin. Dessen stencil könnte man dann mit hinreichenden Werten versorgen, um ihn durch make-bow-stencil zu ersetzen.

Aber bevor ich diesen Weg weiter beschreite:
Zitat
Die Bögen sollen später [...] auch noch zwischen weiteren Stimmen hin und hergehen.
Wie soll das nachher aussehen?

Gruß,
  Harm

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #9 am: Sonntag, 26. Februar 2017, 09:53 »
Hallo,

ein Beispiel, wie es aussehen könnte, ist im Anhang.
Die Bögen sind mit Inkscape gesetzt.
In dem Beispiel sieht man drei Staves, wobei oberer und unterer nur die Lyrics zeigen, der mittlere nur noch für die Anzeige einer Mittellinie gebraucht wird.

Bögen setze ich zusätzlich noch zur Anzeige von Tonhöhenverläufen. Ich brauche also manchmal mehrere Bögen aufeinmal.

Zitat
Insoweit habe ich versucht den PhrasingSlur tatsächlich innerhalb von Lyrics ans laufen zu bekommen, allerdings ohne Erfolg.

Das fände ich spannend.
Ideal wäre für mich, Bögen frei setzen zu können (mal mit, mal ohne Spanner). Auch ohne die Beschränkung, dass nur jeweils ein Bogen eines Typs - Phrasing, Bindung - gesetzt werden kann. Und mal mit, mal ohne Beachtung von Kollisionen.
Ich habe ein Beispiel von dir gefunden, das Bögen setzt. https://archiv.lilypondforum.de/index.php?topic=1422.msg7841#msg7841
Allerdings als markup und ohne Spanner.

Ich habe darüber nachgedacht, ob und wie man einen eigenen Grob erzeugen kann.
Wäre es etwa möglich, sich vom PhrasingSlur_engraver einen Grob erzeugen zu lassen und den zu setzen?
Oder könnte man den PhrasingSlur_engraver kopieren und die Kopie im Voice Kontext einbinden?

Die Beispiele, die ich bisher für das Erstellen eines Engravers gefunden habe, sind mir leider noch zu kompliziert.

Gruß,
Xaver
« Letzte Änderung: Sonntag, 26. Februar 2017, 09:59 von xr »

harm6

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #10 am: Sonntag, 26. Februar 2017, 10:35 »
Hallo,

vielen Dank für das Bild, sehr hilfreich für mich, um eine bessere Vorstellung zu bekommen was Dein Ziel ist.
Kann das Geschehen noch komplexer werden oder ist das Dein Maximalziel?

Zitat
Ich habe ein Beispiel von dir gefunden, das Bögen setzt. https://archiv.lilypondforum.de/index.php?topic=1422.msg7841#msg7841
Allerdings als markup und ohne Spanner.
Mittlerweile ist \undertie im source-code, also direkt nutzbar.
Aber ja, es ist ein markup, nichts sonst.

Zitat
Ich habe darüber nachgedacht, ob und wie man einen eigenen Grob erzeugen kann.
Wäre es etwa möglich, sich vom PhrasingSlur_engraver einen Grob erzeugen zu lassen und den zu setzen?
Oder könnte man den PhrasingSlur_engraver kopieren und die Kopie im Voice Kontext einbinden?

Die Beispiele, die ich bisher für das Erstellen eines Engravers gefunden habe, sind mir leider noch zu kompliziert.

Tatsächlich habe ich auch schon über ein neues grob nachgedacht.
Aber das ist eine komplizierte Sache, mit einem engraver allein ist es nicht getan.
Hier ein Beispiel:
http://lists.gnu.org/archive/html/lilypond-user/2016-11/msg00012.html
Hat mich wesentliche Teile der letzten Sommerferien gekostet, das so Hinzukriegen.


Der PhrasingSlur_engraver selbst ist in C++ geschrieben, da kommt man als user ohne den sorce-code dann neu zu kompilieren nicht dran.
Natürlich kann man versuchen ihn in scheme neu zu schreiben. Das ist allerdings jenseits meiner Fähigkeiten, da ich C++ nicht kann.


Könntest Du mal den code für das Bild posten, ohne die Bögen?
Mich interessiert wie Du das ansonsten angelegt hast.

Gruß,
  Harm

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #11 am: Sonntag, 26. Februar 2017, 11:00 »
Kann das Geschehen noch komplexer werden oder ist das Dein Maximalziel?
Maximalziele ändern sich leider mit jedem neuen Stück. Und ja, manchmal sind auch noch Noten oder markups daneben/dazwischen.
Aber ich wäre schon zufrieden, wenn ich Bögen in Lilypond bereits anlegen kann. Und je mehr ich beachten kann und je weniger ich in der Ausgabedatei noch nachträglich bearbeiten muss, desto besser. Momentan kann ich halt gar keine Bögen eintragen. Wenn sich dann Stücke in der Probephase häufiger ändern, muss ich jedesmal alle Bögen von Hand wieder nachtragen. Das dauert und nervt. Und ich vergesse auch schonmal welche.

Zitat
Hier ein Beispiel:
http://lists.gnu.org/archive/html/lilypond-user/2016-11/msg00012.html
Hat mich wesentliche Teile der letzten Sommerferien gekostet, das so Hinzukriegen.

Schaue ich mir an.
 ;D  Ob Computer wirklich eine Zeitersparnis sind, wenn man besondere Lösungen braucht? (frage ich mich häufiger) Handarbeit ist ja auch was Tolles.

Zitat
Könntest Du mal den code für das Bild posten, ohne die Bögen?
Mich interessiert wie Du das ansonsten angelegt hast.

Das muss ich erst aus mehreren Dateien auseinanderklamüsern. kommt die Tage ...

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #12 am: Sonntag, 26. Februar 2017, 12:27 »
Zitat
Hier ein Beispiel:
http://lists.gnu.org/archive/html/lilypond-user/2016-11/msg00012.html
Hat mich wesentliche Teile der letzten Sommerferien gekostet, das so Hinzukriegen.

Habe ich gerade reingeschaut. Da brauche ich bis zu den Sommerferien, um da was zu verstehen. 8)

xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #13 am: Sonntag, 26. Februar 2017, 17:51 »
So, habe den Code für das Bild doch eben zusammenkopiert.
Da können durchaus doppelte oder unwirksame Einstellungen drin sein. Der Code ist schon was älter, und so lange er funktionierte, hatte ich kein Bedarf ihn zu überarbeiten.

Außerdem hatte ich doch falsch in Erinnerung, was welche Stimme macht.
Der oberste Staff enthält die Noten für StimmeA (sind in diesem Beispiel ausgeblendet, können aber bei Bedarf wieder eingeblendet werden)
Der mittlere Staff enthält Noten und Lyrics für StimmeA und StimmeB. Noten sind ausgeblendet.
Der unterste wie oberste für StimmeB.

Heute würde ich Scores für Duos wohl anders konzipieren, damit sie einfacher um Stimmen zu erweitern sind und jede Stimme auch gleich funktioniert. Bei Scores für mehr als zwei Stimmen habe ich das auch schon gemacht.

Töne und Text wurden mit einem Python Script erzeugt, das mir eine andere Eingabedatei übersetzt. Daher das gestreckte Format.

\version "2.18.2"


\header {
  title = "Example"
}

\paper {
  system-system-spacing.padding = #0
  system-system-spacing.basic-distance = #0
  system-system-spacing.minimal-distance = #0
  score-markup-spacing.basic-distance = #0
  score-markup-spacing.minimal-distance = #0
  score-system-spacing.minimal-distance = #0
  score-system-spacing.basic-distance = #0
  indent = 0.0\cm
 
  print-page-number = ##t
  print-first-page-number = ##t
  oddHeaderMarkup = \markup \null
  evenHeaderMarkup = \markup \null
  oddFooterMarkup = \markup {
    \fill-line {
      \on-the-fly #print-page-number-check-first
      \fromproperty #'page:page-number-string
    }
  }
 
  evenFooterMarkup = \oddFooterMarkup

    myStaffSize = #18
    #(define fonts
        (make-pango-font-tree "Trebuchet MS"
        "Nimbus Sans"
        "Luxi Mono"
        (/ myStaffSize 20))) 
}

dummy = {
  \once \omit Score.TimeSignature
  \once \omit Score.Clef
  \partial 64
  \once  \hideNotes
  b64   
  \once \omit Score.BarLine
}

farbe =  #(x11-color 'grey65)

Layout-Noten = {

  % Farben
  \override Voice.NoteHead.color = \farbe
  \override Voice.Stem.color = \farbe
  \override Voice.Beam.color = \farbe
  \override Voice.TupletNumber.color = \farbe
  \override Voice.Dots.color = \farbe
  \override Voice.Rest.color = \farbe
  \override Staff.BarLine.color = #white
  \override Voice.DynamicText.color = #red

  \override Staff.StaffSymbol.line-count = #0
  \override Staff.NoteHead.font-size = #-4

  % Hals
  \override Voice.Stem.length = #3
  \override Voice.Stem.thickness = #1
  % Hals mit Balken
  \override Voice.Stem.length-fraction = #0.6
  \override Voice.Flag.font-size = #-5
  \override Voice.Beam.beam-thickness = #0.3
  \override Voice.Beam.length-fraction = #0.6
  \override Voice.Beam.auto-knee-gap = #0.1
  \override Voice.Beam.gap = #0.
 
  \override TupletBracket.stencil = ##f
 
  % Abstand Akzente
  \override Staff.Script.padding = #1
 
  \override Voice.Script.color = #red
}

Layout = {
  \override Staff.StaffSymbol.line-count = #1
  \override Staff.StaffSymbol.thickness = #0.2
  \override Staff.Stem.transparent = ##t
  % Hals
  \override Voice.Stem.length = #2
  % Hals mit Balken
  \override Voice.Stem.length-fraction = #0
  \override Staff.NoteHead.font-size = #-100
  % Balken
  \override Voice.Beam.beam-thickness = #0
  \override Voice.Beam.length-fraction = #0
  \override Voice.Dots.stencil = ##f
  \override Voice.Stem.stencil = ##f
  \override Voice.Flag.stencil = ##f
  \override Voice.TupletNumber.stencil = ##f
  \override Staff.TextScript.stencil  = ##f
  \override Staff.Rest.stencil  = ##f
 
  \override Staff.BarLine.bar-extent = #'(-.8 . .8)
  \override Staff.BarLine.hair-thickness = #'1.5

}


abstand = {
  \override
      VerticalAxisGroup.default-staff-staff-spacing =
      #'((basic-distance . 0)
         (minimum-distance . 0)
         (padding . 0)
         )     
}

us-oT = {
  \override Voice.Beam.stencil = ##f
  \override Voice.Stem.stencil = ##f
  \override Voice.Flag.stencil = ##f
  \override Voice.NoteHead.transparent = ##t
  \override Voice.Dots.transparent = ##t
  \override Staff.BarLine.stencil = ##f 
  \override Voice.Script.Y-offset = #0
}

 
%% StimmeA-Toene bis SimmeB-Worte werden mit Code erzeugt,
%% daher der langgestreckte Satz.
StimmeA-Toene = \relative c''
    {\stemUp \dummy

  \us-oT
\time 1/4
b4 |
b4 |
b4 |
b4 |
b4 |
b4 |
b4 |
s4 |

  s4 |
b4 |
b4 \break
|
s4 |
b4 |
s4 |
b4 |
b4 |

  s4 |
b4 |
s4 |
b4 \break
|
s4 |
b4 |
s4 |
b4 |

  s4 |
b4 |
s4 |
b4 |
s4 |
b4 |
s4 |
b4 |

  s4 \break
|

     }



StimmeB-Toene = \relative c''
    {\stemDown \dummy

  \us-oT
\time 1/4
s4 |
s4 |
s4 |
s4 |
s4 |
s4 |
s4 |
b4 |

  b4 |
s4 |
s4 |
b4 |
s4 |
b4 |
s4 |
s4 |

  b4 |
s4 |
b4 |
s4 |
b4 |
s4 |
b4 |
s4 |

  b4 |
s4 |
b4 |
s4 |
b4 |
s4 |
b4 |
s4 |

  b4 |

     }



StimmeA-Worte = {
    \lyricsto first {
        dummi \new dummy{}
       
        \new standard {   
}
\new fly {
nach dem Schleicher durch den gelben Sand
ist also ungerichtet die Reihe
ziel ist leicht es
wa ss au ma
       
        }
    }
}


StimmeB-Worte = {
    \lyricsto second {
        dummi \new dummy{}
       
        \new standard {   
}
\new fly {
ihr
Suchen weitestgehend da
so los vie ist
das s ie s
cht       
        }
    }
}


\score {
 
  <<
   
    \new Staff   
        \with {
            \Layout-Noten
            \abstand
            \override Staff.Rest.Y-offset = #0.8
            \override Staff.Script.direction = #UP
            \dynamicUp
        }
        \StimmeA-Toene
   
    \new Staff = "staff_mitte"
        \with {
            \Layout
            \abstand
        }

    <<
      \Layout
      \override Staff.StaffSymbol.color = #farbe
     
      \new Voice = "first"
          \StimmeA-Toene
      \new Voice = "second"
          \StimmeB-Toene
    >>
   
    \new Lyrics
        \with { alignAboveContext = "staff_mitte" }
        \StimmeA-Worte
   
    \new Lyrics
        \with { \override LyricText.extra-offset = #'(0 . -.6) }
        \StimmeB-Worte

    \new Staff
        \with {\Layout-Noten
              \override Staff.Rest.Y-offset = #-0.8 }
        \StimmeB-Toene
       
  >>

  \layout  {
   
    \context {
      \Score
      \remove "Bar_number_engraver"
      \remove "Bar_engraver"
     
    }
    \context {
        \Staff
        \remove "Time_signature_engraver"
        \remove "Clef_engraver"
    }
   
    \context {
      \Lyrics
     
      \remove "Hyphen_engraver"
      \remove "Lyric_engraver"
     
      \accepts "fly"
      \accepts "standard"
      \accepts "dummy"
    }
       
   
    \context {
      \name standard
      \type "Engraver_group"     
      \consists "Bar_engraver"
      \consists "Lyric_engraver"
      \consists "Hyphen_engraver"
     
      \override LyricText.self-alignment-X = #0     
      \alias Lyrics     
    }
   
    \context {
      \name fly
      \type "Engraver_group"           
      \consists "Lyric_engraver"
      \consists "Hyphen_engraver"
     
      \override LyricText.self-alignment-X = #-1
      \override LyricSpace.minimum-distance = #.6
      \override BarLine.bar-extent = #'(0 . 0)
      \alias Lyrics
    }
   
    \context {     
      \name dummy
      \type "Engraver_group"     
      \alias Lyrics
    }   
  }
}



xr

  • Gast
Re: vom Grob NoteColumn einen Lyrics Grob finden
« Antwort #14 am: Montag, 27. Februar 2017, 11:06 »
Ich habe noch zwei weitere Lösungsansätze.

Der erste ist, mehrere Phrasing_slur_engraver zu registrieren mit:
\layout  {     
        \context {
            \Voice
            \consists "Phrasing_slur_engraver"
            \consists "Phrasing_slur_engraver"
            \consists "Phrasing_slur_engraver"
            \override PhrasingSlur.avoid-slur = #'inside   
        }
    }

Beispiel:

\version "2.18.2"

#(define counter 0)

#(define (shape-slurs grob)
   
    (let* (
            ;; original ControlPoints
            (cps (ly:slur::calc-control-points grob)))
       
         ; shift Control-Points x and y by counter
         (set! cps (map
                    (lambda (xy)
                        (cons (+ (car xy) counter) (+ (cdr xy) counter))
                        )
                    cps)
         )

        (ly:grob-set-property! grob 'control-points cps)
        ; kill grob nr 3
        (if (= counter 3)
            (ly:grob-suicide! grob)
            )
        (set! counter (+ counter 1))
    )   
)

shapeSlur =
#(define-music-function (parser location)
    ()
   #{     
      \override Staff.PhrasingSlur.cross-staff = ##t   
      \override Staff.PhrasingSlur.after-line-breaking = #shape-slurs
  #})

 
txtB = {
    \lyricsto melody {
      Ut enim ad minim veniam,  quis nostrud exercitation ullamco
    laboris nisi ut aliquid ex ea commodi consequat. Quis aute
    }
}

noten = 
\relative c'' {
    \shapeSlur
    c1 c c c \break
    c c c  c
    c \(c c c
    c c c\) c
}

\score {
<<   
    \new Staff
     
    \new Voice = "melody"
        \noten
    \new Lyrics
        \txtB
>>   

    \layout  {     
        \context {
            \Voice
            \consists "Phrasing_slur_engraver"
            \consists "Phrasing_slur_engraver"
            \consists "Phrasing_slur_engraver"
            \override PhrasingSlur.avoid-slur = #'inside   
        }
    }
}

Hier wird jeder Phrasierungsbogen 4x gesetzt. Die Phrasierungsbögen können mit Scheme abgefangen und wieder gelöscht werden.
Auf diese Art ist es möglich, gleichzeitig mehrere Phrasierungsbögen zu setzen.
Allerdings scheinen mir in der Zählzeit versetzte Bögen einen komplizierten Rattenschwanz an Abfragen im Code nach sich zu ziehen.
Und den Vorteil, den Phrasierungsbögen haben, nämlich dass sie Kollisionen vermeiden, hat man mit der Einstellung \override Staff.PhrasingSlur.cross-staff = ##t  ohnehin schon aufgegeben.

Daher werde ich jetzt wohl mal einen zweiten Lösungsansatz verfolgen:
Direktes Zeichnen der Bögen in einem Markup.

z.B.
samplePath =
  #'((moveto 0 0)
     (lineto 0 0)
     (curveto 0 0 5 3.3 10 1 )
     (curveto 10 1 5 3 0 0 )
     (closepath)
     )
%% und einfügen mit:
\markup  { \override #'(filled . #t) \path #0.1 #samplePath  }

Ich werde jetzt mal schauen, ob und wie ich die Punkte berechnen kann.

Könnte man vielleicht eigene Spanner erzeugen und mit zwei Befehlen Anfang und Ende eines Spanners in den VerticalAxisGroups eintragen, an denen sich dann die ControlPoints einer Kurve orientieren lassen?

Gruß,
Xaver