\version "2.19.32" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +thumb bracket #(define (make-thumb-bracket-props location spec-str settings-alist) (define (inchar? index) (> (string-length spec-str) index)) (define (inchar index) (string-ref spec-str index)) (define (char->dir ch) (case (char-upcase ch) ((#\R) 1) ((#\L) -1) (else 0))) (define (char->digit ch) (if (char-numeric? ch) (- (char->integer ch) (char->integer #\0)) 0)) (define (inhit->1 key-str) (if (string-contains spec-str key-str) 1 0)) (define (get key) (assq-ref settings-alist key)) (define (warn p1 p2) (ly:input-warning location (_ " bad thumb-bracket: ~a ~a~a~a") p1 "\"" p2 "\"")) (let* ( ;% decode spec (vdir (if (inchar? 0) (char->dir (inchar 0)) 0)) (vbigger (* 0.5 (if (inchar? 1) (char->digit (inchar 1)) 0))) (vfurther (* 0.5 (if (inchar? 2) (char->digit (inchar 2)) 0))) (hcloser (* 0.5 (if (inchar? 3) (char->digit (inchar 3)) 0))) (hrear (* 0.5 (if (inchar? 4) (char->digit (inchar 4)) 0))) (vbigger+ (* 5 (string-count spec-str #\|))) (posdir ((if (string-contains spec-str "*") - +) vdir)) (hcloser? (eq? (string-contains spec-str "!") #f)) (vtip=? (string-contains spec-str "=")) (hdir-req (- (inhit->1 "]") (inhit->1 "["))) (closed? (char-lower-case? (inchar 0)))) (if (zero? vdir) (begin (warn "first char in" spec-str) '()) (let* ( ;% collect settings (hdir-init (get 'hdir-init)) (htip (get 'htip)) (vtip (get (if vtip=? 'vtip= 'vtip))) (vstem (get 'vstem)) (vmin (get 'vmin)) (hvernier (get 'hvernier)) (vO 0) (hO 0) (hpad-base 0.5) ;% givens (hdir (if (zero? hdir-req) hdir-init hdir-req)) (hflip? (positive? hdir)) (h-interval (if (positive? hdir) (cons hO (+ htip hrear)) (cons (- hrear) htip))) (vsize (+ vtip (if closed? vtip vstem) vbigger vbigger+)) (vsize+ (if (and closed? (< vsize vmin)) (- vmin vsize) 0)) (vshift (+ vfurther vtip (* 0.5 vsize+))) (bracket (lambda (grob) (let* ( ;% collect chord range from grob (vnote-lo-hi (ly:grob-property grob 'positions)) (vnote ((if (eq? posdir 1) cdr car) vnote-lo-hi))) (grob-interpret-markup grob (markup #:translate (cons ((if (positive? hdir) - +) hvernier) (- vnote (* vdir vshift))) #:combine #:draw-line (cons htip vO) #:combine #:translate (cons hO (if closed? (* vdir (+ vsize vsize+)) vO)) #:draw-line (cons htip vO) #:translate (cons (if (positive? hdir) htip hO) vO) #:draw-line (cons hO (* vdir (+ vsize vsize+))))))))) ;% alist of props for misusing Arpeggio as a thumb bracket `((stencil . ,bracket) (X-extent . ,h-interval) (padding . ,((if hcloser? - +) hpad-base hcloser)) (direction . ,hdir) (thickness . ,(get 'weight))))))) thumbBracketEx = #(define-music-function (spec settings) (string? list?) (let* ( (props (make-thumb-bracket-props (*location*) spec settings))) (define (get key) (assq-ref props key)) (if (null? props) #{ #} ;% abort without bracket #{ \once \override Arpeggio.stencil = #(get 'stencil) \once \override Arpeggio.X-extent = #(get 'X-extent) \once \override Arpeggio.padding = #(get 'padding) \once \override Arpeggio.direction = #(get 'direction) \once \override Arpeggio.thickness = #(get 'thickness) $(make-music 'EventChord 'elements (list (make-music 'ArpeggioEvent))) #}))) thumbBracket = #(define-music-function (spec) (string?) (let ((settings thumbBracketSettings)) ;% as Defaults, or user defined ((ly:music-function-extract thumbBracketEx) spec settings))) thumbBracketDefaults = #(quasiquote( (hdir-init . ,LEFT) ;% usual placement wrt note: on RIGHT or LEFT (weight . 1.5 ) ;% line thickness (htip . 0.8 ) ;% horizontal length of bracket tip (vtip . 0.75 ) ;% usual vertical overlap beyond notehead centre (vtip= . 0.30 ) ;% alternative vertical overlap (vstem . 1.25 ) ;% length of an unextended open bracket (excl. tip) (vmin . 0.6 ) ;% minimum length of a closed bracket (hvernier . 0.2 ) ;% horizontal quasi-extra-offset )) thumbBracketSettings = \thumbBracketDefaults %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -thumb bracket