Ripped, torn staff-lines

Here are some macros which can make a single staff appear as though its right side has been torn off. Two styles are available: the first "erases" the ends of individual staff- lines to different lengths; the second draws a zigzag line and erases everything to its right. Furthermore, the first type is capable of producing tear-patterns at random. Both work by temporarily modifying the BarLine stencil.

STYLE 1 PREFERENCES:

edit
  • tearWidth ... default is 1

horizontal distance (measured in staff-spaces) between the end-points of the shortest and longest staff-lines.

  • tearXext ... default is '(0 . 0)

X-extent of the BarLine stencil, NOT including its width. Can be used as "padding" around the stencil, if needed.

STYLE 2 PREFERENCES:

edit
  • zigzagDefaultYext ... default is '(-4 . 4)

Y-extent of the zigzag BarLine stencil (measured in staff-spaces).

  • zigzagDefaultSerrationCount ... default is 5

Number of "teeth" or "notches" on the zigzag line.

  • zigzagTearLineWidth ... default is 0.1

Width of the zigzag line itself.

  • zigzagTearAngle ... default is 90

Angle (measured in degrees) of kinks in the zigzag line.

  • zigzagTearXext ... default is '(0 . 0)

X-extent of the zigzag BarLine stencil, NOT including its width. Can be used as "padding" around the stencil, if needed.

USAGE:

edit

see the \score { } block at the end of the file.

\version "2.24.0"

%% http://lsr.di.unimi.it/LSR/Item?id=668
%% see also http://lilypond.1069038.n5.nabble.com/LSR-v2-18-quot-Ripped-torn-staff-lines-quot-does-not-compile-tc159381.html

%LSR updated by Harm (Feb. 2014)
%LSR This snippet was contributed by Mark Polesky for version 2.12.0

%% preferences %%

tearWidth = #1
tearXext = #'(0 . 0)

zigzagDefaultYext = #'(-4 . 4)
zigzagDefaultSerrationCount = #5
zigzagTearLineWidth = #0.1
zigzagTearAngle = #90
zigzagTearXext = #'(0 . 0)


%% start definitions %%

tearGeneric =
  #(define-music-function (lengths) (list?)
  (let ((x-ext
          (lambda (n)
            (cons (* (list-ref lengths n) (/ tearWidth 4)) tearWidth)))
        (y-ext '(1.5 . 2.5)))

  #{
    \once \override Staff.BarLine.stencil = #ly:text-interface::print
    \once \override Staff.BarLine.text = \markup
      \override #'(baseline-skip . 0) \with-color #white
      \column {
        \filled-box #(x-ext 0) #y-ext #0
        \filled-box #(x-ext 1) #y-ext #0
        \filled-box #(x-ext 2) #y-ext #0
        \filled-box #(x-ext 3) #y-ext #0
        \filled-box #(x-ext 4) #y-ext #0
      }
    \once \override Staff.BarLine.layer = #1
    \once \override Staff.BarLine.X-extent =
      #`(,(car tearXext) . ,(- (+ (cdr tearXext) tearWidth) 0.1))
    \break
  #}))

tear =
  #(define-music-function () ()
  #{
    \tearGeneric
      #(let loop ((unused '(0 1 2 3 4))
                  (lengths '()))
        (if (= (length lengths) 5)
            lengths
            (let* ((x (random (length unused)))
                   (y (- (length unused) x))
                   (z (list-ref unused x)))
             (loop (append (list-tail unused (+ x 1))
                           (list-tail (reverse unused) y))
                   (append lengths `(,z))))))
  #})

tearCustom =
  #(define-music-function (lengths) (list?)
  #{ \tearGeneric #lengths #})

zigzagTearCustom =
  #(define-music-function (y-ext serrations)
    (pair? number?)
    (let* ((zigzagTearHeight (- (cdr y-ext) (car y-ext)))
           (deg2rad (lambda (x) (* x (/ (* (atan 1) 4) 180))))
           (zigzagTearWidth
              (/ zigzagTearHeight
                 serrations
                 (* (tan (/ (deg2rad zigzagTearAngle) 2)) 2))))
  #{
    \once \override Staff.BarLine.stencil = #ly:text-interface::print
    \once \override Staff.BarLine.text =
      \markup \with-dimensions
               #`(0 . ,zigzagTearWidth)
               #`(,(car y-ext) . ,(cdr y-ext))
        \postscript

#(string-append "
/linewidth " (number->string zigzagTearLineWidth) " def
/height " (number->string zigzagTearHeight) " def
/serrations " (number->string serrations) " def
/width " (number->string zigzagTearWidth) " def
/padding " (number->string (cdr zigzagTearXext)) " 2 width mul add def

/serrationHeight height serrations div def
/y0 " (number->string (cdr y-ext)) " def
/xn width def
/yn serrationHeight 2 div neg def

/plotAngle {
  xn yn rlineto
  xn neg yn rlineto
} def

/plotSerrations {
  serrations { plotAngle } repeat
} def

%% whiteout:
1 setgray
linewidth setlinewidth
0 y0 linewidth add moveto %% (whiteout staff-lines when y-exts are integers)
0 y0 lineto
plotSerrations
0 linewidth neg rlineto %% (whiteout staff-lines when y-exts are integers)
padding 0 rlineto
0 height linewidth 2 mul add rlineto %% (account for top and bottom linewidth)
padding neg 0 rlineto
fill stroke

%% draw serrations:
newpath
0 setgray
linewidth setlinewidth
0 y0 moveto
plotSerrations
stroke")

    \once \override Staff.BarLine.layer = #1
    \once \override Staff.BarLine.X-extent =
      #`(,(car zigzagTearXext) .
       ,(- (+ (cdr zigzagTearXext) zigzagTearWidth) 0.1))
    \break
  #}))

zigzagTear = \zigzagTearCustom #zigzagDefaultYext #zigzagDefaultSerrationCount

%% end definitions %%

%% example of a custom tear-pattern:
tearRagged = \tearCustom #'(3 1 3 1 3)

music = { g'4 d'' b' d'' }
\header { tagline=##f }
\score {
  {
    %% random line-lengths:
    \music \tear

    %% set line-lengths on-the-fly:
    \music \tearCustom #'(0 1 2 3 4)

    %% define a custom tear-pattern if you want consistency (see above):
    \music \tearRagged

    %% default zigzag tear:
    \music \zigzagTear

    %% set zigzag Y-extent and serration-count on-the-fly:
    \transpose c c' \music \zigzagTearCustom #'(-4 . 7) #4
  }
  \layout {
    indent = #0
    ragged-right = ##t
  }
}