abjad.bind
|
Annotates |
|
Attaches |
|
Detaches indicators equals to |
- abjad.bind.annotate(component: Component, key: str, value: object) None [source]
Annotates
component
withkey
equal tovalue
.Annotations do not affect LilyPond output.
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.annotate(staff[0], "motive_number", 6) >>> abjad.show(staff)
>>> abjad.get.annotation(staff[0], "motive_number") 6
- abjad.bind.attach(indicator: Any, component: Component, *, check_duplicate_indicator: bool = False, context: str | None = None, deactivate: bool = False, direction: Vertical | None = None, do_not_test: bool = False, synthetic_offset: Offset | None = None, tag: Tag | None = None) None [source]
Attaches
indicator
tocomponent
.The class of
component
is almost always a leaf. (A small number of indicators can attach to both leaves and containers.) Acceptable types ofindicator
:* indicator * abjad.Wrapper * abjad.BeforeGraceContainer (DEPRECATED) * abjad.AfterGraceContainer (DEPRECATED)
Attaches articulation to last note in staff:
>>> staff = abjad.Staff("c'4 d' e' f'") >>> articulation = abjad.Articulation(">") >>> abjad.attach(articulation, staff[-1]) >>> abjad.show(staff)
The
check_duplicate_indicator=False
keyword. Consider the case of a score with two staves. In the usual case, it is necessary to attach a metronome mark to the first note of only one of the two staves:>>> staff_1 = abjad.Staff("c''4 d''4 e''4 f''4") >>> staff_2 = abjad.Staff("c'4 d'4 e'4 f'4") >>> score = abjad.Score([staff_1, staff_2]) >>> metronome_mark = abjad.MetronomeMark(abjad.Duration(1, 4), 52) >>> abjad.attach(metronome_mark, staff_1[0]) >>> abjad.show(score)
But what should happen when a conflicting metronome mark is attached at the same moment in a different context? Abjad allows this behavior, but it is not clear what it should mean to have two metronome marks in effect at the same time. Set
check_duplicate_indicators=True
to raise an exception instead.The
context=None
keyword. Indicators that affect many notes, rests or chords in a row define the context at which they take effect. Clefs effect all notes on a staff, for example, which is why attaching a clef to the first note in a staff effects all the others:>>> clef = abjad.Clef("alto") >>> clef.context 'Staff'
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach(clef, staff[0]) >>> abjad.show(staff)
>>> for leaf in abjad.select.leaves(staff): ... leaf, abjad.get.effective(leaf, abjad.Clef) ... (Note("c'4"), Clef(name='alto', hide=False)) (Note("d'4"), Clef(name='alto', hide=False)) (Note("e'4"), Clef(name='alto', hide=False)) (Note("f'4"), Clef(name='alto', hide=False))
This example sets
context="MusicStaff"
to show that the alto clef governs all notes in a custom staff context (rather than the default staff context):>>> voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> staff = abjad.Staff([voice], name="MusicStaff") >>> clef = abjad.Clef("alto") >>> abjad.attach(clef, voice[0], context="MusicStaff") >>> abjad.show(staff)
>>> for leaf in abjad.select.leaves(staff): ... leaf, abjad.get.effective(leaf, abjad.Clef) ... (Note("c'4"), Clef(name='alto', hide=False)) (Note("d'4"), Clef(name='alto', hide=False)) (Note("e'4"), Clef(name='alto', hide=False)) (Note("f'4"), Clef(name='alto', hide=False))
If multiple contexted indicators are attached at the same offset then
abjad.attach()
raisesabjad.PersistentIndicatorError
if all indicators are active. But simultaneous contexted indicators are allowed if only one is active (and all others are inactive):>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach(abjad.Clef("treble"), staff[0]) >>> abjad.attach( ... abjad.Clef("alto"), ... staff[0], ... deactivate=True, ... tag=abjad.Tag("+PARTS"), ... ) >>> abjad.attach( ... abjad.Clef("tenor"), ... staff[0], ... deactivate=True, ... tag=abjad.Tag("+PARTS"), ... ) >>> abjad.show(staff)
Active indicator is always effective when competing inactive indicators are present:
>>> for note in staff: ... clef = abjad.get.effective(staff[0], abjad.Clef) ... note, clef ... (Note("c'4"), Clef(name='treble', hide=False)) (Note("d'4"), Clef(name='treble', hide=False)) (Note("e'4"), Clef(name='treble', hide=False)) (Note("f'4"), Clef(name='treble', hide=False))
But a lone inactivate indicator is effective when no active indicator is present. Note that
tag
must be anabjad.Tag
whendeactivate=True
:>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach( ... abjad.Clef("alto"), ... staff[0], ... deactivate=True, ... tag=abjad.Tag("+PARTS"), ... ) >>> abjad.show(staff)
>>> for note in staff: ... clef = abjad.get.effective(staff[0], abjad.Clef) ... note, clef ... (Note("c'4"), Clef(name='alto', hide=False)) (Note("d'4"), Clef(name='alto', hide=False)) (Note("e'4"), Clef(name='alto', hide=False)) (Note("f'4"), Clef(name='alto', hide=False))
- abjad.bind.detach(indicator, component: Component, *, by_id: bool = False) tuple [source]
Detaches indicators equals to
indicator
fromcomponent
. Returns tuple of zero or more detached items.Detaches articulations from first note in staff:
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach(abjad.Articulation(">"), staff[0]) >>> abjad.show(staff)
>>> abjad.detach(abjad.Articulation, staff[0]) (Articulation(name='>'),)
>>> abjad.show(staff)
Set
by_id
to true to detach exactindicator
fromcomponent
(rather than detaching all indicatorslequal toindicator
). The use ofby_id
is motivated by the following.Consider the three document-specifier markups below:
>>> markup_1 = abjad.Markup(r"\markup tutti") >>> markup_2 = abjad.Markup(r"\markup { with the others }") >>> markup_3 = abjad.Markup(r"\markup { with the others }")
Markups two and three compare equal:
>>> markup_2 == markup_3 True
But document-tagging like this makes sense for score and two diferent parts:
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach( ... markup_1, staff[0], direction=abjad.UP, tag=abjad.Tag(string="+SCORE") ... ) >>> abjad.attach( ... markup_2, ... staff[0], ... deactivate=True, ... direction=abjad.UP, ... tag=abjad.Tag("+PARTS_VIOLIN_1"), ... ) >>> abjad.attach( ... markup_3, ... staff[0], ... deactivate=True, ... direction=abjad.UP, ... tag=abjad.Tag("+PARTS_VIOLIN_2"), ... ) >>> abjad.show(staff)
>>> string = abjad.lilypond(staff, tags=True) >>> print(string) \new Staff { c'4 %! +SCORE ^ \markup tutti %! +PARTS_VIOLIN_1 %@% ^ \markup { with the others } %! +PARTS_VIOLIN_2 %@% ^ \markup { with the others } d'4 e'4 f'4 }
The question is then how to detach just one of the two markups that compare equal to each other?
Passing in one of the markup objects directory doesn’t work. This is because detach tests for equality to input argument:
>>> markups = abjad.detach(markup_2, staff[0]) >>> for markup in markups: ... markup ... Markup(string='\\markup { with the others }') Markup(string='\\markup { with the others }')
>>> abjad.show(staff)
>>> string = abjad.lilypond(staff, tags=True) >>> print(string) \new Staff { c'4 %! +SCORE ^ \markup tutti d'4 e'4 f'4 }
We start again:
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach( ... markup_1, staff[0], direction=abjad.UP, tag=abjad.Tag(string="+SCORE") ... ) >>> abjad.attach( ... markup_2, ... staff[0], ... deactivate=True, ... direction=abjad.UP, ... tag=abjad.Tag("+PARTS_VIOLIN_1"), ... ) >>> abjad.attach( ... markup_3, ... staff[0], ... deactivate=True, ... direction=abjad.UP, ... tag=abjad.Tag("+PARTS_VIOLIN_2"), ... ) >>> abjad.show(staff)
>>> string = abjad.lilypond(staff, tags=True) >>> print(string) \new Staff { c'4 %! +SCORE ^ \markup tutti %! +PARTS_VIOLIN_1 %@% ^ \markup { with the others } %! +PARTS_VIOLIN_2 %@% ^ \markup { with the others } d'4 e'4 f'4 }
This time we set
by_id
to true. Now detach checks the exact id of its input argument (rather than just testing for equality). This gives us what we want:>>> markups = abjad.detach(markup_2, staff[0], by_id=True) >>> for markup in markups: ... markup ... Markup(string='\\markup { with the others }')
>>> abjad.show(staff)
>>> string = abjad.lilypond(staff, tags=True) >>> print(string) \new Staff { c'4 %! +SCORE ^ \markup tutti %! +PARTS_VIOLIN_2 %@% ^ \markup { with the others } d'4 e'4 f'4 }
REGRESSION. Attach-detach-attach pattern works correctly when detaching wrappers:
>>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.attach(abjad.Clef("alto"), staff[0]) >>> abjad.show(staff)
>>> wrapper = abjad.get.wrappers(staff[0])[0] >>> abjad.detach(wrapper, wrapper.component) (Wrapper(annotation=None, context='Staff', deactivate=False, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='')),)
>>> abjad.show(staff)
>>> abjad.attach(abjad.Clef("tenor"), staff[0]) >>> abjad.show(staff)