Zusätzlichen Slur im Engraver erzeugen

Begonnen von eichhofener, Montag, 1. Mai 2023, 13:30

« vorheriges - nächstes »

eichhofener

Liebe Forumsleser!

Nachdem mein Vorhaben, in meinen Banjotabulaturen bei Slides, Hammer-Ons und Pull-Offs die Saite beizubehalten, gut funktioniert (siehe kein Saitenwechsel im Glissando), versuche ich nun zur weiteren Optimierung der Eingabe den umgekehrten Weg zu programmieren.

Hintergrund: Beim Clawhammer-Spiel ist es üblich die gleiche Saite nicht zweimal hintereinander zu spielen. Insbesondere muss der Off-Beat immer mit dem Daumen der rechten Hand gespielt werden.
Falls das doch anders nötig wäre, behilft man sich mit der linken Hand und spielt einen Hammer-on oder einen Pull-Off.
Das heißt, es ist möglich aus den Notenwerten und der gespielten Saite automatisch zu erkennen, ob ein Hammer-On oder ein Pull-Off zum Einsatz kommen soll.

Beispiele:
- b8(=Bund 0, Saite 2) g8(=Bund 0, Saite 3) kann regulär gespielt werden (Mittelfinger->Daumen)
- g8(=Bund 0, Saite 3) a8(=Bund 2, Saite 3) muss mit Hammer-On gespielt werden
- a8(=Bund 2, Saite 3) g8(=Bund 0, Saite 3) muss mit Pull-Off gespielt werden
- g8(=Bund 0, Saite 3) b8(=Bund 0, Saite 2) muss mit Alternate-String-Pull-Off gespielt werden, weil der Daumen nur höhere Saiten spielen kann.

Um dies umzusetzen muss ich wissen, ob eine Note auf dem On-Beat oder dem Off-Beat steht. Also brauche ich Zugriff auf das Property measurePosition, kann die Logik m.E. also wieder nicht in einer music-function implementieren (jedenfalls nicht ohne die Berechnung der Taktpositionen nachzuprogrammieren), sondern muss es in einem Engraver machen.

In diesem Engraver müsste ich dann ggf. Slurs (für Hammer-On / Pull-Off) erzeugen, für die in der Music-Expression keine Slur-Events angelegt waren.

Leider gelingt mir das nicht und ich finde auch kein entsprechendes Beispiel in den Dokumentationsquellen.

Das ist mein minimalisierter Versuch (noch ohne jede Erkennungslogik), der aber nicht funktioniert:
\version "2.24.0"

#(define (create-slur-engraver context)
( let
  ( ( make-slur? 0 )
    ( attach-to-event #f)
    ( grob-slur #f)
  )
;  ( ly:message "context=~s" context )
  (
    make-engraver
    ( listeners  ; information that will be processed in acknowledger
      ( ( note-event engraver event )
        ( ly:message ">>> note-event")
        ( set! attach-to-event event)
        ( when (= make-slur? 0)
          (set! make-slur? 1 )
    )))
   
    ( ( process-music engraver )
      (ly:message ">>> process-music")
    )
   
    ( acknowledgers
      ( ( slur-interface engraver grob source-engraver)
        ( ly:message ">>> ack-slur")
      )

      ( ( tab-note-head-interface engraver grob source-engraver)
        ( ly:message ">>> ack-tab-note-head ~s" make-slur?)
        ( when (= make-slur? 2)
          (ly:engraver-announce-end-grob engraver grob-slur attach-to-event )
          (ly:spanner-set-bound! grob-slur 1 grob)
          (set! make-slur? -1 )
        )
        ( when (= make-slur? 1)
          (set! grob-slur (ly:engraver-make-spanner engraver 'Slur attach-to-event ))
          (ly:grob-set-property! grob-slur 'direction 1)
          (ly:spanner-set-bound! grob-slur -1 grob)
           (set! make-slur? 2)
        )
      )
    )
)))

\new TabStaff \with {
  \consists #create-slur-engraver
  stringTunings=\stringTuning <g' c g c' d'>
  \tabFullNotation
}
%\displayMusic
{
  g8 a
}


Ich gebe zu, dass mein Vorhaben in gewisser Weise schon Kleinkram ist, aber die Scheme-Programmierung macht ja auch Spaß und wenn jemand ohne großen Aufwand einen Hinweis geben kann, wäre ich dankbar.

Viele Grüße
~eichhofener

juergen74

Hallo,

der zusätzliche Code ist aus dem Regressiontest "scheme-text-spanner.ly":

\version "2.24.0"

#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
       (ly:spanner-set-bound! spanner LEFT item)
       (ly:spanner-set-bound! spanner RIGHT item)))


#(define (create-slur-engraver context)
   ( let
     ( ( make-slur? 0 )
       ( attach-to-event #f)
       ( grob-slur #f)
       )
     ;  ( ly:message "context=~s" context )
     (
       make-engraver
       ( listeners  ; information that will be processed in acknowledger
         ( ( note-event engraver event )
           ( ly:message ">>> note-event")
           ( set! attach-to-event event)
           ( when (= make-slur? 0)
             (set! make-slur? 1 )
             )))

       ( ( process-music engraver )
         (ly:message ">>> process-music")
         )

       ( acknowledgers
         ( ( slur-interface engraver grob source-engraver)
           ( ly:message ">>> ack-slur")
           )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
         ((note-column-interface engraver grob source-engraver)
          (if (ly:spanner? grob-slur)
              (begin
               (ly:grob-set-property! grob-slur 'extra-offset '(0 . -0.2))
               (ly:pointer-group-interface::add-grob grob-slur 'note-columns grob)
               (add-bound-item grob-slur grob))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

         ( ( tab-note-head-interface engraver grob source-engraver)
           ( ly:message ">>> ack-tab-note-head ~s" make-slur?)
           ( when (= make-slur? 2)
             (ly:engraver-announce-end-grob engraver grob-slur attach-to-event )
             ;(ly:spanner-set-bound! grob-slur 1 grob)
             (set! make-slur? -1 )
             )
           ( when (= make-slur? 1)
             (set! grob-slur (ly:engraver-make-spanner engraver 'Slur attach-to-event ))
             (ly:grob-set-property! grob-slur 'direction 1)
             ;(ly:spanner-set-bound! grob-slur -1 grob)
           
             (set! make-slur? 2)
             )
           )
         )
       )))

\new TabStaff \with {
  \consists #create-slur-engraver
  stringTunings=\stringTuning <g' c g c' d'>
  %\tabFullNotation
}
%\displayMusic
{
  g8 a
}



Grüße, Jürgen.

eichhofener