Bracketed or parenthesized alternative KeySignature

Revision as of 22:50, 26 October 2025 by Jean Abou Samra (talk | contribs) (Import snippet from LSR)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Sometimes bracketed or parenthesized KeySignatures indicate an alternative key.
The here proposed alternativeKey-function tries to do so.
It takes three arguments: the tonic-pitch of the original key, the tonic-pitch of the alternative key and the scale. An optional argument is provided as well. It determines whether to use brackets or parentheses, possible settings are 'bracketified (default) or 'parenthesized. Other settings will issue a warning and the alternative KeySignature will be printed without any brackets or parentheses.
Limitations
- works only for minor and major, other scales are not supported
- it's not possible to use a different scale for the alternative key

\version "2.24.0"

\paper { tagline = ##f }

#(define (key-alt-key-stencil p-1 p-2 scale-def bracket-style)
  (lambda (grob)
    (let* ((staff-space (ly:staff-symbol-staff-space grob))
           (th (ly:staff-symbol-line-thickness grob))
           (default-stil (ly:key-signature-interface::print grob))
           ;; a-minor and c-major don't have a visible KeySignature
           ;; TODO: add support for other scales: ionian, locrian etc
           (no-visible-key?
             (lambda (p)
               (or (and (= (ly:pitch-notename p) 5)
                        (= (ly:pitch-alteration p) 0)
                        (eq? scale-def minor))
                   (and (= (ly:pitch-notename p) 0)
                        (= (ly:pitch-alteration p) 0)
                        (eq? scale-def major)))))
           (stil-to-add
             (if (no-visible-key? p-2)
                 #f
                 (grob-interpret-markup grob 
                   #{
                     \markup
                       \score {
%% updaters remark: 
%% 2.22. warns for a loney KeySignature, thus we insert s1*1/100000.
%% Otherwise an assertion error happens.
                         { \key $p-2 $scale-def s1*1/100000 }
                         \layout {
                           \omit Staff.TimeSignature
                           \omit Staff.Clef
                           \override Staff.StaffSymbol.line-count = #0
                           indent = 0
                         }
                     }
                   #}))))
      (if stil-to-add
          (let* ((stil-to-add-x-ext (ly:stencil-extent stil-to-add X))
                 (stil-to-add-y-ext (ly:stencil-extent stil-to-add Y))
                 (new-key-sig-stil
                   (ly:make-stencil
                     (ly:stencil-expr stil-to-add)
                     ;; left bracket is too far away, trimmed a little
                     (cons
                        (+ (car stil-to-add-x-ext) (* 0.7 staff-space))
                        (cdr stil-to-add-x-ext))
                     ;; adjusting the top and bottom ending of the bracket
                     (cons 
                        (+ (car stil-to-add-y-ext) (* 0.2 staff-space)) 
                        (- (cdr stil-to-add-y-ext) (* 0.5 staff-space)))))
                 (bracketified-stil
                   (cond ((eq? bracket-style 'bracketified)
                          (apply bracketify-stencil 
                                 (list 
                                   ;; stil 
                                   new-key-sig-stil 
                                   ;; axis 
                                   Y 
                                   ;; thick 
                                   th 
                                   ;; protrusion 
                                   (* 2.5 th) 
                                   ;; padding
                                   th)))
                         ((eq? bracket-style 'parenthesized)
                          (apply parenthesize-stencil 
                                 (list 
                                   ;; stencil 
                                   new-key-sig-stil 
                                   ;; half-thickness 
                                   th 
                                   ;; width 
                                   (* 0.5 staff-space) 
                                   ;; angularity 
                                   (* 2.5 th) 
                                   ;; padding
                                   th)))
                         (else
                           (ly:warning "Unknown bracket-style: ~a, ignoring"
                                       bracket-style)
                           new-key-sig-stil))))
          (if (no-visible-key? p-1)
              bracketified-stil
              (ly:stencil-combine-at-edge 
                default-stil
                X
                RIGHT
                bracketified-stil
                staff-space)))
         default-stil))))

alternativeKey =
#(define-music-function (style p1 p2 scale)
     ((symbol? 'bracketified) ly:pitch? ly:pitch? number-pair-list?)
#{
  \override Staff.KeySignature.stencil =
   #(key-alt-key-stencil p1 p2 scale style)
  \key $p1 $scale
#})

%%%%%%%%%%%%%%
% EXAMPLES
%%%%%%%%%%%%%%
%%{
\relative c' {
	\alternativeKey c f \major
	c1
	\alternativeKey b c \major
	c
	\alternativeKey e ees \major
	c
	\alternativeKey a aes \major
	c
	\alternativeKey #'parenthesized d des \major
	c
	\alternativeKey g ges \major
	c
	\alternativeKey c ces \major
	c
	\alternativeKey ges g \major
	c
	\alternativeKey des d \major
	c
        \alternativeKey aes a \major
        c
	\alternativeKey ees e \major
	c
	\alternativeKey bes b \major
	c
	\alternativeKey f fis \major
	c
	\alternativeKey ces cis \minor
	c
}