Discussion:
Getting context-definiton, while being in applyContext
Thomas Morley
2018-11-18 17:23:14 UTC
Permalink
Hi,

consider the code below. I'd like to restrict usage to Staff-like
contexts, i.e. Staff, Tab- and DrumStaff, etc would be ok, but
container-contexts like StaffGroup, etc should lead to return '().

Pseudo-code:

\new Staff(Group)
\with {
\applyContext
#(lambda (context)
(if <condition>
;; Do something, if we are in a Staff-like context
;; Multiple Bottom-contexts may happen
(lambda (x) ...)
;; Do nothing if we are are in container-contexts like ChoirStaff,
;; StaffGroup, etc
'()
)
}
{ c''1 }

I thought the <condition> could be "Do I have the Staff_symbol_engraver?"
Though, how to code?
\applyContext
#(lambda (context)
(ly:context-def-lookup context 'consists))
does not work, because 'context' is not a context-definition.

Any hint how to proceed would be great.


Thanks,
Harm
Thomas Morley
2018-11-18 18:05:21 UTC
Permalink
Am So., 18. Nov. 2018 um 18:23 Uhr schrieb Thomas Morley
Post by Thomas Morley
Hi,
consider the code below. I'd like to restrict usage to Staff-like
contexts, i.e. Staff, Tab- and DrumStaff, etc would be ok, but
container-contexts like StaffGroup, etc should lead to return '().
\new Staff(Group)
\with {
\applyContext
#(lambda (context)
(if <condition>
;; Do something, if we are in a Staff-like context
;; Multiple Bottom-contexts may happen
(lambda (x) ...)
;; Do nothing if we are are in container-contexts like ChoirStaff,
;; StaffGroup, etc
'()
)
}
{ c''1 }
I thought the <condition> could be "Do I have the Staff_symbol_engraver?"
Though, how to code?
\applyContext
#(lambda (context)
(ly:context-def-lookup context 'consists))
does not work, because 'context' is not a context-definition.
Any hint how to proceed would be great.
Thanks,
Harm
To answer my own question
(ly:output-find-context-def $defaultlayout (ly:context-name context))
will return an alist of context-defs for current context and all the aliases.

To checking for the engraver in the relevant context-def is trivial now.

Cheers,
Harm
David Kastrup
2018-11-18 18:18:51 UTC
Permalink
Post by Thomas Morley
Hi,
consider the code below. I'd like to restrict usage to Staff-like
contexts, i.e. Staff, Tab- and DrumStaff, etc would be ok, but
container-contexts like StaffGroup, etc should lead to return '().
\new Staff(Group)
\with {
\applyContext
#(lambda (context)
(if <condition>
;; Do something, if we are in a Staff-like context
;; Multiple Bottom-contexts may happen
(lambda (x) ...)
;; Do nothing if we are are in container-contexts like ChoirStaff,
;; StaffGroup, etc
'()
)
}
{ c''1 }
I thought the <condition> could be "Do I have the Staff_symbol_engraver?"
Though, how to code?
\applyContext
#(lambda (context)
(ly:context-def-lookup context 'consists))
does not work, because 'context' is not a context-definition.
Any hint how to proceed would be great.
Why don't you check whether they have a Staff alias? Basically if
looking up 'Staff returns the context itself.
--
David Kastrup
Thomas Morley
2018-11-18 19:36:33 UTC
Permalink
Post by David Kastrup
Post by Thomas Morley
Hi,
consider the code below. I'd like to restrict usage to Staff-like
contexts, i.e. Staff, Tab- and DrumStaff, etc would be ok, but
container-contexts like StaffGroup, etc should lead to return '().
\new Staff(Group)
\with {
\applyContext
#(lambda (context)
(if <condition>
;; Do something, if we are in a Staff-like context
;; Multiple Bottom-contexts may happen
(lambda (x) ...)
;; Do nothing if we are are in container-contexts like ChoirStaff,
;; StaffGroup, etc
'()
)
}
{ c''1 }
I thought the <condition> could be "Do I have the Staff_symbol_engraver?"
Though, how to code?
\applyContext
#(lambda (context)
(ly:context-def-lookup context 'consists))
does not work, because 'context' is not a context-definition.
Any hint how to proceed would be great.
Why don't you check whether they have a Staff alias? Basically if
looking up 'Staff returns the context itself.
--
David Kastrup
You mean like below?

foo =
\applyContext
#(lambda (ctx)
(let* ((ctx-name (ly:context-name ctx))
(staff-ctx-def (ly:output-find-context-def $defaultlayout 'Staff))
(staff-like? (assoc-get ctx-name staff-ctx-def #f)))

(if staff-like?
(format #t "\n\tI'm in a staff-like context: ~a" ctx-name)
(format #t "\n\tWrong here in: ~a" ctx-name))))

\score {
<<
\new StaffGroup R1
\new Staff R1
\new TabStaff R1
\new DrumStaff R1
\new ChoirStaff R1
\layout {
\context Staff \foo
\context {
\StaffGroup
\foo
}
\context {
\ChoirStaff
\foo
}
}
}

Thanks,
Harm
David Kastrup
2018-11-18 19:40:32 UTC
Permalink
Post by Thomas Morley
Post by David Kastrup
Post by Thomas Morley
Hi,
consider the code below. I'd like to restrict usage to Staff-like
contexts, i.e. Staff, Tab- and DrumStaff, etc would be ok, but
container-contexts like StaffGroup, etc should lead to return '().
\new Staff(Group)
\with {
\applyContext
#(lambda (context)
(if <condition>
;; Do something, if we are in a Staff-like context
;; Multiple Bottom-contexts may happen
(lambda (x) ...)
;; Do nothing if we are are in container-contexts like ChoirStaff,
;; StaffGroup, etc
'()
)
}
{ c''1 }
I thought the <condition> could be "Do I have the Staff_symbol_engraver?"
Though, how to code?
\applyContext
#(lambda (context)
(ly:context-def-lookup context 'consists))
does not work, because 'context' is not a context-definition.
Any hint how to proceed would be great.
Why don't you check whether they have a Staff alias? Basically if
looking up 'Staff returns the context itself.
You mean like below?
foo =
\applyContext
#(lambda (ctx)
(let* ((ctx-name (ly:context-name ctx))
(staff-ctx-def (ly:output-find-context-def $defaultlayout 'Staff))
(staff-like? (assoc-get ctx-name staff-ctx-def #f)))
(if staff-like?
(format #t "\n\tI'm in a staff-like context: ~a" ctx-name)
(format #t "\n\tWrong here in: ~a" ctx-name))))
\score {
<<
\new StaffGroup R1
\new Staff R1
\new TabStaff R1
\new DrumStaff R1
\new ChoirStaff R1
\layout {
\context Staff \foo
\context {
\StaffGroup
\foo
}
\context {
\ChoirStaff
\foo
}
}
}
No. Don't refer to the definition at all. Just do

(eq? ctx (ly:context-find ctx 'Staff))
--
David Kastrup
David Kastrup
2018-11-18 20:15:04 UTC
Permalink
Post by David Kastrup
Just do
(eq? ctx (ly:context-find ctx 'Staff))
--
David Kastrup
Find a _parent_ of context that has name or alias name. Return #f if not found.
So I expected it could return
Staff as parent of Voice
StaffGroup as parent of Staff
Score as parent of StaffGroup
Similar to
Function: ly:context-parent context
Return the parent of context, #f if none.
Although this one returns a tree of contexts not even a single parent.
At least for me this was a surprise.
Is my understanding of parents with contexts entirely wrong ...?
Probably not. I remembered that the function was there. I read the doc
string and said "huh?". I read the C++ code and said "WTF?". And then
I pretended that this was totally obvious to make me look smart. In my
defense, I did not write that doc string (at least I hope so).

"Find a parent" does not make a lot of sense considering that each
context has at most one parent.

It's more like "Find among the chain of successive direct parents
starting with the context itself".

Some of our doc strings are not particularly helpful. At least the
function itself is.
--
David Kastrup
Thomas Morley
2018-11-18 20:57:45 UTC
Permalink
Post by David Kastrup
Post by David Kastrup
Just do
(eq? ctx (ly:context-find ctx 'Staff))
--
David Kastrup
Find a _parent_ of context that has name or alias name. Return #f if not found.
So I expected it could return
Staff as parent of Voice
StaffGroup as parent of Staff
Score as parent of StaffGroup
Similar to
Function: ly:context-parent context
Return the parent of context, #f if none.
Although this one returns a tree of contexts not even a single parent.
At least for me this was a surprise.
Is my understanding of parents with contexts entirely wrong ...?
Probably not. I remembered that the function was there. I read the doc
string and said "huh?". I read the C++ code and said "WTF?". And then
I pretended that this was totally obvious to make me look smart.
Rofl
Post by David Kastrup
In my
defense, I did not write that doc string (at least I hope so).
"Find a parent" does not make a lot of sense considering that each
context has at most one parent.
It's more like "Find among the chain of successive direct parents
starting with the context itself".
Indeed.
Post by David Kastrup
Some of our doc strings are not particularly helpful.
Very true.
Post by David Kastrup
At least the
function itself is.
Indeed.

Some background:
Today I was beaten by
https://sourceforge.net/p/testlilyissues/issues/556/
"fingeringOrientations affects cross-voices arpeggio"
which is still present with 2.21.0
and tried to find a workaround.

As a side-effect of this thread I learned that doing
whatever = \context Staff \applyContext #(lambda (ctx) ...)
will affect Staff _and_ all it's alias. Furthermore it can be put as
is into \with or \layout or directly into music.
So I don't need to restrict it to Staff-like contexts anymore, this is
now built-in. :)

But here the code:

correctConnectedArpeggio =
\context Staff
\applyContext
#(lambda (ctx)
(let* ((x-offs '())
(mom '()))
(ly:context-pushpop-property ctx 'Arpeggio 'before-line-breaking
(lambda (grob)
(if (negative? (ly:grob-property grob 'direction))
(let ((grob-mom (grob::when grob))
(x-off-proc (ly:grob-property-data grob 'X-offset)))
(set! x-offs
(if (equal? grob-mom mom)
(cons (x-off-proc grob) x-offs)
'()))
(set! mom (grob::when grob))
(if (pair? x-offs)
(ly:grob-set-property!
grob
'X-offset
;; Mmmh, is using the arbitrary 10 sufficient?
(apply min 10 (drop x-offs 1))))))))))

melody = \relative c'' {
\voiceOne
\set fingeringOrientations = #'(left)
<g-0 c-1>2\arpeggio
\set fingeringOrientations = #'(right)
<g-0 c-1>\arpeggio
\set fingeringOrientations = #'(up)
<g-0 c-1>1\arpeggio
}

bass = \relative c' {
\voiceTwo
\set fingeringOrientations = #'(left)
<c-3>2\arpeggio
\set fingeringOrientations = #'(right)
<c-3>\arpeggio
\set fingeringOrientations = #'(down)
<c-3>1\arpeggio
}

\score {
\context Staff \with {
\consists "Span_arpeggio_engraver"
\correctConnectedArpeggio
}
<<
\set Staff.connectArpeggios = ##t
\context Voice = "melody" { \melody }
\context Voice = "bass" { \bass }
}


Thanks,
Harm

P.S.
You _are_ smart :))
David Kastrup
2018-11-18 21:16:41 UTC
Permalink
Post by Thomas Morley
As a side-effect of this thread I learned that doing
whatever = \context Staff \applyContext #(lambda (ctx) ...)
will affect Staff _and_ all it's alias. Furthermore it can be put as
is into \with or \layout or directly into music.
All with different effect. In \with, it will affect the current
context, no questions asked. In \layout (or \midi), it will affect
_all_ context definitions of the respective output definition having an
alias to Staff . Directly in music, it will walk the hierarchy upwards
until finding a context aliased to Staff and will affect only that.
--
David Kastrup
Thomas Morley
2018-11-18 21:29:06 UTC
Permalink
Post by David Kastrup
Post by Thomas Morley
As a side-effect of this thread I learned that doing
whatever = \context Staff \applyContext #(lambda (ctx) ...)
will affect Staff _and_ all it's alias. Furthermore it can be put as
is into \with or \layout or directly into music.
All with different effect. In \with, it will affect the current
context, no questions asked. In \layout (or \midi), it will affect
_all_ context definitions of the respective output definition having an
alias to Staff .
Which is intended, at least it's what I'd want.
Post by David Kastrup
Directly in music, it will walk the hierarchy upwards
until finding a context aliased to Staff and will affect only that.
Not sure whether this may cause problems in some situations, although
I expect only rare cases.

I think I'll add the workaround to the issue, there is none atm.
For guitarists it's a common problem, I wonder why not more people
complained about it over the years. This issue is 10 years old!

Cheers,
Harm

David Kastrup
2018-11-18 21:12:11 UTC
Permalink
Post by Thomas Morley
Post by David Kastrup
Probably not. I remembered that the function was there. I read the
doc string and said "huh?". I read the C++ code and said "WTF?".
And then I pretended that this was totally obvious to make me look
smart.
Rofl
[...]
Post by Thomas Morley
Thanks,
Harm
P.S.
You _are_ smart :))
I like my bluffs to survive calling them. Turns out I am not a
particularly great poker player.
--
David Kastrup
Loading...