Hi, sometimes automatic cross-staff chords are requested here on the list. After some thinking I come up with the code below.
Though, I suspect there are flaws in it, if used in real world codings. I'd appreciate, if it would be tested in various situations. Here the code: \version "2.20.0" #(define (make-autosplit-chord chord . ref-pitch) "Return a pair of lists, containing the pitches of @var{chord}, splitted at a reference pitch. The reference pitch is derived from @var{ref-pitch}. If @var{ref-pitch} is empty, @code{c'} is regarded as reference. " (define ref-pitch-steps (if (and (pair? ref-pitch) (car ref-pitch)) (ly:pitch-steps (car ref-pitch)) 0)) (call-with-values (lambda () (partition (lambda (note) (> (ly:pitch-steps (ly:music-property note 'pitch)) ref-pitch-steps)) (event-chord-notes chord))) (lambda (x y) (cons x y)))) autoSplitChord = #(define-music-function (stem-dir staff-names pitch chord) ((ly:dir? 0) (pair? '("up" . "down")) (ly:pitch?) ly:music?) (_i "Split @var{chord} at optional @var{pitch}. The default of @var{pitch} is @code{#f}, which is interpreted by the called procedure @code{make-autosplit-chord} as @code{c'}. The splitted chords are distributed to named staves, relying on optional @var{staff-names}. The optional @var{stem-dir}, determines the direction of the stems and whether the chords may be connected by a cross-staff stem. The default results in unconnected chords. If the @code{Span_stem_engraver} is consisted, the chords may be connected by a cross-staff stem.") (let* ((skip (make-duration-of-length (ly:music-length chord))) (devided-pitches (make-autosplit-chord chord pitch)) (upper-chord (if (pair? (car devided-pitches)) (make-event-chord (car devided-pitches)) (make-skip-music skip))) (lower-chord (if (pair? (cdr devided-pitches)) (make-event-chord (cdr devided-pitches)) (make-skip-music skip)))) #{ << \context Staff = #(car staff-names) \context Voice { $(if (negative? stem-dir) #{ \once \override Stem.cross-staff = #cross-staff-connect \once \override Flag.style = #'no-flag <>\noBeam #}) $(if (not (zero? stem-dir)) #{ \once \override Stem.direction = #stem-dir #}) #upper-chord } \context Staff = #(cdr staff-names) \context Voice { $(if (positive? stem-dir) #{ \once \override Stem.cross-staff = #cross-staff-connect \once \override Flag.style = #'no-flag <>\noBeam #}) $(if (not (zero? stem-dir)) #{ \once \override Stem.direction = #stem-dir #}) #lower-chord } >> #})) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXAMPLES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \score { \new StaffGroup \with { \consists #Span_stem_engraver } << \new Staff = "up" \with { instrumentName = "up" } \new Voice = "foo" { \key g \major \clef "treble" <>^"possible stems" \autoSplitChord <f a d'' g''>4 \autoSplitChord #DOWN <f a d'' g''> \autoSplitChord #UP <f a d'' g''>2 \bar "||" <>^"various staves" %% While other staves are specified, the stems direction must be set %% as well. \autoSplitChord #CENTER #'("up" . "middle") <f a d' g'>4 \autoSplitChord #DOWN #'("middle" . "down") <f a d'' g''> %% If the chord is distributed in not descending order, \crossStaff %% needs to be set manually. See below in: \new Staff = "down" [...] \autoSplitChord #UP #'("down" . "middle") <f a d'' g''>2 \bar "||" <>^"other split pitch" %% While other split pitches are specified, the stems direction and %% staff-names must be set as well. \autoSplitChord #CENTER #'("up" . "down") a'' <f a d'' g''>4 \autoSplitChord #UP #'("up" . "down") e'' <f a d'' g''> \autoSplitChord #DOWN #'("up" . "down") g <f a d'' g''> \autoSplitChord #DOWN #'("up" . "down") e <f a d'' g''> \bar "||" } \new Staff = "middle" \with { instrumentName = "middle" } \new Voice = "bar" \crossStaff { \key g \major \clef "bass" s1*3 } \new Staff = "down" \with { instrumentName = "down" } \new Voice = "buzz" { \key g \major \clef "bass" s1 s2 \clef "treble" \crossStaff s2 s2 \clef "bass" s2 } >> \layout { ragged-right = ##f \override TextScript.staff-padding = 4 } } \new PianoStaff \with { \consists #Span_stem_engraver } << \new Staff = "up" \new Voice = "foo" { \key g \major \autoSplitChord #UP <f a a' f'>2 r2 R1 s2 c'2 \autoSplitChord #1 <f a a' f'>8 f'8 8 8 s2 \autoSplitChord #-1 <g d''>2 } \new Staff = "down" \new Voice = "bar" \crossStaff { \key g \major \clef bass s1 c1 \autoSplitChord #DOWN <f a a' f'>2 c2 s8 f f f \autoSplitChord #DOWN <f a a' f'>2 s2 } >> Thanks, Harm