lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

An alternative outside-staff spacing method (new version)


From: Paolo Prete
Subject: An alternative outside-staff spacing method (new version)
Date: Tue, 11 Feb 2020 17:05:58 +0100

Hello all,

thanks to the _great_ support of Aaron and Harm, I implemented this new version of the outside-staff spacing method I proposed some days ago.
Please note that in this way you can order and pad outside staff objects in *any* combination you want, in a very easy way. And you can obtain complex layouts of objects.
You can easily switch the positions, you can add padding empty boxes and you can pad boxes around grobs in any direction (so to bypass the limitation of the outside-staff-padding property that bottom and top padding must be the same) 

TODO:

1) I could not find a way to add a box around piano pedals (and ask to the gurus which  ly:xxx::print interface should I use). Obviously, you can easily compensate this by adding two padding boxes above and below pedals, as the following snippet shows. 

2) Note too that you don't have to specify any position for the "inline" grobs (-\tweak method). But I had to specify this position for TupletBracket as well as for Staff.OttavaBracket. I ask the Scheme gurus if is there a way to put them inline as well.

3) Note too that the Scheme code is somewhat redundant. Any suggestion from the Scheme gurus, for cleaning it, will be obviously greatly accepted.

HTH!
P

%%%%%%%%%% SCHEME CODE %%%%%%%%%%

\version "2.19.83"
#(define PADDER_RECT_DEF_W (cons -3 3))
#(define OSPadderColor grey)
#(define OSPadderThickness 0.1)
#(define posIdxUp 0)
#(define posListUp '())
#(define posIdxDown 0)
#(define posListDown '())
#(define OSBox #{ \markup " " #})

#(define (box-stencil stencil thickness padding color expand?)
   "Add a box around @var{stencil}, producing a new stencil."
   (define (css-style-padding padding)
     ;; padding => (top right bottom left)
     (cond
       ((or (null? padding) (eqv? #f padding)) '(0 0 0 0))
       ((number? padding) (make-list 4 padding))
       ((number-pair? padding)
         (list (car padding) (cdr padding)
               (car padding) (cdr padding)))
       ((and (number-list? padding) (<= (length padding) 4))
         (case (length padding)
           ((1) (make-list 4 (first padding)))
           ((2) (list (first padding) (second padding)
                      (first padding) (second padding)))
           ((3) (list (first padding) (second padding)
                      (third padding) (second padding)))
           (else padding)))
       (else
         (begin (ly:warning "Ignoring invalid padding: ~a" padding)
                '(0 0 0 0)))))
          (let* ((padding (css-style-padding padding))
                 (padding-top (first padding))
                 (padding-right (second padding))
                 (padding-bottom (third padding))
                 (padding-left (fourth padding))

          (x-ext-orig (ly:stencil-extent stencil X))
          (y-ext-orig (ly:stencil-extent stencil Y))
          (x-ext-inner
            (cons (- (interval-start x-ext-orig) padding-left)
                  (+ (interval-end x-ext-orig) padding-right)))
          (y-ext-inner
            (cons (- (interval-start y-ext-orig) padding-bottom)
                  (+ (interval-end y-ext-orig) padding-top)))
          (x-ext-outer (interval-widen x-ext-inner thickness))
          (y-ext-outer (interval-widen y-ext-inner thickness))
          (x-ext-new (if expand? x-ext-outer x-ext-orig))
          (y-ext-new (if expand? y-ext-outer y-ext-orig))

          (x-rule (make-filled-box-stencil (cons 0 thickness) y-ext-inner))
          (y-rule (make-filled-box-stencil x-ext-outer (cons 0 thickness)))
          (box (stencil-with-color
            (ly:stencil-add
              (ly:stencil-translate-axis y-rule (interval-end y-ext-inner) Y)
              (ly:stencil-translate-axis x-rule (interval-end x-ext-inner) X)
              (ly:stencil-translate-axis y-rule (interval-start y-ext-outer) Y)
              (ly:stencil-translate-axis x-rule (interval-start x-ext-outer) X))
            color)))
     (ly:make-stencil
       (ly:stencil-expr (ly:stencil-add stencil box))
       x-ext-new y-ext-new)))

#(define* (make-stencil-boxer thickness padding callback
            #:optional (color OSPadderColor) (expand? #t))
   "Return function that adds a box around the grob passed as argument."
   (lambda (grob)
     (box-stencil (callback grob) thickness padding color expand?)))

#(define (member? x list)
  (cond
    ((null? list) #f)
      ((eqv? x (car list)))
    (else (member? x (cdr list)))))

#(define (next-not-in-list n list)
  (let ((s (+ 1 n)))
    (if (member? s list)
      (next-not-in-list s list) s)))

resetOSPositions  =  #(define-scheme-function () ()
  (set! posIdxUp 0)
  (set! posListUp '())
  (set! posIdxDown 0)
  (set! posListDown '()))

#(define (symbol-list-or-music? x) (or (symbol-list? x) (ly:music? x)))

OSOObj = #(define-music-function (arg) (ly:music?)
  (let ((posIdx 0)
        (name (ly:music-property arg 'name)))
  (if (eq? (ly:music-property arg 'direction) UP)
    (begin
      (set! posIdxUp (next-not-in-list posIdxUp posListUp))
      (set! posListUp (cons posIdxUp posListUp))
      (set! posListUp (sort! posListUp <))
      (set! posIdx posIdxUp))
    (begin
      (set! posIdxDown (next-not-in-list posIdxDown posListDown))
      (set! posListDown (cons posIdxDown posListDown))
      (set! posListDown (sort! posListUp <))
      (set! posIdx posIdxDown)))
    (cond
      ((eq? name 'AbsoluteDynamicEvent)
        #{ -\tweak DynamicLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})    
      ((eq? name 'SustainEvent)
        #{ -\tweak SustainPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})
      ((eq? name 'SostenutoEvent)
        #{ -\tweak SostenutoPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})
      ((eq? name 'UnaCordaEvent)
        #{ -\tweak UnaCordaPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})      
      (else
        #{ -\tweak outside-staff-priority #(* 100 posIdx) #arg #}))))

OSOPadder = #(define-music-function (color thickness padding arg) ((color? white) (number? OSPadderThickness) scheme? symbol-list-or-music?)
  (let ((posIdx 0)
        (name (if (ly:music? arg) (ly:music-property arg 'name) "")))
    (if (ly:music? arg)
      (if (eq? (ly:music-property arg 'direction) UP)
        (begin
          (set! posIdxUp (next-not-in-list posIdxUp posListUp))
          (set! posListUp (cons posIdxUp posListUp))
          (set! posListUp (sort! posListUp <))
          (set! posIdx posIdxUp))
        (begin
          (set! posIdxDown (next-not-in-list posIdxDown posListDown))
          (set! posListDown (cons posIdxDown posListDown))
          (set! posListDown (sort! posListUp <))
          (set! posIdx posIdxDown))))
    (if (ly:music? arg)
      (cond
        ((eq? name 'AbsoluteDynamicEvent) #{
          -\tweak DynamicText.stencil #(make-stencil-boxer thickness padding ly:text-interface::print color)
          -\tweak DynamicLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})    
        ((eq? name 'SustainEvent) #{
          -\tweak SustainPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})
        ((eq? name 'SostenutoEvent) #{
          -\tweak SostenutoPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})
        ((eq? name 'TextScriptEvent) #{
          -\tweak TextScript.stencil #(make-stencil-boxer thickness padding ly:text-interface::print color)
          -\tweak TextScript.outside-staff-priority #(* 100 posIdx) #arg #})      
        ((eq? name 'ArticulationEvent) #{
          -\tweak Script.stencil #(make-stencil-boxer thickness padding ly:script-interface::print color)
          -\tweak outside-staff-priority #(* 100 posIdx) #arg #})
        ((eq? name 'UnaCordaEvent) #{
          -\tweak UnaCordaPedalLineSpanner.outside-staff-priority #(* 100 posIdx) #arg #})      
        (else #{
          -\tweak outside-staff-priority #(* 100 posIdx) #arg #}))
      ;else (symbols)
      (cond
        ((memv 'OttavaBracket arg) #{
           \once \override Staff.OttavaBracket.stencil =
           #(make-stencil-boxer OSPadderThickness padding ly:ottava-bracket::print color)  #})
        ((memv 'TupletBracket arg) #{
           \once \override TupletBracket.stencil =
           #(make-stencil-boxer OSPadderThickness padding ly:tuplet-bracket::print color)  #})))))  

setOSPosition = #(define-music-function (direction pos arg) (number? number? symbol-list?)                                      
  (if (eq? direction UP)
    (begin
      (set! posListUp (cons pos posListUp))
      (set! posListUp (sort! posListUp <)))
    (begin
      (set! posListDown (cons pos posListDown))
      (set! posListDown (sort! posListDown <))))
    #{ \once \override #arg .outside-staff-priority = #(* 100 pos) #})

%%%%%%%%%% USER CODE %%%%%%%%%%

#(define OSOPCOL grey)

{

\time 2/4

\set Staff.pedalSustainStyle = #'mixed
\once \override TupletBracket.direction = #UP
\override Staff.OttavaBracket.outside-staff-padding = 0
\override Staff.TextScript.outside-staff-padding = 0
\override Staff.Script.outside-staff-padding = 0
\override TupletBracket.outside-staff-padding = 0
\override DynamicLineSpanner.outside-staff-padding = 0

#(define OSSLayoutA  #{

\resetOSPositions
\setOSPosition #UP 2 TupletBracket
\setOSPosition #UP 6 Staff.OttavaBracket
\OSOPadder #OSOPCOL #'(0 1 0 1) Staff.OttavaBracket
\OSOPadder #OSOPCOL #'(0 1 0 1) TupletBracket

#})

#(define OSSLayoutB  #{

%-----------ABOVE STAFF------------ (bottom -> top order)
\OSOPadder #OSOPCOL #'(3 1 1 1) ^\OSBox
\OSOPadder #OSOPCOL #'(1 1 1 1) ^\OSBox
\OSOObj                         ^(
\OSOPadder #OSOPCOL #'(1 1 1 1) ^\OSBox
\OSOPadder #OSOPCOL #'(1 1 1 1) ^\OSBox
\OSOPadder #OSOPCOL #'(0 1 0 1) ^>
\OSOPadder #OSOPCOL #'(1 1 1 1) ^\OSBox

%-----------BELOW STAFF------------ (top -> bottom order)
\OSOPadder #OSOPCOL #'(0 1 3 1) _\mf
\OSOPadder #OSOPCOL #'(1 1 1 1) _\OSBox
\OSOObj                         _\sostenutoOn
\OSOPadder #OSOPCOL #'(1 1 1 1) _\OSBox
\OSOObj                         _\sustainOn
\OSOPadder #OSOPCOL #'(1 1 1 1) _\OSBox
\OSOPadder #OSOPCOL #'(0 1 0 1) _\markup {"Use ped. with care!"}
\OSOPadder #OSOPCOL #'(1 1 1 1) _\OSBox

#})

\tuplet 3/2 { $OSSLayoutA \ottava #1 c'''' $OSSLayoutB a'''' c'''')\sustainOff\sostenutoOff \ottava #0 }

}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

reply via email to

[Prev in Thread] Current Thread [Next in Thread]