Re: Vibrato (wavy lines) notation
Hello Jean, That makes sense, thank you (I supposed it was something legacy, else why would it be there?). Cheers, Valentin Am Freitag, 14. Jänner 2022, 21:59:31 CET schrieb Jean Abou Samra: > Le 14/01/2022 à 20:41, Valentin Petzel a écrit : > > Hello Richard, > > > > The file you’ve given us has a lot of nonsensical quoting in lines > > 149-153. > > Actually, not completely nonsensical, but legacy. There used to > be one more level of quoting inside stencil expressions until > > commit 06ba7f0823a14da773391ccf3c10244a54e812d4 > Author: Han-Wen Nienhuys > Date: Sun Aug 2 21:47:25 2020 +0200 > > Dispatch stencil routines using explicit tables > > scm_eval in GUILE became much more elaborate to deal with byte code > (2.2) and JIT compilation (3.0). This means that scm_eval has more > overhead for single shot code: > > * setup temporary storage for bytecode/JIT'd x86 code > * run up and down the syntax tree applying optimizations > * other magic that compiler folks do to make things run faster > > The Scheme expressions for stencils aren't generalized code; they are > just a device-independent description of the output. In particular, > they have no advanced construct (loops, conditionals, tail calls, > variable bindings, variable references), also, they are run only > once. So all the work that scm_eval does to produce faster code is > just overhead. > > The change makes it explicit that the data is just literal data, and > does the one thing to specialize it from device-independent to > device-specific, which is replacing symbols with their definitions > from output-ps.scm > > Because output expression do not pass through eval anymore, we stop > quoting symbol and list values. > > Backend implementors should take the following changes into account: > > * placebox is removed. Instead each stencil expression is surrounded >by settranslation and resettranslation > > * ly:make-paper-outputter takes a single function as argument. The >function takes the Scheme expression, for example, > > (circle 10 0.1 #t) > >as argument. > > * A paper-outputter no longer is associated with a module. For the SVG >backend, this is solved by creating some backend-specific >expressions (set-paper, set-unit-length) which the eval-svg function >treats specially. > > Markup/stencil implementors should take the following changes into > account: > > * Stencil expressions are no longer passed through the eval >function. This means that all inner (quasi)quoting should be >removed. > > Tested >lilypond -dbackend=svg input/regression/les-nereides > > Timing > > In verbose mode, the backend output phase will print timing. This > timing leads to the following data for (MSDM-reduced, 2Ghz CPU): > > Current master > - Guile 1.8: 0.74s > - Guile 2.2: 4.73s > - Guile 3.0: 2.49s > > This commit > - Guile 1.8: 0.80s > - Guile 2.2: 1.41s > - Guile 3.0: 1.20s > > > Basically `(path ...) is already quasi-quoted, so there is no reason to > > quote the symbol round (as it is already quoted). > > Well, but there was. > > `round > => round > > `'round > => (quote round) > > This extra quote was necessary in 2.20. > > > Also you will get an error for > > line 150 where we have > > > > `(,@',(concatenate path-final)) > > > > So we first quasi-quote something that is already quasi-quoted, then we > > create a list, use an unquote splice operator (,@), which basically > > evaluates the expression to a list and then gives the entries of the list > > instead of the list (note we are CREATING a list first just to splice > > something into it – instead of this we can simply do ,(concatenate > > path-final)), then we are quoting the whole thing we just unquoted again > > to add another unquote, which does not work as the last quote was not a > > quasi-quote. > > > > So to get it to work closest to what’s in the file we’d need to do > > > > (,@`,(concatenate path-final)) > > > > Or alternatively > > > > ,`(,@`,(concatenate path-final)) > > > > But much more intelligent would be simply doing this: > > > > ,(concatenate path-final) > > Yes, in 2.22, and in 2.20 you are right that it > can be simplified, but to ',(concatenate path-final) > with an extra quote at the beginning. > > Anyway, here is a largely simplified version of this > snippet: > > > \version "2.22.1" > > #(use-modules (ice-9 match)) > > #(set-object-property! 'curvature-factor 'backend-type? number?) > > vibrato = > #(define-music-function (amplitudes wave-length) (list? number?) > #{ > \once \override TrillSpanner.normalized-endpoints = > #ly:spanner::calc-normalized-endpoints > \once \override TrillSpanner.curvature-factor = 0.35 > \once \override Tr
Re: Vibrato (wavy lines) notation
On Fri, 2022-01-14 at 20:41 +0100, Valentin Petzel wrote: > Hello Richard, > > The file you’ve given us has a lot of nonsensical quoting in lines > 149-153. > > Basically `(path ...) is already quasi-quoted, so there is no reason > to quote > the symbol round (as it is already quoted). Also you will get an > error for > line 150 where we have > > `(,@',(concatenate path-final)) > > So we first quasi-quote something that is already quasi-quoted, then > we create > a list, use an unquote splice operator (,@), which basically > evaluates the > expression to a list and then gives the entries of the list instead > of the > list (note we are CREATING a list first just to splice something into > it – > instead of this we can simply do ,(concatenate path-final)), then we > are > quoting the whole thing we just unquoted again to add another > unquote, which > does not work as the last quote was not a quasi-quote. > > So to get it to work closest to what’s in the file we’d need to do > > (,@`,(concatenate path-final)) > > Or alternatively > > ,`(,@`,(concatenate path-final)) > > But much more intelligent would be simply doing this: > > ,(concatenate path-final) > > I have appended a fixed version of your file. > > Cheers, > Valentin Thank you and Jean Abou for your quick and insightful replies - my score is once more typesetting beautifully. Richard
Re: Vibrato (wavy lines) notation
Le 14/01/2022 à 20:41, Valentin Petzel a écrit : Hello Richard, The file you’ve given us has a lot of nonsensical quoting in lines 149-153. Actually, not completely nonsensical, but legacy. There used to be one more level of quoting inside stencil expressions until commit 06ba7f0823a14da773391ccf3c10244a54e812d4 Author: Han-Wen Nienhuys Date: Sun Aug 2 21:47:25 2020 +0200 Dispatch stencil routines using explicit tables scm_eval in GUILE became much more elaborate to deal with byte code (2.2) and JIT compilation (3.0). This means that scm_eval has more overhead for single shot code: * setup temporary storage for bytecode/JIT'd x86 code * run up and down the syntax tree applying optimizations * other magic that compiler folks do to make things run faster The Scheme expressions for stencils aren't generalized code; they are just a device-independent description of the output. In particular, they have no advanced construct (loops, conditionals, tail calls, variable bindings, variable references), also, they are run only once. So all the work that scm_eval does to produce faster code is just overhead. The change makes it explicit that the data is just literal data, and does the one thing to specialize it from device-independent to device-specific, which is replacing symbols with their definitions from output-ps.scm Because output expression do not pass through eval anymore, we stop quoting symbol and list values. Backend implementors should take the following changes into account: * placebox is removed. Instead each stencil expression is surrounded by settranslation and resettranslation * ly:make-paper-outputter takes a single function as argument. The function takes the Scheme expression, for example, (circle 10 0.1 #t) as argument. * A paper-outputter no longer is associated with a module. For the SVG backend, this is solved by creating some backend-specific expressions (set-paper, set-unit-length) which the eval-svg function treats specially. Markup/stencil implementors should take the following changes into account: * Stencil expressions are no longer passed through the eval function. This means that all inner (quasi)quoting should be removed. Tested lilypond -dbackend=svg input/regression/les-nereides Timing In verbose mode, the backend output phase will print timing. This timing leads to the following data for (MSDM-reduced, 2Ghz CPU): Current master - Guile 1.8: 0.74s - Guile 2.2: 4.73s - Guile 3.0: 2.49s This commit - Guile 1.8: 0.80s - Guile 2.2: 1.41s - Guile 3.0: 1.20s Basically `(path ...) is already quasi-quoted, so there is no reason to quote the symbol round (as it is already quoted). Well, but there was. `round => round `'round => (quote round) This extra quote was necessary in 2.20. Also you will get an error for line 150 where we have `(,@',(concatenate path-final)) So we first quasi-quote something that is already quasi-quoted, then we create a list, use an unquote splice operator (,@), which basically evaluates the expression to a list and then gives the entries of the list instead of the list (note we are CREATING a list first just to splice something into it – instead of this we can simply do ,(concatenate path-final)), then we are quoting the whole thing we just unquoted again to add another unquote, which does not work as the last quote was not a quasi-quote. So to get it to work closest to what’s in the file we’d need to do (,@`,(concatenate path-final)) Or alternatively ,`(,@`,(concatenate path-final)) But much more intelligent would be simply doing this: ,(concatenate path-final) Yes, in 2.22, and in 2.20 you are right that it can be simplified, but to ',(concatenate path-final) with an extra quote at the beginning. Anyway, here is a largely simplified version of this snippet: \version "2.22.1" #(use-modules (ice-9 match)) #(set-object-property! 'curvature-factor 'backend-type? number?) vibrato = #(define-music-function (amplitudes wave-length) (list? number?) #{ \once \override TrillSpanner.normalized-endpoints = #ly:spanner::calc-normalized-endpoints \once \override TrillSpanner.curvature-factor = 0.35 \once \override TrillSpanner.stencil = #(let* ((n-amplitudes-1 (1- (length amplitudes (grob-transformer 'stencil (lambda (grob original) (if (ly:stencil? original) (match-let* (((left . right) (ly:grob-property grob 'normalized-endpoints)) (left-idx (inexact->exact (round (* n-amplitudes-1 left (right-idx (inexact->exact (round (* n-amplitudes-1 right (sublist (match (drop (take amplitudes
Re: Vibrato (wavy lines) notation
Hello Richard, The file you’ve given us has a lot of nonsensical quoting in lines 149-153. Basically `(path ...) is already quasi-quoted, so there is no reason to quote the symbol round (as it is already quoted). Also you will get an error for line 150 where we have `(,@',(concatenate path-final)) So we first quasi-quote something that is already quasi-quoted, then we create a list, use an unquote splice operator (,@), which basically evaluates the expression to a list and then gives the entries of the list instead of the list (note we are CREATING a list first just to splice something into it – instead of this we can simply do ,(concatenate path-final)), then we are quoting the whole thing we just unquoted again to add another unquote, which does not work as the last quote was not a quasi-quote. So to get it to work closest to what’s in the file we’d need to do (,@`,(concatenate path-final)) Or alternatively ,`(,@`,(concatenate path-final)) But much more intelligent would be simply doing this: ,(concatenate path-final) I have appended a fixed version of your file. Cheers, Valentin\version "2.22.0" %% https://raw.githubusercontent.com/mwitmer/LyUtil/master/ly/expressive_markings/vibrato.ly %% Original author: Mark Witmer %% Rewritten version by Harm #(define (line-part-min-max x1 x2) (list (min x1 x2) (max x1 x2))) #(define (bezier-part-min-max x1 x2 x3 x4) ((lambda (x) (list (reduce min 1 x) (reduce max -1 x))) (map (lambda (x) (+ (* x1 (expt (- 1 x) 3)) (+ (* 3 (* x2 (* (expt (- 1 x) 2) x))) (+ (* 3 (* x3 (* (- 1 x) (expt x 2 (* x4 (expt x 3)) (if (< (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3 (list 0.0 1.0) (filter (lambda (x) (and (>= x 0) (<= x 1))) (append (list 0.0 1.0) (map (lambda (op) (if (not (eqv? 0.0 (exact->inexact (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2)) ;; Zeros of the bezier curve (/ (+ (- x1 (* 2 x2)) (op x3 (sqrt (- (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3))) (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2 ;; Apply L'hopital's rule to get the zeros if 0/0 (* (op 0 1) (/ (/ (- x4 x3) 2) (sqrt (- (+ (* x2 x2) (+ (* x3 x3) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3) (list + - #(define (bezier-min-max x1 y1 x2 y2 x3 y3 x4 y4) (map (lambda (x) (apply bezier-part-min-max x)) `((,x1 ,x2 ,x3 ,x4) (,y1 ,y2 ,y3 ,y4 #(define (line-min-max x1 y1 x2 y2) (map (lambda (x) (apply line-part-min-max x)) `((,x1 ,x2) (,y1 ,y2 #(define (path-min-max origin pointlist) ((lambda (x) (list (reduce min +inf.0 (map caar x)) (reduce max -inf.0 (map cadar x)) (reduce min +inf.0 (map caadr x)) (reduce max -inf.0 (map cadadr x (map (lambda (x) (if (= (length x) 8) (apply bezier-min-max x) (apply line-min-max x))) (map (lambda (x y) (append (list (cadr (reverse x)) (car (reverse x))) y)) (append (list origin) (reverse (cdr (reverse pointlist pointlist #(define (make-path-stencil path thickness x-scale y-scale fill) "Make a stencil based on the path described by the list @var{path}, with thickness @var{thickness}, and scaled by @var{x-scale} in the X direction and @var{y-scale} in the Y direction. @var{fill} is a boolean argument that specifies if the path should be filled. Valid path commands are: moveto rmoveto lineto rlineto curveto rcurveto closepath, and their standard SVG single letter equivalents: M m L l C c Z z." (define (convert-path path origin previous-point) "Recursive function to standardize command names and convert any relative path expressions (in @var{path}) to absolute values. Returns a list of lists. @var{origin} is a pair of x and y coordinates for the origin point of the path (used for closepath and reset by moveto commands). @var{previous-point} is a pair of x and y coordinates for the previous point in the path." (if (pair? path) (let* ((head-raw (car path)) (rest (cdr path)) (head (cond ((memq head-raw '(rmoveto M m)) 'moveto) ((memq head-raw '(rlineto L l)) 'lineto) ((memq head-raw '(rcurveto C c)) 'curveto)
Re: Vibrato (wavy lines) notation
On Mon, 2018-03-26 at 21:06 +0100, Richard Shann wrote: > On Mon, 2018-03-26 at 11:53 +0200, Thomas Morley wrote: > > 2018-03-25 21:13 GMT+02:00 Richard Shann : > > > I have been using a bit of code written by Mark Witmer to achieve > > > wavy > > > > [...] someone can suggest a > > > correct way to handle line breaks with these vibrato markings. > > Hi, > > > > you may be interested in > > > > http://lilypond.1069038.n5.nabble.com/How-to-make-this-postscript-spa > > nner-to-work-with-L-amp-R-bound-details-td204375.html#a204622 > > That's great. I notice it uses make-path-stencil which is not in > 2.18, > in fact I couldn't trace the documentation for it in 2.19 either, it > seems to be just mentioned in the Changes document > http://lilypond.org/doc/v2.19/Documentation/changes/index.html > > In case it may be useful to anyone I've attached a 2.18 version which > also takes a thickness parameter. > > Richard I've been trying to typeset a file using these wavy lines with LilyPond 22.2 and it throws an obscure error (this is after running convert.ly). /usr/share/lilypond/2.22.0/scm/output-ps.scm:272:49: In procedure symbol->string in expression (symbol->string join): /usr/share/lilypond/2.22.0/scm/output-ps.scm:272:49: Wrong type argument in position 1 (expecting symbol): (quote round) Exited with return code 1. Attached is the vibrato.ily from before with an test example at the end. I notice that a variable name "round" is used whose name clashes with a Scheme procedure, but that doesn't seem to be the cause of the problem. Any ideas? Richard Shann \version "2.22.0" %% https://raw.githubusercontent.com/mwitmer/LyUtil/master/ly/expressive_markings/vibrato.ly %% Original author: Mark Witmer %% Rewritten version by Harm #(define (line-part-min-max x1 x2) (list (min x1 x2) (max x1 x2))) #(define (bezier-part-min-max x1 x2 x3 x4) ((lambda (x) (list (reduce min 1 x) (reduce max -1 x))) (map (lambda (x) (+ (* x1 (expt (- 1 x) 3)) (+ (* 3 (* x2 (* (expt (- 1 x) 2) x))) (+ (* 3 (* x3 (* (- 1 x) (expt x 2 (* x4 (expt x 3)) (if (< (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3 (list 0.0 1.0) (filter (lambda (x) (and (>= x 0) (<= x 1))) (append (list 0.0 1.0) (map (lambda (op) (if (not (eqv? 0.0 (exact->inexact (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2)) ;; Zeros of the bezier curve (/ (+ (- x1 (* 2 x2)) (op x3 (sqrt (- (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3))) (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2 ;; Apply L'hopital's rule to get the zeros if 0/0 (* (op 0 1) (/ (/ (- x4 x3) 2) (sqrt (- (+ (* x2 x2) (+ (* x3 x3) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3) (list + - #(define (bezier-min-max x1 y1 x2 y2 x3 y3 x4 y4) (map (lambda (x) (apply bezier-part-min-max x)) `((,x1 ,x2 ,x3 ,x4) (,y1 ,y2 ,y3 ,y4 #(define (line-min-max x1 y1 x2 y2) (map (lambda (x) (apply line-part-min-max x)) `((,x1 ,x2) (,y1 ,y2 #(define (path-min-max origin pointlist) ((lambda (x) (list (reduce min +inf.0 (map caar x)) (reduce max -inf.0 (map cadar x)) (reduce min +inf.0 (map caadr x)) (reduce max -inf.0 (map cadadr x (map (lambda (x) (if (= (length x) 8) (apply bezier-min-max x) (apply line-min-max x))) (map (lambda (x y) (append (list (cadr (reverse x)) (car (reverse x))) y)) (append (list origin) (reverse (cdr (reverse pointlist pointlist #(define (make-path-stencil path thickness x-scale y-scale fill) "Make a stencil based on the path described by the list @var{path}, with thickness @var{thickness}, and scaled by @var{x-scale} in the X direction and @var{y-scale} in the Y direction. @var{fill} is a boolean argument that specifies if the path should be filled. Valid path commands are: moveto rmoveto lineto rlineto curveto rcurveto closepath, and their standard SVG single letter equivalents: M m L l C c Z z." (define (convert-path path origin previous-point) "Recursive function to standardize command names and convert any relative path expressions (in @var{path}) to absolute values. Returns a list of lists. @var{origin} is a pair of x and y coordinates for th
Re: Vibrato (wavy lines) notation
On Mon, 2018-03-26 at 11:53 +0200, Thomas Morley wrote: > 2018-03-25 21:13 GMT+02:00 Richard Shann : > > I have been using a bit of code written by Mark Witmer to achieve > > wavy > > [...] someone can suggest a > > correct way to handle line breaks with these vibrato markings. > Hi, > > you may be interested in > http://lilypond.1069038.n5.nabble.com/How-to-make-this-postscript-spa > nner-to-work-with-L-amp-R-bound-details-td204375.html#a204622 That's great. I notice it uses make-path-stencil which is not in 2.18, in fact I couldn't trace the documentation for it in 2.19 either, it seems to be just mentioned in the Changes document http://lilypond.org/doc/v2.19/Documentation/changes/index.html In case it may be useful to anyone I've attached a 2.18 version which also takes a thickness parameter. Richard %\version "2.18.2" %% https://raw.githubusercontent.com/mwitmer/LyUtil/master/ly/expressive_markings/vibrato.ly %% Original author: Mark Witmer %% Rewritten version by Harm #(define (line-part-min-max x1 x2) (list (min x1 x2) (max x1 x2))) #(define (bezier-part-min-max x1 x2 x3 x4) ((lambda (x) (list (reduce min 1 x) (reduce max -1 x))) (map (lambda (x) (+ (* x1 (expt (- 1 x) 3)) (+ (* 3 (* x2 (* (expt (- 1 x) 2) x))) (+ (* 3 (* x3 (* (- 1 x) (expt x 2 (* x4 (expt x 3)) (if (< (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3 (list 0.0 1.0) (filter (lambda (x) (and (>= x 0) (<= x 1))) (append (list 0.0 1.0) (map (lambda (op) (if (not (eqv? 0.0 (exact->inexact (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2)) ;; Zeros of the bezier curve (/ (+ (- x1 (* 2 x2)) (op x3 (sqrt (- (+ (expt x2 2) (+ (expt x3 2) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3))) (- (+ x1 (* 3 x3)) (+ x4 (* 3 x2 ;; Apply L'hopital's rule to get the zeros if 0/0 (* (op 0 1) (/ (/ (- x4 x3) 2) (sqrt (- (+ (* x2 x2) (+ (* x3 x3) (* x1 x4))) (+ (* x1 x3) (+ (* x2 x4) (* x2 x3) (list + - #(define (bezier-min-max x1 y1 x2 y2 x3 y3 x4 y4) (map (lambda (x) (apply bezier-part-min-max x)) `((,x1 ,x2 ,x3 ,x4) (,y1 ,y2 ,y3 ,y4 #(define (line-min-max x1 y1 x2 y2) (map (lambda (x) (apply line-part-min-max x)) `((,x1 ,x2) (,y1 ,y2 #(define (path-min-max origin pointlist) ((lambda (x) (list (reduce min +inf.0 (map caar x)) (reduce max -inf.0 (map cadar x)) (reduce min +inf.0 (map caadr x)) (reduce max -inf.0 (map cadadr x (map (lambda (x) (if (= (length x) 8) (apply bezier-min-max x) (apply line-min-max x))) (map (lambda (x y) (append (list (cadr (reverse x)) (car (reverse x))) y)) (append (list origin) (reverse (cdr (reverse pointlist pointlist #(define (make-path-stencil path thickness x-scale y-scale fill) "Make a stencil based on the path described by the list @var{path}, with thickness @var{thickness}, and scaled by @var{x-scale} in the X direction and @var{y-scale} in the Y direction. @var{fill} is a boolean argument that specifies if the path should be filled. Valid path commands are: moveto rmoveto lineto rlineto curveto rcurveto closepath, and their standard SVG single letter equivalents: M m L l C c Z z." (define (convert-path path origin previous-point) "Recursive function to standardize command names and convert any relative path expressions (in @var{path}) to absolute values. Returns a list of lists. @var{origin} is a pair of x and y coordinates for the origin point of the path (used for closepath and reset by moveto commands). @var{previous-point} is a pair of x and y coordinates for the previous point in the path." (if (pair? path) (let* ((head-raw (car path)) (rest (cdr path)) (head (cond ((memq head-raw '(rmoveto M m)) 'moveto) ((memq head-raw '(rlineto L l)) 'lineto) ((memq head-raw '(rcurveto C c)) 'curveto) ((memq head-raw '(Z z)) 'closepath) (else head-raw))) (arity (cond ((memq head '(lineto moveto)) 2) ((eq? head 'curveto) 6) (else 0))) (coordinates-raw (take rest arity)) (is-absolute (if
Re: Vibrato (wavy lines) notation
2018-03-25 21:13 GMT+02:00 Richard Shann : > I have been using a bit of code written by Mark Witmer to achieve wavy > lines above a series of notes. It co-opts the trill spanner mechanism > for this. > I just found a bug in that code. When there is a line break the > calculation of > (ly:grob-property grob 'X-extent) > - with the grob being a # - > then the value (+inf.0 -inf.0) is returned and in consequence an error > is thrown later when the value is used. > Unfortunately, I don't know what the status of the original file is or > where it came from, but attached is a version which prevents the error > being thrown by returning 0 instead. This results in the wavy line > running off the right margin but the typesetting at least succeeds. > I'm sending this in case anyone else has this problem or needs to > typeset vibrato marks, and - just in case - someone can suggest a > correct way to handle line breaks with these vibrato markings. > > Richard Shann Hi, you may be interested in http://lilypond.1069038.n5.nabble.com/How-to-make-this-postscript-spanner-to-work-with-L-amp-R-bound-details-td204375.html#a204622 Attached you'll find a complete rewrite of Mark's code. Cheers, Harm ___ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user
Vibrato (wavy lines) notation
I have been using a bit of code written by Mark Witmer to achieve wavy lines above a series of notes. It co-opts the trill spanner mechanism for this. I just found a bug in that code. When there is a line break the calculation of (ly:grob-property grob 'X-extent) - with the grob being a # - then the value (+inf.0 -inf.0) is returned and in consequence an error is thrown later when the value is used. Unfortunately, I don't know what the status of the original file is or where it came from, but attached is a version which prevents the error being thrown by returning 0 instead. This results in the wavy line running off the right margin but the typesetting at least succeeds. I'm sending this in case anyone else has this problem or needs to typeset vibrato marks, and - just in case - someone can suggest a correct way to handle line breaks with these vibrato markings. Richard Shann %\version "2.18.2" % vibrato.ly % Author: Mark Witmer % Modified for thickness by Richard Shann % Sets the next trill spanner to draw a waveform with the provided wevelength % and amplitudes. The waveform will go from one amplitude to the next in a % linear fashion. vibrato = #(define-music-function (parser location amplitudes wavelength thickness) (list? number? number?) #{ \once \override TrillSpanner.after-line-breaking = #(lambda (grob) (ly:grob-set-property! grob 'stencil (makevib grob amplitudes wavelength thickness))) #}) % Creates the postscript for one system of the vibrato marking #(define (make_ps lbound xspan span-so-far amplitude-vector wavelength thickness) (letrec ( (frontmatter (string-append "gsave currentpoint translate " (number->string thickness) " setlinewidth newpath\n ")) (backmatter "stroke grestore") (make-curve (lambda (current last) (if (= current (vector-length amplitude-vector)) "" (if (< (vector-ref amplitude-vector current) 0) "" (let ( (current-ps (string-append " x " (number->string (exact->inexact (/ wavelength 3))) " add " (number->string (vector-ref amplitude-vector current)) " x " (number->string (exact->inexact (* 2 (/ wavelength 3 " add " (number->string (- (vector-ref amplitude-vector current))) " x " (number->string wavelength) " add 0.0 curveto /x x " (number->string wavelength) " add def\n"))) (if (= current last) current-ps (string-append current-ps (make-curve (+ 1 current) last) (if (or (= xspan -inf.0) (= xspan +inf.0)) (string-append frontmatter backmatter) (string-append frontmatter " /x " (number->string lbound) " def x 0.0 moveto\n" (make-curve (inexact->exact (ceiling span-so-far)) (+ (inexact->exact (ceiling span-so-far)) (inexact->exact (floor xspan backmatter % Returns the width of a grob #(define (grob-width grob) (if (inf? (cdr (ly:grob-property grob 'X-extent))) 0 (- (cdr (ly:grob-property grob 'X-extent)) (car (ly:grob-property grob 'X-extent) % Returns the number of ems already traversed by the grob's siblings in previous systems #(define (width-up-to grob siblings count) (if (eq? (car siblings) grob) count (+ (+ count (width-up-to grob (cdr siblings) count)) (grob-width (car siblings) % Returns the total width of the individual grobs for each system that make up the original grob #(define (calcfull siblings count) (if (eqv? (length siblings) 0) count (calcfull (cdr siblings) (+ count (grob-width (car siblings)) % Fills a vector of length len with linear interpolations between the values found in amplitudes #(define (fill-amplitude-vector! amplitude-vector len current-index amplitudes) (if (> (length amplitudes) 1) (let ((start-amplitude (car amplitudes)) (end-amplitude (cadr amplitudes)) (start-index current-index) (end-index (+ current-index (inexact->exact (floor (/ (vector-length amplitude-vector) (- len 1))) (do ((n current-index (+ 1 n))) ((or (> n (+ start-index end-index)) (>= n (vector-length amplitude-vector (vector-set! amplitude-vector n (exact->inexact (+ start-amplitude (* (/ (- n start-index) (- end-index start-index)) (- end-amplitude start-amplitude)) (fill-amplitude-vector! amplitude-vector len end-index (cdr amplitudes) % Makes the vector of amplitudes for the vibrato marking #(define (make-amplitude-vector amplitudes total-span wavelength) (let* ( (current-start 0) (len (inexact->exact (ceiling (/ total-span wavelength (amplitude-vector (make-vector len))) (if (> (length amplitudes) 1) (fill-amplitude-vector! amplitude-vector (length amplitudes) 0 amplitudes) (vector-fill! amplitude-vector (car amplitudes))) amplitude-vector)) % Creates a stencil that draws a sine wave for vibrato based on the provided amplitudes and wavelength #