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))
}
}
}
%}
glissando-demo.pdf
Description: Adobe PDF document
