\version "2.18.0" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% A command to horizontally align a grob to another grob. %% %% Syntax: %% %% [\once] \alignGrob [Context.]Grob-to-align [Context.]Grob-to-align-to %% alignment-direction(s) extra-offset(s) %% %% Usage: %% %% The argument "alignment-direction(s)" specifies the sides of our %% grob and the reference grob to align. If a single number (or LEFT, %% CENTER, RIGHT) is given, this is used for both objects. If a pair is %% given, the first value refers to our grob, and the second to the %% reference grob. Standard values are -1 for LEFT, 0 for CENTER, or 1 for %% RIGHT. Fractional values are allowed, permitting greater refinement %% of positioning. %% %% The argument extra-offset(s) can be a number or a pair of numbers. A %% single number always indicates the vertical displacement of the object %% from its default position: the single number or the second value of a %% number-pair. The first value of a pair (e.g., (dx . dy) ) gives an %% extra amount to add to the horizontal position. This allows you to tweak %% the new alignment. %% %% Important: This command uses 'extra-offset, and thus only moves the object %% in question. Other objects will not be moved out of the way in the case %% of a collision. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% alignGrob = #(define-music-function (parser location grob-to-align reference-grob dir extra-displacement) (symbol-list? symbol-list? number-or-pair? number-or-pair?) #{ \override $grob-to-align . extra-offset = #(lambda (grob) (let* ((refp (ly:grob-system grob)) (default-coord (ly:grob-relative-coordinate grob refp X)) (array (ly:grob-object refp 'all-elements)) ;; We only want the name of the grob we're aligning to. If ;; input is in the form Context.Grob, strip Context silently. (reference-grob (if (pair? reference-grob) (car (reverse reference-grob)) reference-grob)) (grob-name (lambda (x) (assq-ref (ly:grob-property x 'meta) 'name))) ;; all the grobs of the reference type in the current system (lst (filter (lambda (x) (eq? reference-grob (grob-name x))) (ly:grob-array->list array))) ;; Find the grob with the X-coordinate closest to our grob. (ref (reduce (lambda (elem prev) (if (< (abs (- default-coord (ly:grob-relative-coordinate elem refp X))) (abs (- default-coord (ly:grob-relative-coordinate prev refp X)))) elem prev)) '() lst))) (if (ly:grob? ref) (let* ((grob-ext (ly:grob-extent grob refp X)) (grob-dir (if (pair? dir) (car dir) dir)) (grob-ext-idx (interval-index grob-ext grob-dir)) (ref-ext (ly:grob-extent ref refp X)) ;; If user specified single direction, use it for both objects. (ref-dir (if (pair? dir) (cdr dir) dir)) (ref-ext-idx (interval-index ref-ext ref-dir)) (extra-X-offset (if (pair? extra-displacement) (car extra-displacement) 0.0)) (extra-Y-offset (if (pair? extra-displacement) (cdr extra-displacement) extra-displacement))) (cons (+ (- ref-ext-idx grob-ext-idx) extra-X-offset) extra-Y-offset)) (cons 0.0 0.0)))) #} ) ln = \markup \with-color #red \draw-line #'(0 . 6) uparrow = \markup \combine \arrow-head #Y #UP ##f \draw-line #'(0 . -2) downarrow = \markup \combine \arrow-head #Y #DOWN ##f \draw-line #'(0 . 2) \relative c' { %% bar 1 \time 3/4 \key d \major d \alignGrob TextScript KeySignature #CENTER #6 e-\ln \alignGrob TextScript Clef #RIGHT #5.5 fis-\ln %% bar 2 \time 5/4 \alignGrob TextScript BarLine #CENTER #-5.5 e^\ln \alignGrob TextScript Hairpin #RIGHT #1 d(_\ln \alignGrob TextScript Slur #CENTER #0 e_\uparrow \alignGrob TextScript StaffSymbol #CENTER #0 fis^\markup \center-column { "mid-staff" \downarrow } d)\< %% bar 3 \time 3/4 \alignGrob TextScript TimeSignature #LEFT #-5 e^\ln \alignGrob TextScript TimeSignature #RIGHT #-5 fis^\ln d %% bar 5 \alignGrob TextScript Stem #CENTER #-5.5 e\!^\ln fis \alignGrob TextScript Accidental #CENTER #0 d!_\uparrow %% bar 6 \time 2/4 \alignGrob Stem NoteHead #CENTER #0 fis \alignGrob Stem NoteHead #CENTER #0 \alignGrob Script BarLine #CENTER #0.5 \alignGrob TextScript StaffSymbol #RIGHT #0 d\fermata _"end" \bar "||" } thickln = \markup { \override #'(thickness . 5) \with-color #red \draw-line #'(0 . 6) } \new Staff { \relative c' { \override Staff.TimeSignature.layer = #2 \time 3/4 \alignGrob TextScript TimeSignature #'(1 . -1) #5.5 s2.-\thickln \time 3/4 \alignGrob TextScript TimeSignature #'(0 . -1) #5.5 s-\thickln \time 3/4 \alignGrob TextScript TimeSignature #'(-1 . -1) #5.5 s-\thickln \alignGrob TextScript TimeSignature #'(1 . 0) #5.5 \time 3/4 s-\thickln \alignGrob TextScript TimeSignature #'(0 . 0) #5.5 \time 3/4 s-\thickln \alignGrob TextScript TimeSignature #'(-1 . 0) #5.5 \time 3/4 s-\thickln \alignGrob TextScript TimeSignature #'(1 . 1) #5.5 \time 3/4 s-\thickln \alignGrob TextScript TimeSignature #'(0 . 1) #5.5 \time 3/4 s-\thickln \alignGrob TextScript TimeSignature #(cons LEFT RIGHT) #5.5 \time 3/4 s-\thickln } } \new Staff { \override Staff.StaffSymbol.width = 50 \alignGrob Score.BarLine StaffSymbol #RIGHT #'(0.08 . 0) c''4 d e f s2. }