Am Do., 10. Okt. 2019 um 14:51 Uhr schrieb Leo Correia de Verdier <leo.correia.de.verd...@gmail.com>: > > Dear list! > > I'm soon going to start engraving a piece that contains very many glissandi > with timing marks (or actually, glissandi with broken bowing and > articulations during the way). The snippet in > http://lilypond.org/doc/v2.19/Documentation/notation/expressive-marks-as-lines#glissando > mentions the stems might need to be repositioned slightly, and I was > wondering if this would be possible to automate. > > I realize this will be complicated, since it (as I understand it at least) > will require changing stem lengths and notehead attachments after the > horizontal spacing is calculated (possibly changing pitches too, but the > solution I’m imagining would not do that). So I would need to access the > calculated positions of the stems and of the endpoints of the glissando. Is > that possible? Where and what do I need to read up to accomplish it? Or has > someone already done something similar? > > I have seen Piaras Hobans code in this thread: > https://lists.gnu.org/archive/html/lilypond-user/2014-03/msg00717.html , and > it’s interesting for me, but it relies on the stems being equally spaced, > which they shouldn’t be in my case. > > In the following example I’m looking for a way to calculate up and y-diff in > the glissNote function, instead of having to type them in by hand after > looking at the resulting score. (The gap between the stems and glissando-line > is intentional, the articulation positioning is just not done yet). I have > not done it minimal because I wanted to give a glimpse of the point of the > notation also. > > %%%%%%%%% > > \version "2.19.82" > > glissNote = #(define-music-function (up y-diff note) (boolean? number? > ly:music?) > #{ \tweak transparent ##t > \tweak no-ledgers ##t > \tweak stem-attachment #(cons (if up -1 1) y-diff) > #note #} ) > > glissRest = #(define-music-function (staff-position rest) (number? ly:music?) > #{ \tweak Y-offset #staff-position > \tweak layer #-1 > \tweak whiteout #10 > \parenthesize > #rest #} ) > > glissSkip = #(define-music-function (music) (ly:music?) > #{ \override NoteColumn.glissando-skip = ##t > #music > \revert NoteColumn.glissando-skip #} ) > > \relative c'' { > \time 6/8 > \set glissandoMap = #'((1 . 1)) > <a f'>16-> -\tweak layer #-2 \glissando > \glissSkip { > <a \glissNote ##f #.5 f'>8-. <a \glissNote ##f #0.3 f'>16-. <a \glissNote > ##f #.1 f'>8-> > << {\glissRest #2.5 r8 s4} \\ > {d,8_-_> <a' \glissNote ##f #-0.4 f'>^. <a \glissNote ##f #-.6 f'>^.} > >> > } > \time 2/4 <a a'>2-- > } > > %%%%%%%%%% > > Thanks a lot! > /Leo
Hi Leo, the topic of glissando-stems pops up from time to time. See older discussions, p.e. here: https://codereview.appspot.com/4661061/#ps1 Some time ago I started to code something in this regard and took your request to polish it a bit. Though, there are still some TODOs: - Scripts are not always positioned nicely. - "Inner" beams 'positions can't be affected from Glissando.after-line-breaking. etc Furthermore I'm not sure the whole approach fits your needs. Nevertheless the code is attached, probably you'll find the calculation for "gliss-stem-intersections" helpful. Cheers, Harm
\version "2.19.83" #(define (make-cross-stencil coords) (let ((thick 0.1) (sz 0.2)) (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))))) %% Glissando has no pointer to the covered NoteColumns, because in most %% traditional music NoteColumns are *not* skipped. %% Thus reading those NoteColumns is inconvenient. %% Correcting Beam.positions is impossible here either. For this pupose an %% additional override is needed. #(define (glissando-and-stems pad-y) (lambda (grob) (let* ((layout (ly:grob-layout grob)) (blot (ly:output-def-lookup layout 'blot-diameter)) (staff-symbol (ly:grob-object grob 'staff-symbol)) (staff-symbol-line-positions (ly:grob-property staff-symbol 'line-positions '(-4 -2 0 2 4))) (top-staff-line (apply max staff-symbol-line-positions)) (bottom-staff-line (apply min staff-symbol-line-positions)) (staff-space (ly:staff-symbol-staff-space grob)) (half-line-thick (/ (ly:staff-symbol-line-thickness grob) 2)) (original (ly:grob-original grob)) (left-bound (ly:spanner-bound original LEFT)) (right-bound (ly:spanner-bound original RIGHT)) (left-bound-when (grob::when left-bound)) (right-bound-when (grob::when right-bound)) ;(stil (ly:grob-property grob 'stencil)) (stil (ly:line-spanner::print grob)) (stil-x-ext (ly:stencil-extent stil X)) (stil-y-ext (ly:stencil-extent stil Y)) (left-bound-info (ly:grob-property grob 'left-bound-info)) (X-left (assoc-get 'X left-bound-info)) (Y-left (assoc-get 'Y left-bound-info)) (left-padding (assoc-get 'padding left-bound-info)) (right-bound-info (ly:grob-property grob 'right-bound-info)) (X-right (assoc-get 'X right-bound-info)) (Y-right (assoc-get 'Y right-bound-info)) (gliss-gradient (/ (- Y-right Y-left) (- X-right X-left))) (sys (ly:grob-system grob)) (sys-elts-array (ly:grob-object sys 'all-elements)) (ncs (filter (lambda (elt) (let (;; Going for `ly:grob-relative-coordinate´ disturbs ;; vertical spacing, thus we sort/filter using ;; `grob::when´ (elt-when (grob::when elt))) (and (grob::has-interface elt 'note-column-interface) (ly:grob-property elt 'glissando-skip #f) (ly:grob-array? (ly:grob-object elt 'note-heads)) (ly:moment<? left-bound-when elt-when) (not (ly:moment<? right-bound-when elt-when))))) (ly:grob-array->list sys-elts-array))) ;; Stems from all NoteColumns covered by the Glissando (stems (map (lambda (nc) (ly:grob-object nc 'stem)) ncs)) (stem-begin-positions (map (lambda (stem) (ly:grob-property stem 'stem-begin-position)) stems)) (stems-x-coords (map (lambda (nc) (ly:grob-relative-coordinate (ly:grob-object nc 'stem) sys X)) ncs)) (gliss-stem-intersections (map (lambda (stem-x-coord) (cons ;; TODO do we need the x-value at all? (+ (- stem-x-coord X-left) (- (car stil-x-ext) left-padding) half-line-thick) (+ (* gliss-gradient (+ (- stem-x-coord X-left) (- (car stil-x-ext) left-padding) half-line-thick (- (+ (car stil-x-ext) half-line-thick)))) (if (negative? gliss-gradient) (- (cdr stil-y-ext) half-line-thick) (+ (car stil-y-ext) half-line-thick))))) stems-x-coords))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; For conveniance/debugging ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Color left/right bound ;;;;;;;;;;;;;;;;;;;;;; ;(ly:grob-set-property! left-bound 'color red) ;(ly:grob-set-property! right-bound 'color green) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Color passed note-heads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;for-each ; (lambda (nh) ; (ly:grob-set-property! nh 'stencil (ly:note-head::print nh)) ; (ly:grob-set-property! nh 'color cyan)) ; (append-map ; (lambda (nc) ; (ly:grob-array->list (ly:grob-object nc 'note-heads))) ; ncs)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Add cross-stencils where Stem and Glissando intersect ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;(ly:grob-set-property! grob 'stencil ; (apply ly:stencil-add ; (ly:grob-property grob 'stencil) ; (map make-cross-stencil gliss-stem-intersections))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Recreate Stem.stencil to match the glissando ;; Move Flag ;; Move Script ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (for-each (lambda (gsi stem) (let* ((stem-length (ly:grob-property stem 'length)) (stem-y-ext (ly:grob-extent stem stem Y)) (stem-y-length (- (cdr stem-y-ext) (car stem-y-ext))) (stem-dir (ly:grob-property stem 'direction)) (pap-col (ly:item-get-column stem)) (pap-col-elts-array (ly:grob-object pap-col 'elements)) (scripts (filter (lambda (elt) (grob::has-interface elt 'script-interface)) (ly:grob-array->list pap-col-elts-array))) (beam (ly:grob-object stem 'beam)) (new-stem-y-ext (ordered-cons (+ (cdr gsi) (* stem-dir pad-y)) (if (ly:grob? beam) (begin ;(pretty-print stem-length) (if (negative? stem-dir) (car stem-y-ext) (cdr stem-y-ext)) ) (+ (* stem-dir stem-y-length) (cdr gsi) (* stem-dir pad-y))))) (flag (ly:grob-object stem 'flag)) (flag-stil (if (and (ly:grob? flag) (grob::has-interface flag 'flag-interface)) (ly:grob-property flag 'stencil) #f))) ;;;;;;;;;;; ;; move scripts according to new Stem.stencil below ;;;;;;;;;;; (if (pair? scripts) (begin (for-each (lambda (i script) (let* ((script-stil (ly:grob-property script 'stencil)) (script-y-off (ly:grob-property script 'Y-offset)) (script-padding (ly:grob-property script 'padding))) ;; TODO Scripts should avoid staff-lines! ;; Special-case some scripts? (ly:grob-set-property! script 'stencil (ly:stencil-translate-axis (ly:grob-property script 'stencil) (+ ;; move script to zero-line (- script-y-off) ;; move script to glissando-line (cdr gsi) ;; Apply one staff-space padding for each script. ;; There are probably multiple ones per ;; NoteColumn (* i staff-space stem-dir -1) (* script-padding stem-dir -1)) Y)))) (iota (length scripts) 1 1) scripts))) ;;;;;;;;;;; ;; move Flag.stencil according to new Stem.stencil below ;;;;;;;;;;; (if flag-stil (let ((default-stem-end (if (positive? stem-dir) (cdr stem-y-ext) (car stem-y-ext))) (new-stem-end (if (positive? stem-dir) (cdr new-stem-y-ext) (car new-stem-y-ext)))) (ly:grob-set-property! flag 'stencil (ly:stencil-translate-axis flag-stil (- new-stem-end default-stem-end) Y)))) ;;;;;;;;;;; ;; recreate a new Stem.stencil ;;;;;;;;;;; (ly:grob-set-property! stem 'stencil (ly:round-filled-box (ly:grob-extent stem stem X) new-stem-y-ext blot)))) gliss-stem-intersections stems)))) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXAMPLES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Not essential, only to ease testings multipleTransposes = #(define-music-function (parser location m music)(ly:music? ly:music?) (music-clone m 'elements (map (lambda (pitch) (ly:music-property #{ \transpose c $pitch $music #} 'element)) (event-chord-pitches m)))) glissOn = { \temporary \override NoteColumn.glissando-skip = ##t \temporary \override NoteHead.stem-attachment = #'(0 . 0) %\temporary \override NoteHead.stencil = #point-stencil \temporary \override NoteHead.transparent = ##t \temporary \override NoteHead.no-ledgers = ##t \temporary \override Accidental.stencil = ##f \temporary \override Stem.no-stem-extend = ##t } glissOff = { \revert NoteColumn.glissando-skip \revert NoteHead.stem-attachment %\revert NoteHead.stencil \revert NoteHead.transparent \revert NoteHead.no-ledgers \revert Accidental.stencil \revert Stem.no-stem-extend } mus = { c''4\glissando \glissOn b'8-. \noBeam b'-> bes'-. \noBeam bes'-. a'[-_ aes']-.---\prall \glissOff g'1 } \multipleTransposes { c, d, e, f, g, a, b, c d e f g a b } { \override NoteHead.layer = -1000 \override Glissando.after-line-breaking = #(glissando-and-stems 0.3) \mus }
_______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user