Hi,

currently I'm trying to add crosses to the start and end of arbitrary Glissandi.
So far it works for unbroken and broken single-staff Glissando, as
well as for unbroken cross-staff Glissando.
Alas, I'm stuck for broken cross-staff Glissando.
Attached are the files with the already done steps.

Any hints?

tl;dr
This is preparatory work for getting Glissando with stems (Sometimes
seen in contemporary music.)
Thus the code is simplified, disregarding padding, possible left/right
text of the Glissando, no safety net for omitted stencils, etc.
Stems are not tackled at all.

Thanks,
  Harm
\version "2.25.29"

\paper {
  ragged-right = ##f
  ragged-last = ##t
}

\layout {
  \context {
    \Voice
    %% For the sake of simplicity:
    \override Glissando.bound-details.left.padding = 0
    \override Glissando.bound-details.right.padding = 0
  }
}

%% cross stencil
#(define* (make-cross-stencil coords #:optional (thick 0.1) (sz 0.4))
  "Print a x-cross-stencil at @var{coords} supposed to be a number pair."
  (ly:stencil-add
    (make-line-stencil
      thick
      (- (car coords) sz)
      (- (cdr coords) sz)
      (+ (car coords) sz)
      (+ (cdr coords) sz))
    (make-line-stencil
      thick
      (- (car coords) sz)
      (+ (cdr coords) sz)
      (+ (car coords) sz)
      (- (cdr coords) sz))))


glissandoX =
#(define-music-function (proc)(procedure?)
#{
  \override Glissando.stencil =
    #(grob-transformer 'stencil
      (lambda (grob orig)
        (apply ly:stencil-add orig
          (map
            (lambda (pt) (stencil-with-color (make-cross-stencil pt) red))
            (proc grob)))))
#})

oneStaffMusic = {
  d''2\glissando c' r d''\glissando
  \break
  s c'
  \bar "|."
}

crossStaffMusic =
  \new PianoStaff
    <<
      \new Staff = "top" { f''2\glissando \change Staff = "bottom" c, }
      \new Staff = "bottom" { \clef "bass" s1 \bar "|." }
    >>

crossStaffMusicBroken =
  \new PianoStaff
    <<
      \new Staff = "top" {
         \clef alto
         a''2\glissando \change Staff = "bottom" c,
         \change Staff = "top"
         a''1\glissando
         \break
         \change Staff = "bottom"
         \override NoteColumn.glissando-skip = ##t
         s2 c,
         \break
         s2 \revert NoteColumn.glissando-skip c,
      }
      \new Staff = "bottom" { \clef "bass" s1*4 \bar "|." }
    >>
% {
%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Attempt 1
%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (gliss-pts-1 grob)
  (let* ((left-bound-info (ly:grob-property grob 'left-bound-info))
         (right-bound-info (ly:grob-property grob 'right-bound-info))
         (X-left-coord (ly:assoc-get 'X left-bound-info 0))
         (Y-left-coord (ly:assoc-get 'Y left-bound-info 0))
         (X-right-coord (ly:assoc-get 'X right-bound-info 0))
         (Y-right-coord (ly:assoc-get 'Y right-bound-info 0)))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Coords are relative to the System grob, we want them relative to the
    ;; Glissando grob. Modifies X-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let* ((sys (ly:grob-system grob))
           (gliss-sys-x (ly:grob-relative-coordinate grob sys X)))
      (set! X-left-coord (- X-left-coord gliss-sys-x))
      (set! X-right-coord (- X-right-coord gliss-sys-x)))

    (list
      (cons X-left-coord Y-left-coord)
      (cons X-right-coord Y-right-coord))))

%% Attempt 1 example
\markup \box \fill-line {
  \column {
    "\\gliss-pts-1 is fine for simple Glissando"
    "It fails for broken ones"
  }
  \null
}

\score {
  \oneStaffMusic
  \layout { \context { \Voice \glissandoX #gliss-pts-1 } }
}
%}
% {
%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Attempt 2
%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (gliss-pts-2 grob)
  (let* ((left-bound-info (ly:grob-property grob 'left-bound-info))
         (right-bound-info (ly:grob-property grob 'right-bound-info))
         (X-left-coord (ly:assoc-get 'X left-bound-info 0))
         (Y-left-coord (ly:assoc-get 'Y left-bound-info 0))
         (X-right-coord (ly:assoc-get 'X right-bound-info 0))
         (Y-right-coord (ly:assoc-get 'Y right-bound-info 0)))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Coords are relative to the System grob, we want them relative to the
    ;; Glissando grob. Modifies X-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let* ((sys (ly:grob-system grob))
           (gliss-sys-x (ly:grob-relative-coordinate grob sys X)))
      (set! X-left-coord (- X-left-coord gliss-sys-x))
      (set! X-right-coord (- X-right-coord gliss-sys-x)))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Take normalized-endpoints into account. Modifies Y-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let ((y-length (- Y-right-coord Y-left-coord))
          (normalized-endpoints
            (ly:grob-property grob 'normalized-endpoints '(0 . 1))))
      (set! Y-left-coord
            (+ Y-left-coord (* (car normalized-endpoints) y-length)))
      (set! Y-right-coord
            (- Y-right-coord (* (- 1 (cdr normalized-endpoints)) y-length))))

    (list
      (cons X-left-coord Y-left-coord)
      (cons X-right-coord Y-right-coord))))

%% Attempt 2 examples
\markup \box \fill-line {
  \column {
    "\\gliss-pts-2 is fine for simple and broken Glissando."
    "It fails if cross-staff."
  }
  \null
}

\score {
  \oneStaffMusic
  \layout { \context { \Voice \glissandoX #gliss-pts-2 } }
}

\score {
  \crossStaffMusic
  \layout { \context { \Voice\glissandoX #gliss-pts-2 } }
}
%}
% {
%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Attempt 3
%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define (gliss-pts-3 grob)
  (let* ((left-bound-info (ly:grob-property grob 'left-bound-info))
         (right-bound-info (ly:grob-property grob 'right-bound-info))
         (X-left-coord (ly:assoc-get 'X left-bound-info 0))
         (Y-left-coord (ly:assoc-get 'Y left-bound-info 0))
         (X-right-coord (ly:assoc-get 'X right-bound-info 0))
         (Y-right-coord (ly:assoc-get 'Y right-bound-info 0)))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Coords are relative to the System grob, we want them relative to the
    ;; Glissando grob. Modifies X-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let* ((sys (ly:grob-system grob))
           (gliss-sys-x (ly:grob-relative-coordinate grob sys X)))
      (set! X-left-coord (- X-left-coord gliss-sys-x))
      (set! X-right-coord (- X-right-coord gliss-sys-x)))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Take normalized-endpoints into account. Modifies Y-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let ((y-length (- Y-right-coord Y-left-coord))
          (normalized-endpoints
            (ly:grob-property grob 'normalized-endpoints '(0 . 1))))
      (set! Y-left-coord
            (+ Y-left-coord (* (car normalized-endpoints) y-length)))
      (set! Y-right-coord
            (- Y-right-coord (* (- 1 (cdr normalized-endpoints)) y-length))))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Attempt for cross-staff Glissando. Modifies Y-coords.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (let ((cross-staff? (ly:grob-property grob 'cross-staff #f)))
      (when cross-staff?
        (let* ((val
                (ly:grob-common-refpoint
                 (ly:spanner-bound grob LEFT)
                 (ly:spanner-bound grob RIGHT) Y))
               (bound-right (ly:spanner-bound grob RIGHT))
               (bound-left (ly:spanner-bound grob LEFT))
               (bounds-delta-Y
                 (- (ly:grob-relative-coordinate bound-right val Y)
                    (ly:grob-relative-coordinate bound-left val Y))))
           (set! Y-right-coord (+ bounds-delta-Y Y-left-coord)))))

    (list
      (cons X-left-coord Y-left-coord)
      (cons X-right-coord Y-right-coord))))

%% Attempt 3 examples
\markup \box \fill-line {
  \column {
    "\\gliss-pts-3 is fine for simple and broken Glissando and unbroken
cross-staff."
    "It fails for broken cross-staff."
  }
  \null
}

\score {
  \oneStaffMusic
  \layout { \context { \Voice \glissandoX #gliss-pts-3 } }
}

\score {
  \crossStaffMusicBroken
  \layout {
    \context { \Voice\glissandoX #gliss-pts-3 }
    \context {
      \PianoStaff
      \override StaffGrouper.staff-staff-spacing =
      #'((minimum-distance . 0)
         (basic-distance . 0)
         (padding . 10)
         (stretchability . 0))
    }
  }
}
%}

Attachment: glissando-demo.pdf
Description: Adobe PDF document

Reply via email to