\version "2.19.17" \paper { indent = 2\in short-indent = 3\in } #(define (center-interval-on-other-interval victim target) (coord-translate victim (- (interval-center target) (interval-center victim)))) #(define (align-interval-on-other victim target dir) (let ((center (center-interval-on-other-interval victim target))) (coord-translate center (* (- (car center) (car target)) dir)))) #(define (custom-align grob) (let* (;; get all InstumentName grobs (system (ly:grob-system grob)) (elements (ly:grob-array->list (ly:grob-object system 'elements))) (text-grobs (filter (lambda (e) (grob::has-interface e 'system-start-text-interface)) elements)) ;(align-x (ly:grob-property grob 'self-alignment-X 0)) (my-extent (ly:grob-extent grob system X)) ;; A delimiter is an initial barline, bracket, brace. (delims (filter (lambda (elt) (grob::has-interface elt 'system-start-delimiter-interface)) elements)) ;; There is no direct way to find out which delimiters affect ;; which InstrumentName grobs. We must compare the StaffSymbol ;; traversed by each delimiter with the StaffSymbol of each ;; InstrumentName. (staff-lists (map (lambda (d) (cons d (list (ly:grob-array->list (ly:grob-object d 'elements))))) delims)) ; for a given text, what delimiters are to the right? (text-grob-delim-to-right (lambda (tg) (let loop ((staff-lists staff-lists) (result '())) (cond ((null? staff-lists) result) ((member (ly:grob-object tg 'staff-symbol) (cadr (car staff-lists))) (loop (cdr staff-lists) (append result (list (caar staff-lists))))) (else (loop (cdr staff-lists) result)))))) ; return a list of text grobs and their delimiters (text-grobs-delims-list (map (lambda (tg) (cons tg (text-grob-delim-to-right tg))) text-grobs)) ; convert a list of delimiters to a list of extents (delim-extent-list (lambda (delim-list) (map (lambda (d) (ly:grob-extent d system X)) delim-list))) ; return a list of text grobs and their associated delimiter extents (text-grobs-delim-extents (map (lambda (tgdl) (cons (car tgdl) (delim-extent-list (cdr tgdl)))) text-grobs-delims-list)) ; combine extebts (text-grobs-total-delim-extents (map (lambda (tgde) (cons (car tgde) (reduce interval-union ; in case there is no delimiter (ly:grob-extent (ly:grob-parent (car tgde) X) system X) (cdr tgde)))) text-grobs-delim-extents)) ; assumption? (representative-delim-extent (cdar text-grobs-total-delim-extents)) ; In order to calculate how much to move our name, we first need ; to construct a list of target positions for all grobs. (bar-line-width 0.1) ; Ugh. Get it from rightmost delimiter. (target (map (lambda (tg) (let ((len (interval-length (ly:grob-extent tg system X)))) (list tg (cons (- (cdr representative-delim-extent) bar-line-width) (+ (- (cdr representative-delim-extent) bar-line-width) len))))) text-grobs)) (target (map (lambda (re) (cons (car re) (coord-translate (cadr re) (ly:side-position-interface::x-aligned-side (car re))))) target)) (longest (car (sort target (lambda (x y) (> (interval-length (cdr x)) (interval-length (cdr y))))))) (target (map (lambda (x) (cons (car x) ;(center-interval-on-other-interval (cdr x) (cdr longest)))) (align-interval-on-other (cdr x) (cdr longest) (ly:grob-property (car x) 'self-alignment-X 0)))) target)) ; determine overlaps of target positioning with delimiters (overlap (map (lambda (x y) (cons (car x) (interval-intersection (cdr x) (cdr y)))) target text-grobs-total-delim-extents)) (overlap (filter (lambda (x) (interval-sane? (cdr x))) overlap)) (largest-overlap (if (null? overlap) 0.0 (apply max (map (lambda (x) (interval-length (cdr x))) overlap)))) (right-padding (ly:grob-property grob 'padding 0.3)) ; X offset returned will displace grob's extent to match ; the target inc. any overlap with delimiters and padding. (X-offset (- (car (assoc-get grob target)) (car my-extent) largest-overlap right-padding))) X-offset)) music = \repeat unfold 20 { c''1 } \score { << \new Staff \with { instrumentName = "Flute" shortInstrumentName = "Abbreviation for Flute" } \music \new Staff \with { instrumentName = "Clarinet" shortInstrumentName = "Cl." } \music \new StaffGroup << \new StaffGroup \with { systemStartDelimiter = #'SystemStartBrace } << \new Staff \with { instrumentName = "Instrumentissimo I" shortInstrumentName = "Inst. I"} \music \new Staff \with { instrumentName = "Instrumentissimo II" } \music >> \new Staff \with { instrumentName = "Cello" } \music >> >> \layout { \context { \Score \override InstrumentName.X-offset = #custom-align \override InstrumentName.padding = 1 } } } \score { << \new Staff \with { instrumentName = \markup \center-column { "Instrumentissimo I" "Grande" } } c''1 \new Staff \with { instrumentName = "Instrumentissimo II" } c''1 \new StaffGroup << \new StaffGroup \with { systemStartDelimiter = #'SystemStartBrace } << \new Staff \with { instrumentName = "Flute" } c''1 \new Staff \with { instrumentName = "Clarinet" } c''1 >> \new Staff \with { instrumentName = "Cello" } c''1 >> >> \layout { \context { \Score \override InstrumentName.self-alignment-X = #LEFT \override InstrumentName.X-offset = #custom-align } } } \score { << \new Staff \with { instrumentName = \markup \center-column { "Instrumentissimo I" "Grande" } } c''1 \new Staff \with { instrumentName = "Instrumentissimo II" } c''1 \new StaffGroup << \new StaffGroup \with { systemStartDelimiter = #'SystemStartBrace } << \new Staff \with { instrumentName = "Flute" \override InstrumentName.self-alignment-X = #LEFT } c''1 \new Staff \with { instrumentName = "Clarinet" } c''1 >> \new Staff \with { instrumentName = "Cello" \override InstrumentName.self-alignment-X = #RIGHT } c''1 >> >> \layout { \context { \Score \override InstrumentName.X-offset = #custom-align \override InstrumentName.padding = 1 } } } \score { << \new Staff \with { instrumentName = "Inst. I" } c''1 >> \layout { \context { \Score \override InstrumentName.X-offset = #custom-align \override InstrumentName.padding = 2 } } }