\version "2.19.65" #(define equal-pitches-gliss ;; Only print a Glissando, if left and right bounding notes are the same. (lambda (grob) (let* ((orig (ly:grob-original grob)) (siblings (if (ly:grob? orig) (ly:spanner-broken-into orig) '())) ;; Get left/right bounds ;; For broken glissandi take first/last of siblings into account, to ;; get the relevant note-events. (left-bound (ly:spanner-bound (if (pair? siblings) (car siblings) grob) LEFT)) (right-bound (ly:spanner-bound (if (pair? siblings) (last siblings) grob) RIGHT)) (left-cause (ly:grob-property left-bound 'cause)) (right-cause (ly:grob-property right-bound 'cause)) (bound-pitch=? (and (ly:prob? left-cause) (ly:prob? right-cause) (equal? (ly:prob-property left-cause 'pitch) (ly:prob-property right-cause 'pitch))))) ;; The glissandi should be bounded by note-events, if not print a warning ;; to terminal, but no stencil. (ly:grob-set-property! grob 'stencil (cond (bound-pitch=? (ly:line-spanner::print grob)) ((not (and (ly:prob? left-cause) (ly:prob? right-cause))) (begin (ly:warning "No bounding note-events found, no stencil printed") #f)) (else #f)))))) #(define same-gliss-start-end ;; All glissandi between chords should start at the same X-coordinate, same ;; for glissando-endings. (lambda (grob) (let* ((left-bound (ly:spanner-bound grob LEFT)) (parent-nc (ly:grob-parent left-bound X)) (vertical-axis-group-elts (ly:grob-object (ly:grob-parent grob Y) 'elements)) ;; Filter VerticalAxisGroup-elements for Glissandi, restricted to ;; those starting at the NoteHeads from same NoteColumn. ;; Return their 'X-value for start/end (relevant-gliss-Xs (if (ly:grob-array? vertical-axis-group-elts) (filter-map (lambda (elt) (and (grob::has-interface elt 'glissando-interface) (equal? (ly:grob-parent (ly:spanner-bound elt LEFT) X) parent-nc) (cons (assoc-get 'X (ly:grob-property elt 'left-bound-info)) (assoc-get 'X (ly:grob-property elt 'right-bound-info))))) (ly:grob-array->list vertical-axis-group-elts)) '())) ;; Get the most left 'X for the final 'X-value of the end. ;; Get the most right 'X for the final 'X-value of the start. ;; Override left/right-bound-info with those values. (min-x-right (apply min (map cdr relevant-gliss-Xs))) (max-x-left (apply max (map car relevant-gliss-Xs)))) (ly:grob-set-nested-property! grob '(left-bound-info X) max-x-left) (ly:grob-set-nested-property! grob '(right-bound-info X) min-x-right)))) %% 'parser'/'location' are present to make it compile with 2.18.2 addGliss = #(define-music-function (parser location mus)(ly:music?) "Adds @code{\\glissando} to every found event-chord, unless already present. But not to the last event-chord." (let* ((evt-chrds (extract-typed-music mus 'event-chord))) (if (pair? evt-chrds) (for-each (lambda (m) (let* ((elts (ly:music-property m 'elements)) (glissando-present? (any (lambda (elt) (music-is-of-type? elt 'glissando-event)) elts))) (if (not glissando-present?) (ly:music-set-property! m 'articulations (cons (make-music 'GlissandoEvent) (ly:music-property m 'articulations)))))) (drop-right evt-chrds 1))) mus)) \score { \addGliss { \override Glissando.after-line-breaking = #(lambda (grob) (same-gliss-start-end grob) (equal-pitches-gliss grob)) \clef bass 1 2. 4-\tweak bound-details.right.padding #0.5 \glissando \break 2. 4 2. 4 2. 4 %% equal notes present, but different voicing, i.e. no glissando-line <>^"See comments in code" 2 \bar "||" %% trigger printed glissando with changed input order. 2 } \layout { \override Glissando.color = #red \override Glissando.thickness = 2.5 \override Glissando.breakable = ##t %% further customizing possible with tweaks/overrides like: \override Glissando.springs-and-rods = #ly:spanner::set-spacing-rods \override Glissando.minimum-length = 8 \override Glissando.bound-details.left.padding = #1 \override Glissando.bound-details.right.padding = #3 } }