\version "2.19.15" \header { tagline = ##f } #(define-event-class 'music-boxer-event 'span-event) #(define-event-class 'box-event 'music-event) #(define (add-grob-definition grob-name grob-entry) (let* ((meta-entry (assoc-get 'meta grob-entry)) (class (assoc-get 'class meta-entry)) (ifaces-entry (assoc-get 'interfaces meta-entry))) ;; change ly:grob-properties? to list? to work from 2.19.12 back to at least 2.18.2 (set-object-property! grob-name 'translation-type? ly:grob-properties?) (set-object-property! grob-name 'is-grob? #t) (set! ifaces-entry (append (case class ((Item) '(item-interface)) ((Spanner) '(spanner-interface)) ((Paper_column) '((item-interface paper-column-interface))) ((System) '((system-interface spanner-interface))) (else '(unknown-interface))) ifaces-entry)) (set! ifaces-entry (uniq-list (sort ifaces-entry symbol thick 0) (make-filled-box-stencil (cons (- (car xext) thick) (+ (cdr xext) thick)) (cons (- (car yext) thick) (car yext))) empty-stencil) (if (> thick 0) (make-filled-box-stencil (cons (- (car xext) thick) (+ (cdr xext) thick)) (cons (cdr yext) (+ (cdr yext) thick))) empty-stencil) (if (and (not open-on-right) (> thick 0)) (make-filled-box-stencil (cons (cdr xext) (+ (cdr xext) thick)) yext) empty-stencil) (if (and (not open-on-left) (> thick 0)) (make-filled-box-stencil (cons (- (car xext) thick) (car xext)) yext) empty-stencil) ))) #(define (music-boxer-stencil grob) (let* ((elts (ly:grob-object grob 'elements)) (refp-X (ly:grob-common-refpoint-of-array grob elts X)) (X-ext (ly:relative-group-extent elts refp-X X)) (refp-Y (ly:grob-common-refpoint-of-array grob elts Y)) (Y-ext (ly:relative-group-extent elts refp-Y Y)) (padding (ly:grob-property grob 'padding 0.3)) (thick (ly:grob-property grob 'thickness 0.1)) (filled (ly:grob-property grob 'filled #f)) (fill-color (ly:grob-property grob 'fill-color grey)) (offset (ly:grob-relative-coordinate grob refp-X X)) ; (left-bound (ly:spanner-bound grob LEFT)) ; (right-bound (ly:spanner-bound grob RIGHT)) ; (break-dir-L (ly:item-break-dir left-bound)) ; (break-dir-R (ly:item-break-dir right-bound)) ; (open-on-left (if (= 1 break-dir-L) #t #f)) ; (open-on-right (if (= -1 break-dir-R) #t #f)) (open-on-left (if (ly:spanner? grob) (if (= 1 (ly:item-break-dir (ly:spanner-bound grob LEFT ))) #t #f) #f)) (open-on-right (if (ly:spanner? grob) (if (= -1 (ly:item-break-dir (ly:spanner-bound grob RIGHT))) #t #f) #f)) (stil (make-box thick padding filled fill-color open-on-left open-on-right X-ext Y-ext)) ) (ly:stencil-translate-axis stil (- offset) X) ) ) #(define box-stil music-boxer-stencil) #(add-grob-definition 'Box `( (stencil . ,box-stil) (meta . ((class . Item) (interfaces . ()))))) #(add-grob-definition 'MusicBoxer `( (stencil . ,music-boxer-stencil) (meta . ((class . Spanner) (interfaces . ()))))) #(define box-types '( (BoxEvent . ((description . "A box encompassing music at a single timestep.") (types . (general-music box-event music-event event)) )) )) #(define music-boxer-types '( (MusicBoxerEvent . ((description . "Used to signal where boxes encompassing music start and stop.") (types . (general-music music-boxer-event span-event event)) )) )) #(set! music-boxer-types (map (lambda (x) (set-object-property! (car x) 'music-description (cdr (assq 'description (cdr x)))) (let ((lst (cdr x))) (set! lst (assoc-set! lst 'name (car x))) (set! lst (assq-remove! lst 'description)) (hashq-set! music-name-to-property-table (car x) lst) (cons (car x) lst))) music-boxer-types)) #(set! box-types (map (lambda (x) (set-object-property! (car x) 'music-description (cdr (assq 'description (cdr x)))) (let ((lst (cdr x))) (set! lst (assoc-set! lst 'name (car x))) (set! lst (assq-remove! lst 'description)) (hashq-set! music-name-to-property-table (car x) lst) (cons (car x) lst))) box-types)) #(set! music-descriptions (append music-boxer-types music-descriptions)) #(set! music-descriptions (append box-types music-descriptions)) #(set! music-descriptions (sort music-descriptions alist1 \f \fermata \once \override Score.Box.acknowledge-script-interface = ##t \once \override Score.Box.acknowledge-finger-interface = ##t \box 1 \f \fermata } \score { \new Staff { \melody \another } } \layout { \context { \Global \grobdescriptions #all-grob-descriptions } \context { \Score \consists \musicBoxerEngraver % for spans \consists \boxEngraver } }