Hello Dirck,

you might be interested in something I recently made for music SE. Essentially 
this will add two new engravers that automatically annotate the string tuning 
whenever it changes.

Cheers,
Valentin
\version "2.24"

% Used for printing the actual changes. A procedure that takes the tuning and the old tuning
% as optional argument and returns a markup.
#(set-object-property! 'stringTuningColumnFormatter
                       'translation-type?
                       procedure?)

% Create a tuning column reahearsal mark whenever the string tuning changes
#(define (string-tuning-engraver context)
   (let ((current-tuning #f))
     (make-engraver
      ((process-music engraver)
       (let ((tuning (ly:context-property context 'stringTunings))
             (formatter (ly:context-property context 'stringTuningColumnFormatter)))
         (if (not (equal? tuning current-tuning))
             (let* ((mark (ly:engraver-make-grob engraver 'RehearsalMark '())))
               (ly:grob-set-property! mark 'text (formatter tuning current-tuning))
               (ly:grob-set-property! mark 'font-size 0)
               (ly:grob-set-property! mark 'self-alignment-X LEFT)
               (set! current-tuning tuning))))))))

% Print tuning supplied in details.string-tuning on the line positions
#(define (key-signature-interface::tuning-column-print grob)
   (let* ((staff-symbol (ly:grob-object grob 'staff-symbol))
          (pos (ly:grob-property staff-symbol 'line-positions #f))
          ; With 2.25 line-positions will be used by default. Before this might not be set, so
          ; in case we recalculate this here to make the code compatible with 2.24
          (pos (or pos
                   (let* ((count (ly:grob-property staff-symbol 'line-count)))
                     (map (lambda (i) (- count (* 2 i) 1)) (iota count)))))
          (ssp (ly:staff-symbol-staff-space staff-symbol))
          (tuning (assoc-get 'string-tuning (ly:grob-property grob 'details)))
          (mups (map (lambda (p) (markup #:whiteout #:pad-markup 0.1 (note-name->markup p #f))) tuning))
          (stcs (map (lambda (m)
                       (ly:stencil-aligned-to
                         (grob-interpret-markup grob m)
                         Y CENTER))
                     mups))
          (common-center (interval-center (ly:stencil-extent (grob-interpret-markup grob "A") X)))
          (tstcs (map
                  (lambda (s p) (ly:stencil-translate s (cons (- common-center) (* ssp 0.5 p))))
                  stcs pos)))
     (apply ly:stencil-add tstcs)))

% Create a "tuning key signature" whenever tuning changes
#(define (tab-staff-string-tuning-key-engraver context)
   (let ((current-tuning #f))
     (make-engraver
      ((process-music engraver)
       (let ((tuning (ly:context-property context 'stringTunings)))
         (if (not (equal? tuning current-tuning))
             (let* ((mark (ly:engraver-make-grob engraver 'KeySignature '())))
               (ly:grob-set-nested-property! mark '(details string-tuning) tuning)
               (ly:grob-set-property! mark 'stencil key-signature-interface::tuning-column-print)
               (set! current-tuning tuning))))))))

% Print a column of all tunings. Optional argument str-nos specifies tho 0 indexed string numbers.
% Keyword arg show-change specifies if only the tuning should be printed or also the change from
% previous tuning.
#(define* (tuning-column::full-formatter
           tuning
           #:optional (old-tuning #f) (str-nos #f)
           #:key (show-change #f))
   (if (not str-nos)
       (set! str-nos (iota (length tuning))))
   (let ((mup
          (map
           (lambda (n o i)
             #{
               \markup {
                 \vcenter \circle \dynamic #(number->string (1+ i))
                 \hspace #0.3
                 \vcenter
                 #(if (or (equal? n o) (not show-change))
                      (note-name->markup n #f)
                      (make-concat-markup
                       (list (note-name->markup o #f)
                             "→"
                             (note-name->markup n #f))))
               }
             #})
           tuning (if old-tuning old-tuning tuning) str-nos)))
     (markup #:override '(baseline-skip . 3) #:fontsize -4 (make-column-markup mup))))

% Like tuning-column::full-formatter, but with show-change = #t
#(define* (tuning-column::full-formatter-change . args)
   (apply tuning-column::full-formatter (append args (list #:show-change #t))))

% Like tuning-column::full-formatter, but only print strings with changed tuning
#(define* (tuning-column::diff-formatter tuning
                                         #:optional (old-tuning #f) (str-nos #f)
                                         #:key (show-change #f))
   (if (not str-nos)
       (set! str-nos (iota (length tuning))))
   (if old-tuning
       (let* ((triplets (map list tuning old-tuning str-nos))
              (triplets (filter (lambda (x) (not (equal? (car x) (cadr x)))) triplets)))
         (set! tuning (map car triplets))
         (set! old-tuning (map cadr triplets))
         (set! str-nos (map caddr triplets))))
   (tuning-column::full-formatter tuning old-tuning str-nos #:show-change show-change))

% Like tuning-column::diff-formatter, but with show-change = #t
#(define* (tuning-column::diff-formatter-change . args)
   (apply tuning-column::diff-formatter (append args (list #:show-change #t))))

% Set default formatter to diff with change. Add tuning columns to Staff and TabStaff.
% Add tuning key to TabStaff
\layout {
  \context {
    \Score
    stringTuningColumnFormatter = #tuning-column::diff-formatter-change
  }
  \context {
    \Staff
    \consists #string-tuning-engraver
  }
  \context {
    \TabStaff
    \consists #string-tuning-engraver
    \consists #tab-staff-string-tuning-key-engraver
    \override KeySignature.font-size = #-4
    \override KeySignature.break-visibility = #all-visible
  }
}


%%%%%%%%% EXAMPLE %%%%%%%%%%

\layout {
  \revert TabStaff.TimeSignature.stencil
}


\paper {
  ragged-right = ##t
}

music = {
  <c c'>4 4 4 4
  \set Staff.stringTunings = \stringTuning <e, ais, d g c' e'>
  <c c'>4 <c c'>4
  \set Staff.stringTunings = \stringTuning <e, a, d g b e'>
  <c c'>4 4
  \break
  \set Staff.stringTunings = \stringTuning <e, ais, d g c' e'>
  <c c'>4 4 4 4
}

<<
  \new Staff \with {
    stringTuningColumnFormatter = #tuning-column::full-formatter
    \clef "treble_8"
  } \music
  \new Staff \with {
    stringTuningColumnFormatter = #tuning-column::full-formatter-change
    \clef "treble_8"
  } \music
  \new Staff \with {
    stringTuningColumnFormatter = #tuning-column::diff-formatter
    \clef "treble_8"
  } \music
  \new Staff \with {
    stringTuningColumnFormatter = #tuning-column::diff-formatter-change
    \clef "treble_8"
  } \music
  \new TabStaff \music
>>

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to