Initial clef change
Appearance
This snippet handles initial clef changes with a custom engraver. This engraver checks whether there is a difference between the initial clef (as given by \with { \clef ... } and the clef at the first timestep. If any difference is encountered a new clef (spaced like a cue clef) is created, while the original clef and any key signatures are modified to look like the initial clef values. See also the snippets Clef change at the beginning of a piece and Clef change at the beginning of a piece (alternative).
\version "2.24"
%%% This engraver records the initial clef properties (e.g. what is set by \with { \clef ... })
%%% If in the first timestep these changed, engrave the original clef, and change formatting and break
%%% alignment of the actual clef to mimic a clef change clef. Duplicates some procedure from clef engraver
%%% and could easily be integrated.
#(define (initial-clef-change-engraver context)
(let ((initial-clef-properties #f) (cclef #f) (keysigs '()))
; macro for checking if any clef property has changed
(define (clef-changed)
(>
(length initial-clef-properties)
(length
(filter
(lambda (x) (equal? (cdr x) (ly:context-property context (car x))))
initial-clef-properties))))
(make-engraver
; Record initials propertis
((initialize engraver)
(set!
initial-clef-properties
`((clefGlyph . ,(ly:context-property context 'clefGlyph))
(clefPosition . ,(ly:context-property context 'clefPosition))
(middleCClefPosition . ,(ly:context-property context 'middleCClefPosition))
(clefTransposition . ,(ly:context-property context 'clefTransposition)))))
; Record the actual clef to adjust. Use details.muted to not acknowledge clef created by this engraver.
(acknowledgers
((clef-interface engraver grob source-engraver)
(if (not (assoc-get 'muted (ly:grob-property grob 'details) #f))
(set! cclef grob)))
((key-signature-interface engraver grob source-engraver)
(set! keysigs (cons grob keysigs))))
; Create a clef if necessary
((process-music engraver)
(if (and initial-clef-properties (clef-changed))
(let ((clef (ly:engraver-make-grob engraver 'Clef '())))
(ly:grob-set-property! clef 'staff-position (assoc-get 'clefPosition initial-clef-properties))
(ly:grob-set-property! clef 'glyph (assoc-get 'clefGlyph initial-clef-properties))
(ly:grob-set-nested-property! clef '(details muted) #t)
(if ((lambda (x) (and (number? x) (not (= 0 x))))
(assoc-get 'clefTransposition initial-clef-properties 0))
(let ((mod (ly:engraver-make-grob engraver 'ClefModifier '()))
(formatter (ly:context-property context 'clefTranspositionFormatter))
(style (ly:context-property context 'clefTranspositionStyle))
(dir (sign (assoc-get 'clefTransposition initial-clef-properties 0)))
(abs_trans (1+ (abs (assoc-get 'clefTransposition initial-clef-properties 0)))))
(if (procedure? formatter)
(ly:grob-set-property! mod 'text (formatter (number->string abs_trans) style)))
(ly:grob-set-object! mod 'side-support-elements (ly:grob-list->grob-array (list clef)))
(ly:grob-set-parent! mod X clef)
(ly:grob-set-parent! mod Y clef)
(ly:grob-set-property! mod 'direction dir))))))
; Adjust the actual clef and key signatures
((process-acknowledged engraver)
(if (and cclef initial-clef-properties (clef-changed))
(begin
; Key signatures need to be handled if they appear before the cue-clef
; This requires the break alignment information, so this only sets a
; hook which will be processed during `before-line-breaking` of the
; BreakAlignGroups
(for-each
(lambda (keysig)
(let ((det (ly:grob-property keysig 'details))
(initial-clef-properties initial-clef-properties))
(ly:grob-set-property!
keysig
'details
(acons
'break-alignment-handler
(lambda (grob break-alignment)
(let ((start-of-line
(vector-ref
(ly:grob-property break-alignment 'break-align-orders)
2)))
(if (member 'cue-clef (or (member 'key-signature start-of-line) '()))
(ly:grob-set-property!
grob 'c0-position
(assoc-get 'middleCClefPosition initial-clef-properties)))))
det))))
keysigs)
(ly:grob-set-property! cclef 'non-default #t)
(ly:grob-set-property! cclef 'break-align-symbol 'cue-clef)
(if (not (eq? #t (ly:grob-property cclef 'full-size-change)))
(ly:grob-set-property! cclef 'glyph-name
(format #f "~a_change" (ly:grob-property cclef 'glyph)))))))
; Unset parameters
((stop-translation-timestep engraver)
(set! initial-clef-properties #f)
(set! clef #f)
(set! keysigs '())))))
\layout {
\context {
\Staff
\consists #initial-clef-change-engraver
}
\context {
\Score
\override BreakAlignGroup.before-line-breaking =
#(lambda (grob)
(let ((grobs (ly:grob-object grob 'elements))
(break-alignment (ly:grob-parent grob X)))
(if (not (null? grobs))
(set! grobs (ly:grob-array->list grobs)))
(for-each
(lambda (grob)
(let* ((det (ly:grob-property grob 'details))
(handler (assoc-get 'break-alignment-handler det)))
(if (procedure? handler)
(handler grob break-alignment))))
grobs)))
}
}
\new Staff \with { \clef "bass^15" } {
\key bes\major
\clef "treble_8"
c'1 c'1
\clef bass
c'1
}
\score {
\layout {
\context {
\Score
\override BreakAlignment.break-align-orders =
##((staff-ellipsis
left-edge
cue-end-clef
ambitus
breathing-sign
optional-material-end-bracket
signum-repetitionis
clef
cue-clef
staff-bar
key-cancellation
key-signature
time-signature
optional-material-start-bracket
custos)
(staff-ellipsis
left-edge
optional-material-end-bracket
cue-end-clef
ambitus
breathing-sign
signum-repetitionis
clef
cue-clef
staff-bar
key-cancellation
key-signature
time-signature
optional-material-start-bracket
custos)
(staff-ellipsis
left-edge
optional-material-end-bracket
ambitus
breathing-sign
signum-repetitionis
clef
cue-clef
key-cancellation
key-signature
time-signature
staff-bar
optional-material-start-bracket
custos))
}
}
\new Staff \with { \clef "bass^15" } {
\key bes\major
\clef "treble_8"
c'1 c'1
\clef bass
c'1
}
}
% Basic usage:
\score {
<<
% Just the treble clef
\new Staff {
\key bes \major
c''1
}
% Just the bass clef
\new Staff \with { \clef bass } {
\key bes \major
c1
}
% Initial treble clef, then bass clef
\new Staff {
\key bes \major
\clef bass
c1
}
% Initial bass clef, then treble clef
\new Staff \with { \clef bass } {
\key bes \major
\clef treble
c''1
}
>>
\layout {
\context {
\Staff
\consists #initial-clef-change-engraver
}
}
}