1 ;;;; fret-diagrams.scm --
3 ;;;; source file of the GNU LilyPond music typesetter
5 ;;;; (c) 2004--2009 Carl D. Sorensen <c_sorensen@byu.edu>
12 (define (string-x-extent start-point end-point)
13 "Return the x-extent of a string that goes from start-point
15 (let ((x1 (car start-point))
21 (define (string-y-extent start-point end-point)
22 "Return the y-extent of a string that goes from start-point
24 (let ((y1 (cdr start-point))
31 (define (cons-fret new-value old-list)
32 "Put together a fret-list in the format desired by parse-string"
33 (if (eq? old-list '())
35 (cons* new-value old-list)))
37 (define (get-numeric-from-key keystring)
38 "Get the numeric value from a key of the form k:val"
39 (string->number (substring keystring 2 (string-length keystring))))
41 (define (numerify mylist)
42 "Convert string values to numeric or character"
45 (let ((numeric-value (string->number (car mylist))))
47 (cons* numeric-value (numerify (cdr mylist)))
48 (cons* (car (string->list (car mylist)))
49 (numerify (cdr mylist)))))))
52 "Calculate the font step necessary to get a desired magnification"
53 (* 6 (/ (log mag) (log 2))))
55 (define (fret-count fret-range)
56 "Calculate the fret count for the diagram given the range of frets in the diagram."
57 (1+ (- (cdr fret-range) (car fret-range))))
59 (define (subtract-base-fret base-fret dot-list)
60 "Subtract @var{base-fret} from every fret in @var{dot-list}"
63 (let ((this-list (car dot-list)))
64 (cons* (list (car this-list) (- (second this-list) base-fret)
65 (if (null? (cddr this-list))
68 (subtract-base-fret base-fret (cdr dot-list))))))
70 (define (drop-paren item-list)
71 "Drop a final parentheses from a fret indication list
72 @code{item-list} resulting from a terse string specification of barre."
73 (if (> (length item-list) 0)
74 (let* ((max-index (- (length item-list) 1))
75 (last-element (car (list-tail item-list max-index))))
76 (if (or (equal? last-element ")") (equal? last-element "("))
77 (list-head item-list max-index)
81 (define (get-sub-list value master-list)
82 "Get a sub-list whose cadr is equal to @var{value} from @var{master-list}"
83 (if (eq? master-list '())
85 (let ((sublist (car master-list)))
86 (if (equal? (cadr sublist) value)
88 (get-sub-list value (cdr master-list))))))
90 (define (merge-details key alist-list . default)
91 "Return @code{alist-list} entries for @code{key}, in one combined alist.
92 There can be two @code{alist-list} entries for a given key. The first
93 comes from the override-markup function, the second comes
94 from property settings during a regular override.
95 This is necessary because some details can be set in one
96 place, while others are set in the other. Both details
97 lists must be merged into a single alist.
98 Return @code{default} (optional, else #f) if not
101 (define (helper key alist-list default)
102 (if (null? alist-list)
104 (let* ((handle (assoc key (car alist-list))))
106 (append (cdr handle) (chain-assoc-get key (cdr alist-list) '()))
107 (helper key (cdr alist-list) default)))))
109 (helper key alist-list
110 (if (pair? default) (car default) #f)))
113 ; Conversions between fret/string coordinate system and x-y coordinate
116 ; Fret coordinates are measured down the fretboard from the nut,
119 ; String coordinates are measured from the lowest string, starting at 0.
121 ; The x-y origin is at the intersection of the nut and the lowest string.
123 ; X coordinates are positive to the right.
124 ; Y coordinates are positive up.
127 (define (negate-extent extent)
128 "Return the extent in an axis opposite to the axis of @code{extent}."
129 (cons (- (cdr extent)) (- (car extent))))
131 (define (stencil-fretboard-extent stencil fretboard-axis orientation)
132 "Return the extent of @code{stencil} in the @code{fretboard-axis}
134 (if (eq? fretboard-axis 'fret)
135 (cond ((eq? orientation 'landscape)
136 (ly:stencil-extent stencil X))
137 ((eq? orientation 'opposing-landscape)
138 (negate-extent (ly:stencil-extent stencil X)))
140 (negate-extent (ly:stencil-extent stencil Y))))
141 ; else -- eq? fretboard-axis 'string
142 (cond ((eq? orientation 'landscape)
143 (ly:stencil-extent stencil Y))
144 ((eq? orientation 'opposing-landscape)
145 (negate-extent (ly:stencil-extent stencil Y)))
147 (ly:stencil-extent stencil Y)))))
150 (define (stencil-fretboard-offset stencil fretboard-axis orientation)
151 "Return a the stencil coordinates of the center of @code{stencil}
152 in the @code{fretboard-axis} direction."
153 (* 0.5 (interval-length
154 (stencil-fretboard-extent stencil fretboard-axis orientation))))
157 (define (string-thickness string thickness-factor)
158 (expt (1+ thickness-factor) (1- string)))
161 ; Functions that create stencils used in the fret diagram
164 (define (sans-serif-stencil layout props mag text)
165 "Create a stencil in sans-serif font based on @var{layout} and @var{props}
166 with magnification @var{mag} of the string @var{text}."
169 'font-size (stepmag mag)
170 (prepend-alist-chain 'font-family 'sans props))))
171 (interpret-markup layout my-props text)))
175 ;; markup commands and associated functions
180 (define (fret-parse-marking-list marking-list my-fret-count)
181 "Parse a fret-diagram-verbose marking list into component sublists"
182 (let* ((fret-range (cons 1 my-fret-count))
188 (let parse-item ((mylist marking-list))
189 (if (not (null? mylist))
190 (let* ((my-item (car mylist)) (my-code (car my-item)))
192 ((or (eq? my-code 'open)(eq? my-code 'mute))
193 (set! xo-list (cons* my-item xo-list)))
194 ((eq? my-code 'barre)
195 (set! barre-list (cons* (cdr my-item) barre-list)))
197 (set! capo-fret (cadr my-item)))
198 ((eq? my-code 'place-fret)
199 (set! dot-list (cons* (cdr my-item) dot-list))))
200 (parse-item (cdr mylist)))))
201 ;; calculate fret-range
203 (minfret (if (> capo-fret 0) capo-fret 99)))
204 (let updatemax ((fret-list dot-list)) ;CHANGE THIS TO HELPER FUNCTION?
205 (if (null? fret-list)
207 (let ((fretval (second (car fret-list))))
208 (if (> fretval maxfret) (set! maxfret fretval))
209 (if (< fretval minfret) (set! minfret fretval))
210 (updatemax (cdr fret-list)))))
211 (if (> maxfret my-fret-count)
214 (let ((upfret (- (+ minfret my-fret-count) 1)))
215 (if (> maxfret upfret) maxfret upfret)))))
216 (set! capo-fret (1+ (- capo-fret minfret)))
217 ; subtract fret from dots
218 (set! dot-list (subtract-base-fret (- (car fret-range) 1) dot-list)))
219 (acons 'fret-range fret-range
220 (acons 'barre-list barre-list
221 (acons 'dot-list dot-list
222 (acons 'xo-list xo-list
223 (acons 'capo-fret capo-fret '())))))))
225 (define (make-fret-diagram layout props marking-list)
226 "Make a fret diagram markup"
228 ; note: here we get items from props that are needed in this routine,
229 ; or that are needed in more than one of the procedures
230 ; called from this routine. If they're only used in one of the
231 ; sub-procedure, they're obtained in that procedure
232 (size (chain-assoc-get 'size props 1.0)) ; needed for everything
233 ;TODO -- get string-count directly from length of stringTunings;
234 ; from FretBoard engraver, but not from markup call
235 (details (merge-details 'fret-diagram-details props '()))
237 (assoc-get 'string-count details 6)) ; needed for everything
239 (assoc-get 'fret-count details 4)) ; needed for everything
241 (assoc-get 'orientation details 'normal)) ; needed for everything
244 'finger-code details 'none)) ; needed for draw-dots and draw-barre
246 (if (eq? finger-code 'in-dot) 0.425 0.25)) ; bigger dots if labeled
247 (default-dot-position
248 (if (eq? finger-code 'in-dot)
249 (- 0.95 default-dot-radius)
250 0.6)) ; move up to make room for bigger dot if labeled
253 'dot-radius details default-dot-radius)) ; needed for draw-dots
257 'dot-position details default-dot-position)) ; needed for
258 ; draw-dots and draw-barre
260 (* (ly:output-def-lookup layout 'line-thickness)
261 (chain-assoc-get 'thickness props 0.5))) ; needed for draw-frets
264 (thickness-factor (assoc-get 'string-thickness-factor details 0))
266 (chain-assoc-get 'align-dir props -0.4)) ; needed only here
268 (* size (assoc-get 'xo-padding details 0.2))) ; needed only here
269 (parameters (fret-parse-marking-list marking-list my-fret-count))
270 (capo-fret (assoc-get 'capo-fret parameters 0))
271 (dot-list (cdr (assoc 'dot-list parameters)))
272 (xo-list (cdr (assoc 'xo-list parameters)))
273 (fret-range (cdr (assoc 'fret-range parameters)))
274 (my-fret-count (fret-count fret-range))
275 (barre-list (cdr (assoc 'barre-list parameters)))
277 (assoc-get 'barre-type details 'curved))
278 (fret-diagram-stencil '()))
280 ;; Here are the fret diagram helper functions that depend on the
281 ;; fret diagram parameters. The functions are here because the
282 ;; diagram parameters are part of the lexical scope here.
284 (define (stencil-coordinates fret-coordinate string-coordinate)
285 "Return a pair @code{(x-coordinate . y-coordinate)}
286 in stencil coordinate system."
288 ((eq? orientation 'landscape)
289 (cons fret-coordinate
290 (- string-coordinate (1- string-count))))
291 ((eq? orientation 'opposing-landscape)
292 (cons (- fret-coordinate) (- string-coordinate)))
294 (cons string-coordinate (- fret-coordinate)))))
296 (define (make-bezier-sandwich-list start stop base height
298 "Make the argument list for a bezier sandwich from
299 string coordinate @var{start} to string-coordinate @var{stop} with a
300 baseline at fret coordinate @var{base}, a height of
301 @var{height}, and a half thickness of @var{half-thickness}."
302 (let* ((width (+ (- stop start) 1))
303 (cp-left-width (+ (* width half-thickness) start))
304 (cp-right-width (- stop (* width half-thickness)))
305 (bottom-control-point-height
306 (- base (- height half-thickness)))
307 (top-control-point-height
310 (stencil-coordinates base start))
312 (stencil-coordinates base stop))
313 (left-upper-control-point
315 top-control-point-height cp-left-width))
316 (left-lower-control-point
318 bottom-control-point-height cp-left-width))
319 (right-upper-control-point
321 top-control-point-height cp-right-width))
322 (right-lower-control-point
324 bottom-control-point-height cp-right-width)))
325 ; order of bezier control points is:
326 ; left cp low, right cp low, right end low, left end low
327 ; right cp high, left cp high, left end high, right end high.
329 (list left-lower-control-point
330 right-lower-control-point
333 right-upper-control-point
334 left-upper-control-point
338 (define (draw-strings)
339 "Draw the string lines for a fret diagram with
340 @var{string-count} strings and frets as indicated in @var{fret-range}.
341 Line thickness is given by @var{th}, fret & string spacing by
342 @var{size}. Orientation is determined by @var{orientation}. "
346 (string-stencil (car x))
348 (string-stencil (car x))
351 (let* ( (string-list (map 1+ (iota string-count))))
352 (helper string-list)))
354 (define (string-stencil string)
355 "Make a stencil for @code{string}, given the fret-diagram
357 (let* ((string-coordinate (- string-count string))
358 (current-string-thickness
359 (* th size (string-thickness string thickness-factor)))
360 (fret-half-thickness (* size th 0.5))
361 (half-string (* current-string-thickness 0.5))
364 (- fret-half-thickness)
365 (- (* size string-coordinate) half-string)))
368 (+ fret-half-thickness (* size (1+ (fret-count fret-range))))
369 (+ half-string (* size string-coordinate)))))
371 (string-x-extent start-coordinates end-coordinates)
372 (string-y-extent start-coordinates end-coordinates)
376 "Draw the fret lines for a fret diagram with
377 @var{string-count} strings and frets as indicated in @var{fret-range}.
378 Line thickness is given by @var{th}, fret & string spacing by
379 @var{size}. Orientation is given by @var{orientation}."
382 (fret-stencil (car x))
384 (fret-stencil (car x))
387 (let ((fret-list (iota (1+ my-fret-count))))
390 (define (fret-stencil fret)
391 "Make a stencil for @code{fret}, given the
392 fret-diagram overall parameters."
393 (let* ((low-string-half-thickness
397 (string-thickness string-count thickness-factor)))
398 (fret-half-thickness (* 0.5 size th))
402 (- fret-half-thickness low-string-half-thickness)))
406 (* size (1- string-count)))))
409 (car start-coordinates) (cdr start-coordinates)
410 (car end-coordinates) (cdr end-coordinates))))
412 (define (draw-barre barre-list)
413 "Create barre indications for a fret diagram"
414 (if (not (null? barre-list))
415 (let* ((string1 (caar barre-list))
416 (string2 (cadar barre-list))
417 (barre-fret (caddar barre-list))
418 (top-fret (cdr fret-range))
419 (low-fret (car fret-range))
420 (fret (1+ (- barre-fret low-fret)))
421 (barre-vertical-offset 0.5)
422 (dot-center-fret-coordinate (+ (1- fret) dot-position))
423 (barre-fret-coordinate
424 (+ dot-center-fret-coordinate
425 (* (- barre-vertical-offset 0.5) dot-radius)))
426 (barre-start-string-coordinate (- string-count string1))
427 (barre-end-string-coordinate (- string-count string2))
428 (scale-dot-radius (* size dot-radius))
429 (barre-type (assoc-get 'barre-type details 'curved))
432 ((eq? barre-type 'straight)
433 (make-straight-barre-stencil
434 barre-fret-coordinate
435 barre-start-string-coordinate
436 barre-end-string-coordinate
438 ((eq? barre-type 'curved)
439 (make-curved-barre-stencil
440 barre-fret-coordinate
441 barre-start-string-coordinate
442 barre-end-string-coordinate
443 scale-dot-radius)))))
444 (if (not (null? (cdr barre-list)))
447 (draw-barre (cdr barre-list)))
450 (define (make-straight-barre-stencil
452 start-string-coordinate
453 end-string-coordinate
455 "Create a straight barre stencil."
458 (* size fret-coordinate)
459 (* size start-string-coordinate)))
462 (* size fret-coordinate)
463 (* size end-string-coordinate))))
471 (define (make-curved-barre-stencil
473 start-string-coordinate
474 end-string-coordinate
476 "Create a curved barre stencil."
477 (let* ((bezier-thick 0.1)
480 (make-bezier-sandwich-list
481 (* size start-string-coordinate)
482 (* size end-string-coordinate)
483 (* size fret-coordinate)
484 (* size bezier-height)
485 (* size bezier-thick)))
488 (+ (* size fret-coordinate) half-thickness)
489 (- (* size start-string-coordinate) half-thickness)))
492 (- (* size fret-coordinate)
493 (* size bezier-height)
495 (+ (* size end-string-coordinate) half-thickness)))
496 (x-extent (cons (car box-lower-left) (car box-upper-right)))
497 (y-extent (cons (cdr box-lower-left) (cdr box-upper-right))))
499 (list 'bezier-sandwich
500 `(quote ,bezier-list)
501 (* size bezier-thick))
505 (define (draw-dots dot-list)
506 "Make dots for fret diagram."
508 (let* ( (scale-dot-radius (* size dot-radius))
509 (scale-dot-thick (* size th))
510 (dot-color (assoc-get 'dot-color details 'black))
511 (finger-label-padding 0.3)
514 (assoc-get 'dot-label-font-mag details 1.0)))
515 (string-label-font-mag
518 'string-label-font-mag details
519 (cond ((or (eq? orientation 'landscape)
520 (eq? orientation 'opposing-landscape))
523 (mypair (car dot-list))
524 (restlist (cdr dot-list))
525 (string (car mypair))
527 (fret-coordinate (* size (+ (1- fret) dot-position)))
528 (string-coordinate (* size (- string-count string)))
530 (stencil-coordinates fret-coordinate string-coordinate))
531 (extent (cons (- scale-dot-radius) scale-dot-radius))
532 (finger (caddr mypair))
533 (finger (if (number? finger) (number->string finger) finger))
534 (dot-stencil (if (eq? dot-color 'white)
537 scale-dot-radius scale-dot-thick #t)
540 (- scale-dot-radius (* 0.5 scale-dot-thick))
544 scale-dot-radius scale-dot-thick #t)))
546 (ly:stencil-translate dot-stencil dot-coordinates))
549 ((or (eq? finger '())(eq? finger-code 'none))
551 ((eq? finger-code 'in-dot)
555 layout props dot-label-font-mag finger))))
556 (ly:stencil-translate
559 (if (eq? dot-color 'white)
561 (ly:stencil-in-color finger-label 1 1 1)))
563 ((eq? finger-code 'below-string)
564 (let* ((label-stencil
567 layout props string-label-font-mag
570 (stencil-fretboard-offset
571 label-stencil 'fret orientation))
572 (label-fret-coordinate
574 (+ 1 my-fret-count finger-label-padding))
576 (label-string-coordinate string-coordinate)
579 label-fret-coordinate
580 label-string-coordinate)))
583 (ly:stencil-translate
585 label-translation))))
586 (else ;unknown finger-code
592 labeled-dot-stencil))))
594 (define (draw-thick-zero-fret)
595 "Draw a thick zeroth fret for a fret diagram whose base fret is 1."
596 (let* ((half-lowest-string-thickness
597 (* 0.5 th (string-thickness string-count thickness-factor)))
598 (half-thick (* 0.5 sth))
600 (* sth (assoc-get 'top-fret-thickness details 3.0)))
601 (start-string-coordinate (- half-lowest-string-thickness))
602 (end-string-coordinate (+ (* size (1- string-count)) half-thick))
603 (start-fret-coordinate half-thick)
604 (end-fret-coordinate (- half-thick top-fret-thick))
607 start-fret-coordinate start-string-coordinate))
610 end-fret-coordinate end-string-coordinate)))
612 (cons (car lower-left) (car upper-right))
613 (cons (cdr lower-left) (cdr upper-right))
616 (define (draw-xo xo-list)
617 "Put open and mute string indications on diagram, as contained in
621 'xo-font-magnification details
622 (cond ((or (eq? orientation 'landscape)
623 (eq? orientation 'opposing-landscape))
626 (mypair (car xo-list))
627 (restlist (cdr xo-list))
628 (glyph-string (if (eq? (car mypair) 'mute)
629 (assoc-get 'mute-string details "X")
630 (assoc-get 'open-string details "O")))
631 (glyph-string-coordinate (* (- string-count (cadr mypair)) size))
635 layout props (* size xo-font-mag) glyph-string)))
636 (glyph-stencil-coordinates
637 (stencil-coordinates 0 glyph-string-coordinate))
639 (ly:stencil-translate
641 glyph-stencil-coordinates)))
645 (draw-xo restlist)))))
647 (define (draw-capo fret)
648 "Draw a capo indicator across the full width of the fret-board
651 (* size (assoc-get 'capo-thickness details 0.5)))
652 (half-thick (* capo-thick 0.5))
653 (last-string-position 0)
654 (first-string-position (* size (- string-count 1)))
655 (fret-position ( * size (1- (+ dot-position fret))))
659 first-string-position))
663 last-string-position)))
666 (car start-point) (cdr start-point)
667 (car end-point) (cdr end-point))))
669 (define (label-fret fret-range)
670 "Label the base fret on a fret diagram"
671 (let* ((base-fret (car fret-range))
672 (label-font-mag (assoc-get 'fret-label-font-mag details 0.5))
673 (label-space (* 0.5 size))
674 (label-dir (assoc-get 'label-dir details RIGHT))
675 (label-vertical-offset
676 (assoc-get 'fret-label-vertical-offset details 0))
678 (assoc-get 'number-type details 'roman-lower))
681 ((equal? number-type 'roman-lower)
682 (fancy-format #f "~(~@r~)" base-fret))
683 ((equal? number-type 'roman-upper)
684 (fancy-format #f "~@r" base-fret))
685 ((equal? 'arabic number-type)
686 (fancy-format #f "~d" base-fret))
687 (else (fancy-format #f "~(~@r~)" base-fret))))
691 layout props (* size label-font-mag) label-text)))
693 (stencil-fretboard-offset
697 (label-outside-diagram (+ label-space label-half-width)))
698 (ly:stencil-translate
701 (1+ (* size label-vertical-offset))
702 (if (eq? label-dir LEFT)
703 (- label-outside-diagram)
704 (+ (* size (1- string-count)) label-outside-diagram))))))
707 ; Here is the body of make-fret-diagram
710 (set! fret-diagram-stencil
711 (ly:stencil-add (draw-strings) (draw-frets)))
712 (if (and (not (null? barre-list))
713 (not (eq? 'none barre-type)))
714 (set! fret-diagram-stencil
716 (draw-barre barre-list)
717 fret-diagram-stencil)))
718 (if (not (null? dot-list))
719 (set! fret-diagram-stencil
722 (draw-dots dot-list))))
723 (if (= (car fret-range) 1)
724 (set! fret-diagram-stencil
727 (draw-thick-zero-fret))))
728 (if (not (null? xo-list))
729 (let* ((diagram-fret-top
730 (car (stencil-fretboard-extent
734 (xo-stencil (draw-xo xo-list))
736 (stencil-fretboard-offset
737 xo-stencil 'fret orientation)))
738 (set! fret-diagram-stencil
741 (ly:stencil-translate
747 0)))))) ; no string offset
750 (set! fret-diagram-stencil
753 (draw-capo capo-fret))))
754 (if (> (car fret-range) 1)
755 (set! fret-diagram-stencil
758 (label-fret fret-range))))
759 (ly:stencil-aligned-to fret-diagram-stencil X alignment)))
761 (define (fret-parse-definition-string props definition-string)
762 "Parse a fret diagram string and return a pair containing:
763 @var{props}, modified as necessary by the definition-string
764 a fret-indication list with the appropriate values"
765 (let* ((fret-count 4)
767 (fret-range (cons 1 fret-count))
773 (details (merge-details 'fret-diagram-details props '()))
774 (items (string-split definition-string #\;)))
775 (let parse-item ((myitems items))
776 (if (not (null? (cdr myitems)))
777 (let ((test-string (car myitems)))
778 (case (car (string->list (substring test-string 0 1)))
779 ((#\s) (let ((size (get-numeric-from-key test-string)))
780 (set! props (prepend-alist-chain 'size size props))))
781 ((#\f) (let* ((finger-code (get-numeric-from-key test-string))
782 (finger-id (case finger-code
785 ((2) 'below-string))))
787 (acons 'finger-code finger-id details))))
788 ((#\c) (set! output-list
793 (string-split (substring test-string 2) #\-)))
795 ((#\h) (let ((fret-count (get-numeric-from-key test-string)))
797 (acons 'fret-count fret-count details))))
798 ((#\w) (let ((string-count (get-numeric-from-key test-string)))
800 (acons 'string-count string-count details))))
801 ((#\d) (let ((dot-size (get-numeric-from-key test-string)))
803 (acons 'dot-radius dot-size details))))
804 ((#\p) (let ((dot-position (get-numeric-from-key test-string)))
806 (acons 'dot-position dot-position details))))
808 (let ((this-list (string-split test-string #\-)))
809 (if (string->number (cadr this-list))
812 (cons 'place-fret (numerify this-list))
814 (if (equal? (cadr this-list) "x" )
817 (list 'mute (string->number (car this-list)))
821 (list 'open (string->number (car this-list)))
823 (parse-item (cdr myitems)))))
824 ; add the modified details
826 (prepend-alist-chain 'fret-diagram-details details props))
827 `(,props . ,output-list))) ;ugh -- hard-coded spell -- procedure better
830 (fret-parse-terse-definition-string props definition-string)
831 "Parse a fret diagram string that uses terse syntax;
832 return a pair containing:
833 @var{props}, modified to include the string-count determined by the
834 definition-string, and
835 a fret-indication list with the appropriate values"
836 ;TODO -- change syntax to fret\string-finger
838 (let* ((details (merge-details 'fret-diagram-details props '()))
839 (barre-start-list '())
842 (items (string-split definition-string #\;))
843 (string-count (- (length items) 1)))
844 (let parse-item ((myitems items))
845 (if (not (null? (cdr myitems)))
846 (let* ((test-string (car myitems))
847 (current-string (- (length myitems) 1))
848 (indicators (string-split test-string #\ )))
849 (let parse-indicators ((myindicators indicators))
850 (if (not (eq? '() myindicators))
851 (let* ((this-list (string-split (car myindicators) #\-))
852 (max-element-index (- (length this-list) 1))
854 (car (list-tail this-list max-element-index)))
856 (if (string->number (car this-list))
857 (string->number (car this-list))
859 (if (equal? last-element "(")
861 (set! barre-start-list
862 (cons-fret (list current-string fret)
865 (list-head this-list max-element-index))))
866 (if (equal? last-element ")")
868 (get-sub-list fret barre-start-list))
869 (insert-index (- (length this-barre) 1)))
871 (cons-fret (cons* 'barre
877 (list-head this-list max-element-index))))
884 (drop-paren (numerify this-list)))
886 (if (equal? (car this-list) "x" )
890 (list 'mute current-string)
895 (list 'open current-string)
897 (parse-indicators (cdr myindicators)))))
898 (parse-item (cdr myitems)))))
899 (set! details (acons 'string-count string-count details))
900 (set! props (prepend-alist-chain 'fret-diagram-details details props))
901 `(,props . ,output-list))) ; ugh -- hard coded; proc is better
904 (define-builtin-markup-command
905 (fret-diagram-verbose layout props marking-list)
906 (pair?) ; argument type (list, but use pair? for speed)
907 instrument-specific-markup ; markup type
908 ((align-dir -0.4) ; properties and defaults
910 (fret-diagram-details)
912 "Make a fret diagram containing the symbols indicated in @var{marking-list}.
917 \\markup \\fret-diagram-verbose
918 #'((mute 6) (mute 5) (open 4)
919 (place-fret 3 2) (place-fret 2 3) (place-fret 1 2))
923 produces a standard D@tie{}chord diagram without fingering indications.
925 Possible elements in @var{marking-list}:
928 @item (mute @var{string-number})
929 Place a small @q{x} at the top of string @var{string-number}.
931 @item (open @var{string-number})
932 Place a small @q{o} at the top of string @var{string-number}.
934 @item (barre @var{start-string} @var{end-string} @var{fret-number})
935 Place a barre indicator (much like a tie) from string @var{start-string}
936 to string @var{end-string} at fret @var{fret-number}.
938 @item (capo @var{fret-number})
939 Place a capo indicator (a large solid bar) across the entire fretboard
940 at fret location @var{fret-number}. Also, set fret @var{fret-number}
941 to be the lowest fret on the fret diagram.
943 @item (place-fret @var{string-number} @var{fret-number} @var{finger-value})
944 Place a fret playing indication on string @var{string-number} at fret
945 @var{fret-number} with an optional fingering label @var{finger-value}.
946 By default, the fret playing indicator is a solid dot. This can be
947 changed by setting the value of the variable @var{dot-color}. If the
948 @var{finger} part of the @code{place-fret} element is present,
949 @var{finger-value} will be displayed according to the setting of the
950 variable @var{finger-code}. There is no limit to the number of fret
951 indications per string.
954 (make-fret-diagram layout props marking-list))
957 (define-builtin-markup-command (fret-diagram layout props definition-string)
958 (string?) ; argument type
959 instrument-specific-markup ; markup category
960 (fret-diagram-verbose-markup) ; properties and defaults
961 "Make a (guitar) fret diagram. For example, say
964 \\markup \\fret-diagram #\"s:0.75;6-x;5-x;4-o;3-2;2-3;1-2;\"
968 for fret spacing 3/4 of staff space, D chord diagram
970 Syntax rules for @var{definition-string}:
974 Diagram items are separated by semicolons.
981 @code{s:}@var{number} -- Set the fret spacing of the diagram (in staff
986 @code{t:}@var{number} -- Set the line thickness (in staff spaces).
990 @code{h:}@var{number} -- Set the height of the diagram in frets.
994 @code{w:}@var{number} -- Set the width of the diagram in strings.
998 @code{f:}@var{number} -- Set fingering label type
999 (0@tie{}= none, 1@tie{}= in circle on string, 2@tie{}= below string).
1003 @code{d:}@var{number} -- Set radius of dot, in terms of fret spacing.
1007 @code{p:}@var{number} -- Set the position of the dot in the fret space.
1008 0.5 is centered; 1@tie{}is on lower fret bar, 0@tie{}is on upper fret bar.
1012 @code{c:}@var{string1}@code{-}@var{string2}@code{-}@var{fret} -- Include a
1013 barre mark from @var{string1} to @var{string2} on @var{fret}.
1016 @var{string}@code{-}@var{fret} -- Place a dot on @var{string} at @var{fret}.
1017 If @var{fret} is @samp{o}, @var{string} is identified as open.
1018 If @var{fret} is @samp{x}, @var{string} is identified as muted.
1021 @var{string}@code{-}@var{fret}@code{-}@var{fingering} -- Place a dot on
1022 @var{string} at @var{fret}, and label with @var{fingering} as defined
1023 by the @code{f:} code.
1027 Note: There is no limit to the number of fret indications per string.
1029 (let ((definition-list
1030 (fret-parse-definition-string props definition-string)))
1031 (fret-diagram-verbose-markup
1032 layout (car definition-list) (cdr definition-list))))
1034 (define-builtin-markup-command
1035 (fret-diagram-terse layout props definition-string)
1036 (string?) ; argument type
1037 instrument-specific-markup ; markup category
1038 (fret-diagram-verbose-markup) ; properties
1039 "Make a fret diagram markup using terse string-based syntax.
1044 \\markup \\fret-diagram-terse #\"x;x;o;2;3;2;\"
1048 for a D@tie{}chord diagram.
1050 Syntax rules for @var{definition-string}:
1055 Strings are terminated by semicolons; the number of semicolons
1056 is the number of strings in the diagram.
1059 Mute strings are indicated by @samp{x}.
1062 Open strings are indicated by @samp{o}.
1065 A number indicates a fret indication at that fret.
1068 If there are multiple fret indicators desired on a string, they
1069 should be separated by spaces.
1072 Fingerings are given by following the fret number with a @code{-},
1073 followed by the finger indicator, e.g. @samp{3-2} for playing the third
1074 fret with the second finger.
1077 Where a barre indicator is desired, follow the fret (or fingering) symbol
1078 with @code{-(} to start a barre and @code{-)} to end the barre.
1081 ;; TODO -- change syntax to fret\string-finger
1082 (let ((definition-list
1083 (fret-parse-terse-definition-string props definition-string)))
1084 (fret-diagram-verbose-markup layout
1085 (car definition-list)
1086 (cdr definition-list))))