bend.ly - please test and comment

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

bend.ly - please test and comment

Marc Hohl
Hello tablature users group,

here is my first attempt to bends.
I have made some changes, so I can cover most of the cases David has
sent to us some time ago.

When version 2.13.4 will be released, everything will be fine; in the
meantime
you'll probably have to \include "tablature.ly" - otherwise there will
be spurious
stems and stuff in the tablature.

What's important: please test the commands, fiddle around with the values
defined in the first few lines - I hope the variable names are
self-explanatory;
if not, call me.

The syntax "problem" is not relevant at this early stage, but I would
like to
simplify the structure; for example, the callback should recognize two
consecutive calls automagically, as in

 \bendOn c4 ( d )( e )( c ) \bendOff

the same holds for ties

 \bendOn c2 ( d ) ~ d ( c ) \bendOff

would definitely be better than

  \bendOn c2 ( \holdBend ) ~ d ( c ) \bendOff

And if there is a possibility to check whether a slur points to a grace
note or not,
I could get rid of the distinction between \preBend and \preBendOnly
(silly name, you
can guess which commmand I'd like to drop :-)

Ok, so much for now, have fun!

Marc

%
% bend.ly
%
% preliminary tests for drawing bends
% 2009-08-13
%
% Marc Hohl
%
% TODO:
% - draw dashed line for \holdBend
% - enable consecutive bend ups
% - simplify \preBend and \holdBend usage
% - ...

#(display "\n\nbend.ly ─ 2009-08-13\n\n")

\version "2.13.3"

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

%%% sizes and values (to be changed/adapted):

% the line thickness of bends and stuff:
#(define bend-line-thickness 0.1)

% the height of pointed slurs is fixed regardless of its width
% (TODO: should this be changed?):
#(define pointed-slur-height 2.0)

% the linear amount of the bend arrow (TODO: find a better name?)
#(define bend-ratio 0.35)

% the distance between the topmost tablature line and the arrow head
#(define bend-dy 2.75)

% the height of the bend arrow head:
#(define bend-arrow-height 1.25)

% the width of the arrow head base:
#(define bend-arrow-width 0.8)

% the distance between the tablature line where a bend starts
% and the starting point in vertical direction:
#(define bend-y-offset 0.35)

%%% internal commands
#(define-public (quarterdiff->string quarterdiff)
  (let ((wholesteps (floor (/ quarterdiff 4))))

       (string-append (case wholesteps
                            ((0) "")
                            (else (number->string wholesteps)))
                      (case (modulo quarterdiff 4)
                            ((1) "¼")
                            ((2) "½")
                            ((3) "¾")
                            (else "")))))

%%% markup commands
#(define-markup-command (pointedSlur layout props thickness bx by mx my ex ey)
  (number? number? number? number? number? number? number?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto stroke" thickness bx by mx my ex ey))))

#(define-markup-command (drawBendArrow layout props
  thickness begin-x middle-x end-x begin-y end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f ~f ~f ~f ~f curveto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill"
                        thickness
                        begin-x begin-y
                        middle-x begin-y
                        middle-x begin-y end-x begin-y end-x arrow-y
                        arrow-lx arrow-y
                        end-x end-y
                        arrow-rx arrow-y)
            #:hspace 0
            #:translate (cons (- end-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawHoldBend layout props
  thickness begin-x end-x line-y)
  (number? number? number? number?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke" thickness begin-x line-y end-x line-y))))

#(define-markup-command (drawHoldBendWithArrow layout props
  thickness begin-x begin-y end-x end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke"
                        thickness
                        begin-x begin-y
                        begin-x arrow-y
                        arrow-lx arrow-y
                        begin-x end-y
                        arrow-rx arrow-y
                        begin-x end-y
                        end-x end-y)
            #:hspace 0
            #:translate (cons (- begin-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawHoldBendArrowOnly layout props
  thickness begin-x begin-y end-x end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill"
                        thickness
                        begin-x begin-y
                        begin-x arrow-y
                        arrow-lx arrow-y
                        begin-x end-y
                        arrow-rx arrow-y)
            #:hspace 0
            #:translate (cons (- begin-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawDashedLine layout props
  thickness begin-x end-x line-y)
  (number? number? number? number?)
  ;; TODO: draws a full line instead of a dashed line
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke"
                        thickness begin-x line-y end-x line-y))))

%%% callbacks

#(define-public (slur::draw-pointed-slur grob)
  (let* (;;(pointed-slur-height 2.0)
         ;;(bend-line-thickness 0.1)
         (control-points (ly:grob-property grob 'control-points))
         (direction (ly:grob-property grob 'direction))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (begin-x (car left-point))
         (begin-y (cdr left-point))
         (end-x (car right-point))
         (end-y (cdr right-point))
         (middle-x (/ (+ begin-x end-x) 2))
         (middle-y (/ (+ begin-y end-y) 2))
         (normal-x (* direction (- begin-y end-y)))
         (normal-y (* direction (- end-x begin-x)))
         (normal-length (sqrt (+ (* normal-x normal-x)
                                 (* normal-y normal-y))))
         (point-x (+ middle-x (* pointed-slur-height
                                 (/ normal-x normal-length))))
         (point-y (+ middle-y (* pointed-slur-height
                                 (/ normal-y normal-length)))))

         (grob-interpret-markup grob
                                (make-pointedSlur-markup bend-line-thickness
                                  begin-x begin-y point-x point-y end-x end-y))))

#(define-public (slur::draw-bend-arrow grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-ratio 0.35)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         ;;(bend-y-offset 0.35)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position) 2)
                        staff-space)
                     bend-y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- end-x (/ bend-arrow-width 2)))
         (arrow-rx (+ end-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (middle-x (+ begin-x (* bend-ratio (- end-x begin-x))))
         (bend-amount (quarterdiff->string quarterdiff)))

        (if (< quarterdiff 0)
            ;; bend down
            (let* ((y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
                   (temp begin-y))

                  (set! begin-y end-y) ;; swap begin-y/end-y
                  (set! end-y (+ temp y-offset))
                  (set! arrow-y (+ end-y bend-arrow-height))
                  (set! bend-amount "")
                  (ly:grob-set-property! right-tab-note-head 'stencil
                                         (lambda (grob) (parenthesize-tab-note-head grob))))
            ;; bend up
            (let* ((x-offset (/ (cdr (ly:grob-extent left-tab-note-head left-tab-note-head X))
                                2)))

                  (set! begin-x (+ begin-x x-offset))
                  (ly:grob-set-property! right-tab-note-head 'transparent #t)))
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawBendArrow-markup
                                 bend-line-thickness
                                 begin-x middle-x end-x begin-y end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (slur::draw-pre-bend-hold grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         ;;(bend-y-offset 0.35)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position)
                           2)
                        staff-space)
                     y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- begin-x (/ bend-arrow-width 2)))
         (arrow-rx (+ begin-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (bend-amount (quarterdiff->string quarterdiff)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawHoldBendWithArrow-markup
                                 bend-line-thickness
                                 begin-x begin-y
                                 end-x end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (slur::draw-pre-bend-only grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position)
                           2)
                        staff-space)
                     y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- begin-x (/ bend-arrow-width 2)))
         (arrow-rx (+ begin-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (bend-amount (quarterdiff->string quarterdiff)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawHoldBendArrowOnly-markup
                                 bend-line-thickness
                                 begin-x begin-y
                                 end-x end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (tie::draw-hold-bend grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-tab-note-head (ly:spanner-bound grob LEFT))
         (right-tab-note-head (ly:spanner-bound grob RIGHT))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (begin-x (car left-point))
         (end-x (car right-point))
         (line-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        (grob-interpret-markup grob
                               (make-drawDashedLine-markup
                                 bend-line-thickness
                                 begin-x end-x line-y))))

%%% music functions

bendOn = {
  \override Voice.Slur #'stencil = #slur::draw-pointed-slur
  \override TabVoice.Slur #'stencil = #slur::draw-bend-arrow
}

bendOff = {
  \revert Voice.Slur #'stencil
  \override TabVoice.Slur #'stencil = ##f
  %\override TabVoice.Slur #'direction = #UP
}

bendGrace = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override Voice.Stem #'stencil = ##f
    \once \override Voice.Stem #'direction = #DOWN
    \once \override Voice.Slur #'direction = #UP
    \grace $note
  #})

preBendOnly = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override TabVoice.Slur #'stencil = #slur::draw-pre-bend-only
    \once \override TabStaff.ParenthesesItem #'transparent = ##t
    \parenthesize $note
  #})

preBend = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override TabVoice.Slur #'stencil = #slur::draw-pre-bend-hold
    \once \override TabStaff.ParenthesesItem #'transparent = ##t
    \parenthesize $note
  #})

holdBend = #(define-music-function (parser location) ()
  #{
    \once \override TabVoice.Tie #'stencil = #tie::draw-hold-bend
  #})

%% the test (finally!)

test = \relative c'' {
  \bendOn
  % First, some bends to see if they work from the topmost to the lowest string
  c4 ( d )( c2 )
  c4\2 ( d\2 )( c2\2 )
  c4\3 ( des\3 )( c2\3 ) \break
  c,4\4 ( d\4 )( c2\4 )
  c4\5 ( d\5 )( c2\5 )
  c4\6 ( d\6 )( c2\6 ) \break
  % is the bend amount displayed correctly? (should be ½ in both cases)
  c4 ( cis) d ( es )
  % grace notes
  \bendGrace c8(  d4 )( c4 ) r2
  % the distinction between \preBendOnly and \preBend is not very
  % elegant here, I hope that there will be a better solution...
  \bendGrace { \preBendOnly c8( } d2)  r2
  \bendGrace { \preBend c8( d)( } c2)  r2
  c4 ( es) e\2 ( gis\2 ) \break
  % quarter tone bends are not yet supported as they should be, but
  % the bend amount is calculated correctly ;-)
  c,4 ( cih ) c4 ( cisih )
  % I hope that in future releases the tie will recognize automagically
  % that he ties to a note which is bent, but I don't know how (yet).
  \bendGrace c'8 ( \holdBend d2 ) ~ d2 ( c1 )
  \bendOff
  % switching bends off works apparently
  c,4 ( e ) c4 ( f )
  c'4 ( b ) c4 ( a )
}

\score {
  <<
    \new Staff {
      \new Voice {
        \clef "G_8"
        \test
      }
    }
    \new TabStaff {
      \new TabVoice {
        \clef "tab"
        \set TabStaff.stringTunings = #guitar-seven-string-tuning
        \test
      }
    }
  >>
}
Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Federico Bruni
Marc Hohl wrote:

>  
> When version 2.13.4 will be released, everything will be fine; in the
> meantime
> you'll probably have to \include "tablature.ly" - otherwise there will
> be spurious
> stems and stuff in the tablature.
>
> What's important: please test the commands, fiddle around with the values
> defined in the first few lines - I hope the variable names are
> self-explanatory;
> if not, call me.
>
I'm trying to test it, but I have an error message I can't understand.
I attach the .ly file.
Below it's the error message..

============================================================================

GNU LilyPond 2.13.3
Processing `bend-test.ly'
Parsing...
/home/fede/lilypond/usr/share/lilypond/current/ly/tablature.ly:86:1:
error: GUILE signaled an error for the expression beginning here
#
  (add-new-clef "moderntab" "markup.moderntab" 0 0 0)
Unbound variable: add-new-clef


bend.ly ─ 2009-08-13

/home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:452:39:
error: GUILE signaled an error for the expression beginning here
         \set TabStaff.stringTunings = #
                                        guitar-seven-string-tuning
Unbound variable: guitar-seven-string-tuning
warning: unknown clef type `moderntab'
warning: supported clefs: C F G G2 alto baritone bass french
hufnagel-do-fa hufnagel-do1 hufnagel-do2 hufnagel-do3 hufnagel-fa1
hufnagel-fa2 medicaea-do1 medicaea-do2 medicaea-do3 medicaea-fa1
medicaea-fa2 mensural-c1 mensural-c2 mensural-c3 mensural-c4
mensural-f mensural-g mezzosoprano neomensural-c1 neomensural-c2
neomensural-c3 neomensural-c4 percussion petrucci-c1 petrucci-c2
petrucci-c3 petrucci-c4 petrucci-c5 petrucci-f petrucci-f3 petrucci-f4
petrucci-g soprano subbass tab tenor treble varbaritone vaticana-do1
vaticana-do2 vaticana-do3 vaticana-fa1 vaticana-fa2 violin
warning: unknown clef type `moderntab'
warning: supported clefs: C F G G2 alto baritone bass french
hufnagel-do-fa hufnagel-do1 hufnagel-do2 hufnagel-do3 hufnagel-fa1
hufnagel-fa2 medicaea-do1 medicaea-do2 medicaea-do3 medicaea-fa1
medicaea-fa2 mensural-c1 mensural-c2 mensural-c3 mensural-c4
mensural-f mensural-g mezzosoprano neomensural-c1 neomensural-c2
neomensural-c3 neomensural-c4 percussion petrucci-c1 petrucci-c2
petrucci-c3 petrucci-c4 petrucci-c5 petrucci-f petrucci-f3 petrucci-f4
petrucci-g soprano subbass tab tenor treble varbaritone vaticana-do1
vaticana-do2 vaticana-do3 vaticana-fa1 vaticana-fa2 violin
Interpreting music...
warning: type check for `stringTunings' failed; value `#<unspecified>'
must be of type `list'
[8][16]
Preprocessing graphical objects...
Interpreting music...
Interpreting music...
Preprocessing graphical objects...
MIDI output to `bend-test.midi'...
Solving 1 page-breaking chunks...[1: 1 pages]
Drawing
systems.../home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
In expression (parenthesize-tab-note-head grob):
/home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
Unbound variable: parenthesize-tab-note-head

\version "2.13.3"
\include "tablature.ly"
\include "bend.ly"
\include "english.ly"



upper=  \relative c' {
  \time 4/4
  \key e \minor
  \bendOn
  b4.  d8( dqs)  e4  a,8 ~ |
  a4.  d8( dqs)  e4  b8  ~ |
  \bendOff
 
}


lower=  \relative c {
  b4  ds  b  ds |
  b4  ds  b  ds |
}


\score {
  \new StaffGroup <<
    \new Staff = "guitar" <<
      \context Voice = "upper guitar" { \clef "G_8" \voiceOne  \override Voice.StringNumber #'transparent = ##t  \upper }
      \context Voice = "lower guitar" { \clef "G_8" \voiceTwo  \override Voice.StringNumber #'transparent = ##t  \lower }
    >>
    \new TabStaff = "tab" <<
      \context TabVoice = "upper tab" { \clef "moderntab" \voiceOne \upper }
      \context TabVoice = "lower tab" { \clef "moderntab" \voiceTwo \lower }
    >>
  >>
 
\midi {
    \context {
      \Score tempoWholesPerMinute = #(ly:make-moment 120 4)
    }
  }
 
  \layout {
  }

}
Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Marc Hohl
Federico Bruni schrieb:

> Marc Hohl wrote:
>>  
>> When version 2.13.4 will be released, everything will be fine; in the
>> meantime
>> you'll probably have to \include "tablature.ly" - otherwise there
>> will be spurious
>> stems and stuff in the tablature.
>>
>> What's important: please test the commands, fiddle around with the
>> values
>> defined in the first few lines - I hope the variable names are
>> self-explanatory;
>> if not, call me.
>>
> I'm trying to test it, but I have an error message I can't understand.
> I attach the .ly file.
> Below it's the error message..
>
> ============================================================================
>
>
> GNU LilyPond 2.13.3
> Processing `bend-test.ly'
> Parsing...
> /home/fede/lilypond/usr/share/lilypond/current/ly/tablature.ly:86:1:
> error: GUILE signaled an error for the expression beginning here
> #
>  (add-new-clef "moderntab" "markup.moderntab" 0 0 0)
> Unbound variable: add-new-clef
>
>
> bend.ly ─ 2009-08-13
>
> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:452:39:
> error: GUILE signaled an error for the expression beginning here
>         \set TabStaff.stringTunings = #
>                                        guitar-seven-string-tuning
> Unbound variable: guitar-seven-string-tuning
> warning: unknown clef type `moderntab'
Hi Federico,

these errors are due to the fact that the tablature features (including
the moderntab clef and the
definitions for a seven-string guitar) are not included in 2.13.3 -
either you change your file to
six strings (by ommitting the \set TabStaff.stringTunings = ... line
completely) and the
calligraphic tab clef, or you just ignore the messages, because lilypond
compiles in either case.
> [...]
> Interpreting music...
> warning: type check for `stringTunings' failed; value `#<unspecified>'
> must be of type `list'
This error comes from the missing definition for seven strings...

> [8][16]
> Preprocessing graphical objects...
> Interpreting music...
> Interpreting music...
> Preprocessing graphical objects...
> MIDI output to `bend-test.midi'...
> Solving 1 page-breaking chunks...[1: 1 pages]
> Drawing
> systems.../home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
> In expression (parenthesize-tab-note-head grob):
> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
> Unbound variable: parenthesize-tab-note-head
Sorry, this is a little bug in tablature.ly; please search the line
where you can find

#(define (parenthesize-tab-note-head grob)

and change it to

#(define-public (parenthesize-tab-note-head grob)

Then (hopefully) everything will be ok.

Sorry for the inconvenience and thank you for testing!

Marc



Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Federico Bruni
Hi Marc,

thanks for your answer

Marc Hohl wrote:

>
>> [...]
>> Interpreting music...
>> warning: type check for `stringTunings' failed; value `#<unspecified>'
>> must be of type `list'
> This error comes from the missing definition for seven strings...
>> [8][16]
>> Preprocessing graphical objects...
>> Interpreting music...
>> Interpreting music...
>> Preprocessing graphical objects...
>> MIDI output to `bend-test.midi'...
>> Solving 1 page-breaking chunks...[1: 1 pages]
>> Drawing
>> systems.../home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
>> In expression (parenthesize-tab-note-head grob):
>> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
>> Unbound variable: parenthesize-tab-note-head
> Sorry, this is a little bug in tablature.ly; please search the line
> where you can find
>
> #(define (parenthesize-tab-note-head grob)
>
> and change it to
>
> #(define-public (parenthesize-tab-note-head grob)
>
> Then (hopefully) everything will be ok.
>

I can't find this line in my tablature.ly
Could you please send me your tablature.ly?


Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Marc Hohl
Federico Bruni schrieb:

> Hi Marc,
>
> thanks for your answer
>
> Marc Hohl wrote:
>>
>>> [...]
>>> Interpreting music...
>>> warning: type check for `stringTunings' failed; value
>>> `#<unspecified>' must be of type `list'
>> This error comes from the missing definition for seven strings...
>>> [8][16]
>>> Preprocessing graphical objects...
>>> Interpreting music...
>>> Interpreting music...
>>> Preprocessing graphical objects...
>>> MIDI output to `bend-test.midi'...
>>> Solving 1 page-breaking chunks...[1: 1 pages]
>>> Drawing
>>> systems.../home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
>>> In expression (parenthesize-tab-note-head grob):
>>> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:244:57:
>>> Unbound variable: parenthesize-tab-note-head
>> Sorry, this is a little bug in tablature.ly; please search the line
>> where you can find
>>
>> #(define (parenthesize-tab-note-head grob)
>>
>> and change it to
>>
>> #(define-public (parenthesize-tab-note-head grob)
>>
>> Then (hopefully) everything will be ok.
>>
>
> I can't find this line in my tablature.ly
> Could you please send me your tablature.ly?
>
>
>
Yes, here you are.

Marc


%%%% tablature.ly
%%%%
%%%% source file of the GNU LilyPond music typesetter
%%%%
%%%% (c) 2009 Marc Hohl <[hidden email]>


% some publications use the triangle-shaped note head
% for palm mute, so here we go:
palmMuteOn = {
  \override NoteHead #'style = #'do
}

palmMuteOff = {
  \revert NoteHead #'style
}

% for single notes (even in chord constructs <...>),
% or grouped notes in {...}
palmMute =
#(define-music-function (parser location note) (ly:music?)
  ;; are we inside a <...>?
  (if (eq? (ly:music-property note 'name) 'NoteEvent)
      ;; yes -> add a tweak
      (begin (set! (ly:music-property note 'tweaks)
                    (acons 'style 'do (ly:music-property note 'tweaks)))
      note)
      ;; no -> use predefined commands to switch to triangle-shaped note heads
      #{
        \palmMuteOn
        $note
        \palmMuteOff
      #}))


% dead notes are marked with a cross-shape note head,
% both in normal notation and in tablature:
deadNotesOn = {
  \override TabNoteHead #'style = #'cross
  \override NoteHead #'style = #'cross
}

deadNotesOff = {
  \revert TabNoteHead #'style
  \revert NoteHead #'style
}

% for single notes (even in chord constructs <...>),
% or grouped notes in {...}
deadNote =
#(define-music-function (parser location note) (ly:music?)
  ;; are we inside a <...>?
  (if (eq? (ly:music-property note 'name) 'NoteEvent)
      ;; yes -> add a tweak
      (begin (set! (ly:music-property note 'tweaks)
                    (acons 'style 'cross (ly:music-property note 'tweaks)))
       note)
       ;; no -> use predefined commmands for changing
       ;; note head and tablature fret signs
       #{
         \deadNotesOn
         $note
         \deadNotesOff
       #}))

% for more control over glyph-name calculations,
% use custom callback with tab noteheads which will ignore
% 'style = 'do
#(define-public (tab-note-head::calc-glyph-name grob)
  (let ((style (ly:grob-property grob 'style)))
   (case style
      ((cross) "2cross"))))

% ensure we only call notehead callback when
% 'style = 'cross
#(define-public (tab-note-head::whiteout-if-style-set grob)
  (let ((style (ly:grob-property grob 'style)))
       (if (and (symbol? style)
                (eq? style 'cross))
           (stencil-whiteout (ly:note-head::print grob))
           (ly:text-interface::print grob))))

% definitions for the "moderntab" clef:
% the "moderntab" clef will be added to the list of known clefs,
% so it can be used as any other clef:
%
% \clef "moderntab"
%
#(add-new-clef "moderntab" "markup.moderntab" 0 0 0)

% this function decides which clef to take
#(define-public (clef::print-modern-tab-if-set grob)
  (let ((glyph (ly:grob-property grob 'glyph)))
       ;; which clef is wanted?
       (if (string=? glyph "markup.moderntab")
           ;; if it is "moderntab", we'll draw it
           (let* ((staff-symbol (ly:grob-object grob 'staff-symbol))
                  (line-count   (ly:grob-property staff-symbol 'line-count))
                  (staff-space  (ly:grob-property staff-symbol 'staff-space 1)))
                 (grob-interpret-markup grob (make-customTabClef-markup line-count staff-space)))
           ;; otherwise, we simply use the default printing routine
           (ly:clef::print grob))))

% define sans serif-style tab-Clefs as a markup:
#(define-markup-command (customTabClef layout props num-strings staff-space) (integer? number?)
  (define (square x) (* x x))
  (let* ((scale-factor (/ staff-space 1.5))
         (font-size (- (* num-strings 1.5 scale-factor) 7))
         (base-skip (* (square (+ (* num-strings 0.195) 0.4)) scale-factor)))

        (interpret-markup layout props
           (markup #:vcenter #:bold
                   #:override (cons 'font-family 'sans)
                   #:fontsize font-size
                   #:override (cons 'baseline-skip base-skip)
                   #:left-align #:center-column ("T" "A" "B")))))

% if the stems are drawn, it is nice to have a double stem for
% (dotted) half notes to distinguish them from quarter notes:
#(define-public (tabvoice::draw-double-stem-for-half-notes grob)
  (let ((stem (ly:stem::print grob)))

       ;; is the note a (dotted) half note?
       (if (= 1 (ly:grob-property grob 'duration-log))
           ;; yes -> draw double stem
           (ly:stencil-combine-at-edge stem X RIGHT stem 0.5)
           ;; no -> draw simple stem
           stem)))

% as default, the glissando line between fret numbers goes
% upwards, here we have a function to correct this behavior:
#(define-public (glissando::calc-tab-extra-dy grob)
  (let* ((original (ly:grob-original grob))
         (left-bound (ly:spanner-bound original LEFT))
         (right-bound (ly:spanner-bound original RIGHT))
         (left-pitch (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch)))

    (if (< (ly:pitch-semitones right-pitch) (ly:pitch-semitones left-pitch))
        -0.75
         0.75)))

% for ties in tablature, fret numbers that are tied to should be invisible,
% except for 'tied to' numbers after a line break; these will be parenthesized
% (thanks to Neil for his solution):
#(define-public (parenthesize-tab-note-head grob)
  ;; Helper function to parenthesize tab noteheads,
  ;; since we can't use ParenthesesItem at this stage
  ;; This is basically the same as the C++ function
  ;; in accidental.cc, converted to Scheme
  (let* ((font (ly:grob-default-font grob))
         (open (stencil-whiteout (ly:font-get-glyph font "accidentals.leftparen")))
         (close (stencil-whiteout (ly:font-get-glyph font "accidentals.rightparen")))
         (me (ly:text-interface::print grob)))
        (ly:stencil-combine-at-edge
         (ly:stencil-combine-at-edge
          me
          X
          LEFT
          open)
         X
         RIGHT
         close)))

% ParenthesesItem doesn't work very well for TabNoteHead, since
% the parentheses are too small and clash with the staff-lines
% Define a callback for the 'stencils property which will tweak
% the parentheses' appearance for TabNoteHead
#(define-public (parentheses-item::calc-tabstaff-parenthesis-stencils grob)
   ;; the grob we want to parenthesize
   (let ((victim (ly:grob-array-ref (ly:grob-object grob 'elements) 0)))
     ;; check whether it's a notehead
     (if (grob::has-interface victim 'note-head-interface)
         (begin
           ;; tweak appearance before retrieving list of stencils '(left-paren right-paren)
           (ly:grob-set-property! grob 'font-size -2)
           (ly:grob-set-property! grob 'padding 0)
           ;; apply whiteout to each element of the list
           (map stencil-whiteout (parentheses-item::calc-parenthesis-stencils grob)))
         (parentheses-item::calc-parenthesis-stencils grob))))

% the handler for ties in tablature; split ties yield in a parenthesized
% fret number, otherwise the fret number will be invisible.
#(define-public (tie::handle-tab-tie grob)
   (let* ((original (ly:grob-original grob))
          (tied-tab-note-head (ly:spanner-bound grob RIGHT))
          (siblings (if (ly:grob? original)
                        (ly:spanner-broken-into original) '())))

     (if (and (>= (length siblings) 2)
              (eq? (car (last-pair siblings)) grob))
         ;; tie is split -> parenthesize
         (ly:grob-set-property! tied-tab-note-head 'stencil
                                (lambda (grob) (parenthesize-tab-note-head grob)))

         ;; tie is not split -> make fret number invisible
         (ly:grob-set-property! tied-tab-note-head 'transparent #t))))

% repeat ties occur within alternatives in a repeat construct;
% the correspondig fret numbers are shown in parentheses:
#(define-public (repeat-tie::parenthesize-tab grob)
  (let ((tied-tab-note-head (ly:grob-object grob 'note-head)))

        (ly:grob-set-property! tied-tab-note-head 'stencil
                               (lambda (grob) (parenthesize-tab-note-head grob)))))

% a command for switching to the (improved) full notation
tabFullNotation = {
  % time signature
  \revert TabStaff.TimeSignature #'stencil
  % stems (the half note gets a double stem)
  \override TabVoice.Stem #'stencil = #tabvoice::draw-double-stem-for-half-notes
  % beams, dots
  \revert TabVoice.Beam #'stencil
  \revert TabVoice.Dots #'stencil
  \revert TabVoice.Tie #'stencil
  \revert TabVoice.Tie #'after-line-breaking
  \revert TabVoice.RepeatTie #'stencil
  \revert TabVoice.RepeatTie #'after-line-braking
  \revert TabVoice.LaissezVibrerTie #'stencil
  \revert TabVoice.Slur #'stencil
  \revert PhrasingSlur #'stencil
  % tuplet stuff
  \revert TabVoice.TupletBracket #'stencil
  \revert TabVoice.TupletNumber #'stencil
  % dynamic signs
  \revert DynamicText #'transparent
  \revert DynamicTextSpanner #'stencil
  \revert TabVoice.DynamicTextSpanner #'stencil
  \revert TabVoice.Hairpin #'transparent
  % rests
  \revert TabVoice.Rest #'stencil
  \revert TabVoice.MultiMeasureRest #'stencil
  % markups etc.
  \revert TabVoice.Script #'stencil
  \revert TabVoice.TextScript #'stencil
  \revert TabStaff.Arpeggio #'stencil
}

% the defaults for tablature:
\layout {
  \context {
    \TabStaff
    % the clef handler
    \override Clef #'stencil = #clef::print-modern-tab-if-set
    % no time signature
    \override TimeSignature #'stencil = ##f
    % better parentheses in a TabStaff
    \override ParenthesesItem #'stencils = #parentheses-item::calc-tabstaff-parenthesis-stencils
    % no arpeggios
    \override Arpeggio #'stencil = ##f
  }
  \context {
    \TabVoice
    % remove stems, beams, dots and rests ...
    \override Stem #'stencil = ##f
    \override Beam #'stencil = ##f
    \override Dots #'stencil = ##f
    \override Rest #'stencil = ##f
    \override MultiMeasureRest #'stencil = ##f
    % ... all kinds of ties/slurs
    \override Tie  #'stencil = ##f
    \override RepeatTie #'stencil = ##f
    \override LaissezVibrerTie #'stencil = ##f
    \override Slur #'stencil = ##f
    \override PhrasingSlur #'stencil = ##f
    % 'tied to' fret numbers become invisible or parenthesized, respectively)
    \override Tie #'after-line-breaking = #tie::handle-tab-tie
    \override RepeatTie #'after-line-breaking = #repeat-tie::parenthesize-tab
    % ... and all kinds of markups, spanners etc.
    \override TupletBracket #'stencil = ##f
    \override TupletNumber #'stencil = ##f
    \override DynamicText #'transparent = ##t
    \override DynamicTextSpanner #'stencil = ##f
    \override TextSpanner #'stencil = ##f
    \override Hairpin #'transparent = ##t
    \override Script #'stencil = ##f
    \override TextScript #'stencil = ##f
    % the direction for glissando lines will be automatically corrected
    \override Glissando #'extra-dy = #glissando::calc-tab-extra-dy
    % dead notes in tablature and within chord constructs
    \override TabNoteHead #'glyph-name = #tab-note-head::calc-glyph-name
    \override TabNoteHead #'stencil = #tab-note-head::whiteout-if-style-set
  }
}
Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Federico Bruni
In reply to this post by Marc Hohl
Marc Hohl wrote:
> Federico Bruni schrieb:
[...]

>> /home/fede/lilypond/usr/share/lilypond/current/ly/tablature.ly:86:1:
>> error: GUILE signaled an error for the expression beginning here
>> #
>>  (add-new-clef "moderntab" "markup.moderntab" 0 0 0)
>> Unbound variable: add-new-clef
>>
>>
>> bend.ly ─ 2009-08-13
>>
>> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:452:39:
>> error: GUILE signaled an error for the expression beginning here
>>         \set TabStaff.stringTunings = #
>>                                        guitar-seven-string-tuning
>> Unbound variable: guitar-seven-string-tuning
>> warning: unknown clef type `moderntab'
> Hi Federico,
>
> these errors are due to the fact that the tablature features (including
> the moderntab clef and the
> definitions for a seven-string guitar) are not included in 2.13.3 -
> either you change your file to
> six strings (by ommitting the \set TabStaff.stringTunings = ... line
> completely) and the
> calligraphic tab clef, or you just ignore the messages, because lilypond
> compiles in either case.

I commented out the example at the bottom of bend.ly, so no more error
regarding seven-string guitar.
And - stupid me! - I had forgot to add the code for the moderntab clef
in parser-clef.scm

With your tablature.ly now everything works perfect, many thanks!

I'll test it again in the next days and in case send feedback..

Regards,
Federico


Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

Marc Hohl
Federico Bruni schrieb:

> Marc Hohl wrote:
>> Federico Bruni schrieb:
> [...]
>>> /home/fede/lilypond/usr/share/lilypond/current/ly/tablature.ly:86:1:
>>> error: GUILE signaled an error for the expression beginning here
>>> #
>>>  (add-new-clef "moderntab" "markup.moderntab" 0 0 0)
>>> Unbound variable: add-new-clef
>>>
>>>
>>> bend.ly ─ 2009-08-13
>>>
>>> /home/fede/lilypond/usr/share/lilypond/current/ly/bend.ly:452:39:
>>> error: GUILE signaled an error for the expression beginning here
>>>         \set TabStaff.stringTunings = #
>>>                                        guitar-seven-string-tuning
>>> Unbound variable: guitar-seven-string-tuning
>>> warning: unknown clef type `moderntab'
>> Hi Federico,
>>
>> these errors are due to the fact that the tablature features
>> (including the moderntab clef and the
>> definitions for a seven-string guitar) are not included in 2.13.3 -
>> either you change your file to
>> six strings (by ommitting the \set TabStaff.stringTunings = ... line
>> completely) and the
>> calligraphic tab clef, or you just ignore the messages, because
>> lilypond compiles in either case.
>
> I commented out the example at the bottom of bend.ly, so no more error
> regarding seven-string guitar.
> And - stupid me! - I had forgot to add the code for the moderntab clef
> in parser-clef.scm
And I forgot to clearly separate the code definitions from my minimal
example, which can lead to
even more confusion.
>
> With your tablature.ly now everything works perfect, many thanks!
>
> I'll test it again in the next days and in case send feedback..
>
Great! Thank you.

Marc
> Regards,
> Federico
>
>
>



Reply | Threaded
Open this post in threaded view
|

Re: bend.ly - please test and comment

David Stocker-2
In reply to this post by Marc Hohl
Hi Marc, hi everyone,

Great work. This is really exciting.

Just a couple of comments:

   1. It might be good to move the beginning point of the pointed slur
      right about an eighth of a space and the end of the pointed slur
      left by the same amount. This would make the space between the two
      on notes that are bent to and then released more appreciable.
   2. For the example in bar 10, both of the pointed slurs should arch
      under.

I'll fiddle around with some of the settings when I have the opportunity.

Kudos!

David

Marc Hohl wrote:

> Hello tablature users group,
>
> here is my first attempt to bends.
> I have made some changes, so I can cover most of the cases David has
> sent to us some time ago.
>
> When version 2.13.4 will be released, everything will be fine; in the
> meantime
> you'll probably have to \include "tablature.ly" - otherwise there will
> be spurious
> stems and stuff in the tablature.
>
> What's important: please test the commands, fiddle around with the values
> defined in the first few lines - I hope the variable names are
> self-explanatory;
> if not, call me.
>
> The syntax "problem" is not relevant at this early stage, but I would
> like to
> simplify the structure; for example, the callback should recognize two
> consecutive calls automagically, as in
>
> \bendOn c4 ( d )( e )( c ) \bendOff
>
> the same holds for ties
>
> \bendOn c2 ( d ) ~ d ( c ) \bendOff
>
> would definitely be better than
>
>  \bendOn c2 ( \holdBend ) ~ d ( c ) \bendOff
>
> And if there is a possibility to check whether a slur points to a
> grace note or not,
> I could get rid of the distinction between \preBend and \preBendOnly
> (silly name, you
> can guess which commmand I'd like to drop :-)
>
> Ok, so much for now, have fun!
>
> Marc


Reply | Threaded
Open this post in threaded view
|

bend.ly - first corrections

Marc Hohl
David Stocker schrieb:

> Hi Marc, hi everyone,
>
> Great work. This is really exciting.
>
> Just a couple of comments:
>
>   1. It might be good to move the beginning point of the pointed slur
>      right about an eighth of a space and the end of the pointed slur
>      left by the same amount. This would make the space between the two
>      on notes that are bent to and then released more appreciable.
I did so in the latest version; see below.
>   2. For the example in bar 10, both of the pointed slurs should arch
>      under.
Ok, I corrected this, but it looks not perfect yet.
>
> I'll fiddle around with some of the settings when I have the opportunity.
>
> Kudos!
Thank you!

To make life easier for you testers, I split the file in two parts:

bend.ly contains the definitions, bendtest.ly is an example;
so you can easily \include "bend.ly" in your own files (and perhaps
tablature.ly  - I don't know when 2.13.4 will be released).

You can change the values defined at the beginning of bend.ly
to your needs - let me know which values look best.

Marc
>
> David
>


%
% bend.ly
%
% preliminary tests for drawing bends
% 2009-08-13
%
% Marc Hohl
%
% TODO:
% - draw dashed line for \holdBend
% - enable consecutive bend ups
% - simplify \preBend and \holdBend usage
% - ...

#(display "\n\nbend.ly ─ 2009-08-23\n\n")


%%% sizes and values (to be changed/adapted):

% the line thickness of bends and stuff:
#(define bend-line-thickness 0.1)

% the height of pointed slurs is fixed regardless of its width
% (TODO: should this be changed?):
#(define pointed-slur-height 2.0)

% the linear amount of the bend arrow (TODO: find a better name?)
#(define bend-ratio 0.35)

% the distance between the topmost tablature line and the arrow head
#(define bend-dy 2.75)

% the height of the bend arrow head:
#(define bend-arrow-height 1.25)

% the width of the arrow head base:
#(define bend-arrow-width 0.8)

% the distance between the tablature line where a bend starts
% and the starting point in vertical direction:
#(define bend-y-offset 0.35)

%%% internal commands
#(define-public (quarterdiff->string quarterdiff)
  (let ((wholesteps (floor (/ quarterdiff 4))))

       (string-append (case wholesteps
                            ((0) "")
                            (else (number->string wholesteps)))
                      (case (modulo quarterdiff 4)
                            ((1) "¼")
                            ((2) "½")
                            ((3) "¾")
                            (else "")))))

%%% markup commands
#(define-markup-command (pointedSlur layout props thickness bx by mx my ex ey)
  (number? number? number? number? number? number? number?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto stroke" thickness bx by mx my ex ey))))

#(define-markup-command (drawBendArrow layout props
  thickness begin-x middle-x end-x begin-y end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f ~f ~f ~f ~f curveto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill"
                        thickness
                        begin-x begin-y
                        middle-x begin-y
                        middle-x begin-y end-x begin-y end-x arrow-y
                        arrow-lx arrow-y
                        end-x end-y
                        arrow-rx arrow-y)
            #:hspace 0
            #:translate (cons (- end-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawHoldBend layout props
  thickness begin-x end-x line-y)
  (number? number? number? number?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke" thickness begin-x line-y end-x line-y))))

#(define-markup-command (drawHoldBendWithArrow layout props
  thickness begin-x begin-y end-x end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke"
                        thickness
                        begin-x begin-y
                        begin-x arrow-y
                        arrow-lx arrow-y
                        begin-x end-y
                        arrow-rx arrow-y
                        begin-x end-y
                        end-x end-y)
            #:hspace 0
            #:translate (cons (- begin-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawHoldBendArrowOnly layout props
  thickness begin-x begin-y end-x end-y arrow-lx arrow-rx arrow-y outstring)
  (number? number? number? number? number? number? number? number? string?)
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke
                        ~f ~f moveto
                        ~f ~f lineto
                        ~f ~f lineto
                        closepath fill"
                        thickness
                        begin-x begin-y
                        begin-x arrow-y
                        arrow-lx arrow-y
                        begin-x end-y
                        arrow-rx arrow-y)
            #:hspace 0
            #:translate (cons (- begin-x 1.2) (+ end-y 0.5))
            #:fontsize -2
            #:bold #:center-column (outstring))))

#(define-markup-command (drawDashedLine layout props
  thickness begin-x end-x line-y)
  (number? number? number? number?)
  ;; TODO: draws a full line instead of a dashed line
  (interpret-markup layout props
    (markup #:postscript
            (ly:format "~f setlinewidth
                        ~f ~f moveto
                        ~f ~f lineto
                        stroke"
                        thickness begin-x line-y end-x line-y))))

%%% callbacks

#(define-public (slur::draw-pointed-slur grob)
  (let* (;;(pointed-slur-height 2.0)
         ;;(bend-line-thickness 0.1)
         (control-points (ly:grob-property grob 'control-points))
         (direction (ly:grob-property grob 'direction))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (begin-x (+ (car left-point) 0.125)) ;; due to David's proposals
         (begin-y (cdr left-point))
         (end-x (- (car right-point) 0.125)) ;; due to David's proposals
         (end-y (cdr right-point))
         (middle-x (/ (+ begin-x end-x) 2))
         (middle-y (/ (+ begin-y end-y) 2))
         (normal-x (* direction (- begin-y end-y)))
         (normal-y (* direction (- end-x begin-x)))
         (normal-length (sqrt (+ (* normal-x normal-x)
                                 (* normal-y normal-y))))
         (point-x (+ middle-x (* pointed-slur-height
                                 (/ normal-x normal-length))))
         (point-y (+ middle-y (* pointed-slur-height
                                 (/ normal-y normal-length)))))

         (grob-interpret-markup grob
                                (make-pointedSlur-markup bend-line-thickness
                                  begin-x begin-y point-x point-y end-x end-y))))

#(define-public (slur::draw-bend-arrow grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-ratio 0.35)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         ;;(bend-y-offset 0.35)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position) 2)
                        staff-space)
                     bend-y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- end-x (/ bend-arrow-width 2)))
         (arrow-rx (+ end-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (middle-x (+ begin-x (* bend-ratio (- end-x begin-x))))
         (bend-amount (quarterdiff->string quarterdiff)))

        (if (< quarterdiff 0)
            ;; bend down
            (let* ((y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
                   (temp begin-y))

                  (set! begin-y end-y) ;; swap begin-y/end-y
                  (set! end-y (+ temp y-offset))
                  (set! arrow-y (+ end-y bend-arrow-height))
                  (set! bend-amount "")
                  (ly:grob-set-property! right-tab-note-head 'stencil
                                         (lambda (grob) (parenthesize-tab-note-head grob))))
            ;; bend up
            (let* ((x-offset (/ (cdr (ly:grob-extent left-tab-note-head left-tab-note-head X))
                                2)))

                  (set! begin-x (+ begin-x x-offset))
                  (ly:grob-set-property! right-tab-note-head 'transparent #t)))
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawBendArrow-markup
                                 bend-line-thickness
                                 begin-x middle-x end-x begin-y end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (slur::draw-pre-bend-hold grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         ;;(bend-y-offset 0.35)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position)
                           2)
                        staff-space)
                     y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- begin-x (/ bend-arrow-width 2)))
         (arrow-rx (+ begin-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (bend-amount (quarterdiff->string quarterdiff)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawHoldBendWithArrow-markup
                                 bend-line-thickness
                                 begin-x begin-y
                                 end-x end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (slur::draw-pre-bend-only grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-bound (ly:spanner-bound grob LEFT))
         (right-bound (ly:spanner-bound grob RIGHT))
         (left-tab-note-head (ly:grob-property left-bound 'cause))
         (right-tab-note-head (ly:grob-property right-bound 'cause))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (left-pitch  (ly:event-property (event-cause left-bound) 'pitch))
         (right-pitch (ly:event-property (event-cause right-bound) 'pitch))
         (quarterdiff (- (ly:pitch-quartertones right-pitch)
                         (ly:pitch-quartertones left-pitch)))
         (begin-x (car left-point))
         (y-offset (cdr (ly:grob-extent left-tab-note-head left-tab-note-head Y)))
         (begin-y (+ (* (/ (ly:grob-property left-tab-note-head 'staff-position)
                           2)
                        staff-space)
                     y-offset))
         ;; cdr left-point doesn't work, because invisible stems are included
         (end-x (car right-point))
         (end-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy))
         (arrow-lx (- begin-x (/ bend-arrow-width 2)))
         (arrow-rx (+ begin-x (/ bend-arrow-width 2)))
         (arrow-y (- end-y bend-arrow-height))
         (bend-amount (quarterdiff->string quarterdiff)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        ;; draw resulting bend arrow
        (grob-interpret-markup grob
                               (make-drawHoldBendArrowOnly-markup
                                 bend-line-thickness
                                 begin-x begin-y
                                 end-x end-y
                                 arrow-lx arrow-rx arrow-y
                                 bend-amount))))

#(define-public (tie::draw-hold-bend grob)
  (let* (;;(bend-line-thickness 0.1)
         ;;(bend-dy 2.75)
         ;;(bend-arrow-height 1.25)
         ;;(bend-arrow-width 0.8)
         (staff-symbol (ly:grob-object grob 'staff-symbol))
         (line-count (ly:grob-property staff-symbol 'line-count))
         (staff-space (ly:grob-property staff-symbol 'staff-space))
         (left-tab-note-head (ly:spanner-bound grob LEFT))
         (right-tab-note-head (ly:spanner-bound grob RIGHT))
         (control-points (ly:grob-property grob 'control-points))
         (left-point (car control-points))
         (right-point (cadddr control-points))
         (begin-x (car left-point))
         (end-x (car right-point))
         (line-y (+ (* (/ (- line-count 1) 2) staff-space) bend-dy)))

        (ly:grob-set-property! right-tab-note-head 'transparent #t)
        (grob-interpret-markup grob
                               (make-drawDashedLine-markup
                                 bend-line-thickness
                                 begin-x end-x line-y))))

%%% music functions

bendOn = {
  \override Voice.Slur #'stencil = #slur::draw-pointed-slur
  \override TabVoice.Slur #'stencil = #slur::draw-bend-arrow
}

bendOff = {
  \revert Voice.Slur #'stencil
  \override TabVoice.Slur #'stencil = ##f
  %\override TabVoice.Slur #'direction = #UP
}

bendGrace = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override Voice.Stem #'stencil = ##f
    \once \override Voice.Stem #'direction = #DOWN
    \once \override Voice.Slur #'direction = #UP
    \grace $note
  #})

preBendOnly = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override TabVoice.Slur #'stencil = #slur::draw-pre-bend-only
    \once \override TabStaff.ParenthesesItem #'transparent = ##t
    \parenthesize $note
  #})

preBend = #(define-music-function (parser location note) (ly:music?)
  #{
    \once \override TabVoice.Slur #'stencil = #slur::draw-pre-bend-hold
    \once \override TabStaff.ParenthesesItem #'transparent = ##t
    \once \override Voice.Slur #'direction = #DOWN
    \parenthesize $note
  #})

holdBend = #(define-music-function (parser location) ()
  #{
    \once \override TabVoice.Tie #'stencil = #tie::draw-hold-bend
  #})

\version "2.13.3"

\include "bend.ly"

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

%% the test

test = \relative c'' {
  \bendOn
  % First, some bends to see if they work from the topmost to the lowest string
  c4 ( d )( c2 )
  c4\2 ( d\2 )( c2\2 )
  c4\3 ( des\3 )( c2\3 ) \break
  c,4\4 ( d\4 )( c2\4 )
  c4\5 ( d\5 )( c2\5 )
  c4\6 ( d\6 )( c2\6 ) \break
  % is the bend amount displayed correctly? (should be ½ in both cases)
  c4 ( cis) d ( es )
  % grace notes
  \bendGrace c8(  d4 )( c4 ) r2
  % the distinction between \preBendOnly and \preBend is not very
  % elegant here, I hope that there will be a better solution...
  \bendGrace { \preBendOnly c8( } d2)  r2
  \bendGrace { \preBend c8( d)( } c2)  r2
  c4 ( es) e\2 ( gis\2 ) \break
  % quarter tone bends are not yet supported as they should be, but
  % the bend amount is calculated correctly ;-)
  c,4 ( cih ) c4 ( cisih )
  % I hope that in future releases the tie will recognize automagically
  % that he ties to a note which is bent, but I don't know how (yet).
  \bendGrace c'8 ( \holdBend d2 ) ~ d2 ( c1 )
  \bendOff
  % switching bends off works apparently
  c,4 ( e ) c4 ( f )
  c'4 ( b ) c4 ( a )
}

\score {
  <<
    \new Staff {
      \new Voice {
        \clef "G_8"
        \test
      }
    }
    \new TabStaff {
      \new TabVoice {
        \clef "tab"
        \set TabStaff.stringTunings = #guitar-seven-string-tuning
        \test
      }
    }
  >>
}