Jump to content

Using path expressions to override stencils

From LilyPond wiki

The stencil expression path can be used to override stencils for any printed object. The advantage of using path instead of embedded-ps is that path is supported by both the PostScript and SVG backends, and uses the same syntax.

There are six commands available to use in a path expression, and all commands use prefix notation. The six commands are moveto, rmoveto, lineto, rlineto, curveto, and rcurveto. Note that the commands that begin with r are the relative variants of the other three commands.

The commands moveto, rmoveto, lineto, and rlineto take 2 arguments; they are the X and Y coordinates for the destination point.

The commands curveto and rcurveto create cubic Bézier curves, and take 6 arguments; the first two are the X and Y coordinates for the first control point, the second two are the X and Y coordinates for the second control point, and the last two are the X and Y coordinates for the destination point.

In addition this snippet shows how to create a filled stencil using path, and adds a scheme function to automatically resize custom stencils when individual staves are resized.

\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=623

%{
  Note: since SVG path data needs an "M" or "m" at the
  beginning to start a new subpath, every path expression
  must begin with "rmoveto" (or "moveto") to work with the
  SVG backend.
%}

customClefStencilOne =
  #(ly:make-stencil
    `(path 0.2
	  (rmoveto 0 0
	    rcurveto 0 0.75 1 0.75 1 0
	    rcurveto 0 -0.75 -1 -0.75 -1 0
	    rcurveto -1 0 -1 1.5 -0.5 1.5
	    rmoveto 0.5 -1.5
	    rcurveto -1 0 -1 -1.5 -0.5 -1.5
	    rmoveto 0.5 1.5
	    rmoveto 1 0
	    rcurveto 2.5 0 2.5 4 4 4
	    rmoveto -4 -4
	    rcurveto 2.5 0 2.5 -4 4 -4))
     (cons -0.5 1)
     (cons -3 5))
  
% a filled custom stencil
customClefStencilTwo = 
  #(ly:make-stencil
    ;; path line thickness is set to 0.1 
    `(path 0.1
      ;; path coordinates
	  (moveto 0 0
	    curveto 0 1 0.7 2.5 1.5 1.5
            lineto 1.5 -3
            closepath)
          ;; path cap style
          round
          ;; path join style
          round
          ;; path filled?  #t or #f
          #t)
     ;; horizontal extent
     (cons 0 1.5)
     ;; vertical extent
     (cons -3 2))

% scheme function to automatically resize a custom stencil 
% when an individual staff is resized (uses font-size)
scaleCustomClefStencilTwo =
#(lambda (grob)
  (let* ((sz (ly:grob-property grob 'font-size 0.0))
           (mult (magstep sz)))
    (ly:stencil-scale
      customClefStencilTwo
      mult mult)))
  
customClefOne = \override Staff.Clef.stencil = \customClefStencilOne
customClefTwo = \override Staff.Clef.stencil = \scaleCustomClefStencilTwo
normalClefs = \revert Staff.Clef.stencil

music =
\relative c' {
  \customClefOne
  \clef "alto"
  c1 g1
  \customClefTwo
  \clef "bass"
  c1 g1
  \normalClefs
  \clef "treble"
  c1 g1
  \clef "alto"
  c1 g1
}
<<
\new Staff \with {
    fontSize = #-3
    \override StaffSymbol.staff-space = #(magstep -3)
    \override StaffSymbol.thickness = #(magstep -3)
}
\music

\new Staff 
\music

\new Staff \with {
    fontSize = #2
    \override StaffSymbol.staff-space = #(magstep 2)
    \override StaffSymbol.thickness = #(magstep 2)
}
\music
>>