+;;; Tablature functions, by Jiba (jiba@tuxfamily.org)
+
+;; The TabNoteHead stem attachment function.
+(define (tablature-stem-attachment-function style duration)
+ (cons 0.0 0.5))
+
+;; The TabNoteHead tablatureFormat callback.
+;; Compute the text grob-property
+(define-public (fret-number-tablature-format string tuning pitch)
+ (number->string
+ (- (ly:pitch-semitones pitch)
+ (list-ref tuning
+ ;; remove 1 because list index starts at 0 and guitar string at 1.
+ (- string 1)))))
+
+;; The 5-string banjo has got a extra string, the fifth (duh), wich
+;; starts at the fifth fret on the neck. Frets on the fifth string
+;; are referred to relative to the other frets:
+;; the "first fret" on the fifth string is really the sixth fret
+;; on the banjo neck.
+;; We solve this by defining a new fret-number-tablature function:
+(define-public (fret-number-tablature-format-banjo string tuning pitch)
+ (let ((fret (- (ly:pitch-semitones pitch) (list-ref tuning (- string 1)))))
+ (number->string (cond
+ ((and (> fret 0) (= string 5))
+ (+ fret 5))
+ (else fret)))))
+
+(define-public (hammer-print-function grob)
+ (let* ((note-collums (ly:grob-property grob 'note-columns))
+ (note-column1 (cadr note-collums))
+ (note-column2 (car note-collums))
+ (note1 (car (ly:grob-property note-column1 'note-heads)))
+ (note2 (car (ly:grob-property note-column2 'note-heads)))
+ (text1 (ly:grob-property note1 'text))
+ (text2 (ly:grob-property note2 'text))
+ (fret1 (if (string? text1) (string->number text1) 0))
+ (fret2 (if (string? text2) (string->number text2) 0))
+ (letter (cond
+ ((< fret1 fret2) "H")
+ ((> fret1 fret2) "P")
+ (else ""))))
+ (let* ((slur
+ ;; (Slur::print grob)
+
+ ;;
+ ;; FIXME: a hammer is not a slur.
+ ;;
+ (ly:make-stencil '() '(0 . 0) '(0 . 0)))
+ (layout (ly:grob-layout grob))
+ (text (interpret-markup
+ layout
+ (ly:grob-alist-chain grob (ly:output-def-lookup layout 'text-font-defaults))
+ letter)))
+
+ (let ((x (/ (- (cdr (ly:stencil-extent slur 0))
+ (/ (cdr (ly:stencil-extent text 0)) 2.0))
+ -2.0)))
+
+ (set! text
+ (ly:make-stencil (ly:stencil-expr text)
+ (cons x x)
+ (ly:stencil-extent text Y)))
+
+ (ly:stencil-aligned-to text X RIGHT)))))
+
+
+(define-public guitar-tuning '(4 -1 -5 -10 -15 -20))
+(define-public bass-tuning '(-17 -22 -27 -32))
+
+;; tunings for 5-string banjo
+(define-public banjo-open-g-tuning '(2 -1 -5 -10 7))
+(define-public banjo-c-tuning '(2 -1 -5 -12 7))
+(define-public banjo-modal-tuning '(2 0 -5 -10 7))
+(define-public banjo-open-d-tuning '(2 -3 -6 -10 9))
+(define-public banjo-open-dm-tuning '(2 -3 -6 -10 9))
+;; convert 5-string banjo tunings to 4-string tunings by
+;; removing the 5th string
+;;
+;; example:
+;; \set TabStaff.stringTunings = #(four-string-banjo banjo-open-g-tuning)
+(define-public (four-string-banjo tuning)
+ (reverse (cdr (reverse tuning))))
+
+;;; end of tablature functions
+
+(define-public (make-stencil-boxer thickness padding callback)
+ "Return function that adds a box around the grob passed as argument."
+ (lambda (grob) (box-stencil (callback grob) thickness padding)))
+
+(define-public (make-stencil-circler thickness padding callback)
+ "Return function that adds a circle around the grob passed as argument."
+ (lambda (grob) (circle-stencil (callback grob) thickness padding)))
+
+(define-public (arg->string arg)
+ (cond ((number? arg) (ly:inexact->string arg 10))