[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: engraver to change staff name based on visibility of related staff?
From: |
Thomas Morley |
Subject: |
Re: engraver to change staff name based on visibility of related staff? |
Date: |
Sat, 17 Jun 2017 12:42:29 +0200 |
2017-06-16 23:47 GMT+02:00 Shevek <address@hidden>:
> Following up on an aspect of the discussion on parts sharing a staff
> (http://lilypond.1069038.n5.nabble.com/parts-sharing-a-staff-tt203873.html).
>
> I've spent quite a few hours over the last day trying to figure out how
> engravers work and how I might take a crack at writing something to
> automatically handle changing Staff names for divisi staves. I feel like
> I've understood most of what I've read, but I'm still totally befuddled.
> This seems like a difficult problem because:
>
> 1) It's completely opaque to me how one would check if a Staff is visible or
> not on a given system. The hara-kiri-group-spanner, as far as I can tell,
> does its work without telling anybody about it. There's not like a boolean
> function you can call to find out if a context will be visible.
>
> 2) One needs to do something in one context depending on what happens in a
> different context. Most of the example engravers just do something in one
> context. Keep_alive_together_engraver collects grobs from different contexts
> and tells them about each other, but then relies on on them to figure out
> what to do with that information. That doesn't seem adequate here.
>
> 3) Such an engraver would need to step through the score by system, after
> breaking, rather than event by event, and it might need to be able to
> backtrack to insert an event to change the instrument name prior to the most
> recent system break. The code and documentation I've read has not given me
> any insight into how one might do such a thing.
>
> I'd love some feedback and guidance.
Hi,
I doubt an engraver will ever work for this purpose. As far as I
understand an engraver usually puts in stuff far too early. You can
assign a procedure to a grob via 'after-line-breaking, but you will
not be able to access whatever the procedure returns _in_ the
engraver.
I may be proven wrong, though.
Nevertheless, I tried a different approach:
\version "2.19.62"
%% NB
%% It's a proof of concept, nothing more!!
%% Currently it will fail for various reasons with extended examples
#(define change-instr-names
(lambda (grob)
(let* ((sys (ly:grob-system grob))
(sys-all-elts (ly:grob-object sys 'all-elements))
(sys-all-elts-list
(if (ly:grob-array? sys-all-elts)
(ly:grob-array->list sys-all-elts)
'()))
;; get all VerticalAxisGroup-grobs per System
(vertical-axis-group-list
(filter
(lambda (g)
(grob::has-interface g 'hara-kiri-group-spanner-interface))
sys-all-elts-list))
;; get all InstrumentName-grobs per System
(instrument-names-list
(filter
(lambda (g)
(grob::has-interface g 'system-start-text-interface))
sys-all-elts-list))
;; construct a nested list like
;; ((#t #<Grob InstrumentName >)
;; (#f #<Grob InstrumentName >))
;; the boolean indicates whether the Staff is alive, derived from
;; VerticalAxisGroup.Y-extent
(alive?-instr-list
(map
(lambda (v i)
(list (interval-sane? (ly:grob-property v 'Y-extent)) i))
vertical-axis-group-list
instrument-names-list)))
;(pretty-print alive?-instr-list)
;; First constructing a list and then fragmenting it in various ways is
;; not elegant, to say the least.
;; Just a proof of concept...
(if (any not (map car alive?-instr-list))
(let* ((instr-to-set
(remove
(lambda (e)
(not (car e)))
alive?-instr-list)))
(ly:grob-set-property! (cadar instr-to-set) 'text
(make-column-markup
(map
(lambda (arg)
(ly:grob-property arg 'text))
(map cadr alive?-instr-list)))))))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Example
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\layout {
\context {
\Staff
\override VerticalAxisGroup.after-line-breaking = #change-instr-names
\RemoveEmptyStaves
}
}
<<
\new Staff \with { instrumentName = "One" shortInstrumentName = "one" }
{ R1 \break c \break c }
\new Staff \with { instrumentName = "Two" shortInstrumentName = "two" }
{ c1 R c }
>>
Cheers,
Harm