lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Automatic cross-staff chords - testing help


From: Thomas Morley
Subject: Automatic cross-staff chords - testing help
Date: Fri, 25 Dec 2020 12:29:41 +0100

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]