"""Build Abjad attachments from Mutwo data.
"""
import dataclasses
import inspect
import typing
import warnings
import abjad # type: ignore
from mutwo import abjad_parameters
from mutwo import music_parameters
LeafOrLeafSequence = abjad.Leaf | typing.Sequence[abjad.Leaf]
[docs]class Arpeggio(abjad_parameters.abc.BangFirstAttachment):
_string_to_direction = {
"up": abjad.enums.UP,
"down": abjad.enums.DOWN,
"center": abjad.enums.CENTER,
"^": abjad.enums.UP,
"_": abjad.enums.DOWN,
}
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
direction = self.indicator.direction
direction = self._string_to_direction.get(direction, direction)
abjad.attach(abjad.Arpeggio(direction=direction), leaf)
return leaf
[docs]class Articulation(abjad_parameters.abc.BangEachAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(abjad.Articulation(self.indicator.name), leaf)
return leaf
[docs]class Trill(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(abjad.Articulation("trill"), leaf)
return leaf
[docs]class Cue(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.Markup(rf"\markup \rounded-box {{ {self.indicator.index} }}"),
leaf,
direction=abjad.enums.UP,
)
return leaf
[docs]class WoodwindFingering(abjad_parameters.abc.BangFirstAttachment):
fingering_size = 0.7
@staticmethod
def _tuple_to_scheme_list(tuple_to_convert: tuple[str, ...]) -> str:
return f"({' '.join(tuple_to_convert)})"
def _get_markup_content(self) -> str:
# \\override #'(graphical . #f)
return f"""
\\override #'(size . {self.fingering_size})
{{
\\woodwind-diagram
#'{self.indicator.instrument}
#'((cc . {self._tuple_to_scheme_list(self.indicator.cc)})
(lh . {self._tuple_to_scheme_list(self.indicator.left_hand)})
(rh . {self._tuple_to_scheme_list(self.indicator.right_hand)}))
}}"""
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
fingering = abjad.LilyPondLiteral(
f"^\\markup {self._get_markup_content()}", site="after"
)
abjad.attach(fingering, leaf)
return leaf
[docs]class Tremolo(abjad_parameters.abc.BangEachAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.StemTremolo(
self.indicator.flag_count * (2**leaf.written_duration.flag_count)
),
leaf,
)
return leaf
[docs]class ArtificalHarmonic(abjad_parameters.abc.BangEachAttachment):
@staticmethod
def _convert_and_test_leaf(leaf: abjad.Leaf) -> tuple[abjad.Leaf, bool]:
# return True if artifical_harmonic can be attached and False if
# artifical harmonic can't be attached
match leaf:
case abjad.Chord():
if len(leaf.note_heads) != 1:
warnings.warn(
"Can't attach artifical harmonic on chord with more or less"
" than one pitch!"
)
return leaf, False
return leaf, True
case abjad.Note():
new_abjad_leaf = abjad.Chord(
[leaf.written_pitch],
leaf.written_duration,
)
for indicator in abjad.get.indicators(leaf):
if type(indicator) != dict:
abjad.attach(indicator, new_abjad_leaf)
return new_abjad_leaf, True
case _:
warnings.warn(
f"Can't attach artifical harmonic on abjad leaf "
f"'{leaf}' of type '{type(leaf)}'!"
)
return leaf, False
def _get_second_pitch(self, abjad_pitch: abjad.Pitch) -> abjad.Pitch:
return abjad_pitch + self.indicator.semitone_count
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
leaf, is_attachable = ArtificalHarmonic._convert_and_test_leaf(leaf)
if is_attachable:
first_pitch = leaf.note_heads[0].written_pitch
second_pitch = self._get_second_pitch(first_pitch)
leaf.written_pitches = abjad.PitchSegment([first_pitch, second_pitch])
set_note_head_style(leaf, note_head_index=1)
return leaf
[docs]class NaturalHarmonicNodeList(abjad_parameters.abc.AbjadAttachment):
replace_leaf_by_leaf = False
# Some indicators are needed for both elements!
disallow_detach_indicator_list = [abjad.LilyPondLiteral(r"\-", site="after")]
[docs] def process_leaf_tuple(
self,
leaf_tuple: tuple[abjad.Leaf, ...],
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> typing.Sequence[abjad.Leaf]:
if len((indicator := self.indicator)) > 2:
warnings.warn(
"Can only represent double harmonics, "
"but not triple or more. The following nodes "
f"are ignored:\n\n\t{self.indicator[2:]}"
)
indicator = indicator[:2]
stem_direction_tuple = self._node_tuple_to_stem_direction_tuple(
tuple(indicator)
)
# We put each harmonic into its own voice, because we
# don't want to have all harmonics on the same stem,
# because then it's not clear for the player which node
# on which string she or he needs to play. If the stems
# are separated this is very clear.
container = abjad.Container([], simultaneous=True)
for index, data in enumerate(zip(indicator, stem_direction_tuple)):
node, stem_direction = data
voice = abjad.Voice([])
if self.with_duration_line:
voice.consists_commands.append("Duration_line_engraver")
for leaf in leaf_tuple:
leaf = self._leaf_to_chord(leaf)
if index > 0: # Avoid indicator duplicates!
self._detach_all_indicators(leaf)
self._process_leaf(leaf, node, stem_direction)
voice.append(leaf)
container.append(voice)
return container
def _process_leaf(
self,
leaf_to_process: abjad.Chord,
node: music_parameters.NaturalHarmonic.Node,
stem_direction: bool | type[None],
):
m2a = self.mutwo_pitch_to_abjad_pitch
pitch_segment = [m2a(node.pitch)]
if self.indicator.write_string:
pitch_segment.insert(0, m2a(node.string.tuning_original))
leaf_to_process.written_pitches = abjad.PitchSegment(pitch_segment)
if self.indicator.write_string and self.indicator.parenthesize_lower_note_head:
leaf_to_process.note_heads[0].is_parenthesized = True
if self.indicator.harmonic_note_head_style:
set_note_head_style(
leaf_to_process, note_head_index=int(self.indicator.write_string)
)
if stem_direction in (True, False):
abjad.attach(
abjad.LilyPondLiteral(
r"\once \override Staff.Stem.thickness = 2"
"\n"
r"\once \override Voice.Stem.direction = "
f"{[-1, 1][int(stem_direction)]}",
site="before",
),
leaf_to_process,
)
if self.with_duration_line:
abjad.attach(
abjad.LilyPondLiteral(
r"\once \override Staff.Stem.duration-log = 2"
"\n"
r"\once \undo \omit Staff.Stem"
"\n",
site="before",
),
leaf_to_process,
)
if stem_direction is False:
abjad.attach(
abjad.LilyPondLiteral(
r"\once \override NoteColumn #'force-hshift = #1.5", site="before"
),
leaf_to_process,
)
def _detach_all_indicators(self, leaf_to_process: abjad.Chord):
for indicator in abjad.get.indicators(leaf_to_process):
if indicator not in self.disallow_detach_indicator_list:
abjad.detach(indicator, leaf_to_process)
@staticmethod
def _node_tuple_to_stem_direction_tuple(
node_tuple: tuple[music_parameters.NaturalHarmonic.Node]
| tuple[
music_parameters.NaturalHarmonic.Node, music_parameters.NaturalHarmonic.Node
]
) -> tuple[bool | type[None], ...]:
if (node_count := len(node_tuple)) == 2:
node0, node1 = node_tuple # type: ignore
if node0.pitch > node1.pitch:
stem_direction_tuple = (False, True)
elif node0.pitch == node1.pitch:
stem_direction_tuple = (True, True)
else:
stem_direction_tuple = (True, False)
elif node_count == 1:
stem_direction_tuple = (None,) # type: ignore
else:
raise NotImplementedError(node_count)
return stem_direction_tuple
@staticmethod
def _leaf_to_chord(leaf: abjad.Leaf) -> abjad.Chord:
if isinstance(leaf, abjad.Chord):
return abjad.mutate.copy(leaf)
else:
new_abjad_leaf = abjad.Chord(
"c",
leaf.written_duration,
)
for indicator in abjad.get.indicators(leaf):
if type(indicator) != dict:
abjad.attach(indicator, new_abjad_leaf)
return new_abjad_leaf
[docs]class Pedal(abjad_parameters.abc.ToggleAttachment):
[docs] def process_leaf(
self,
leaf: abjad.Leaf,
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> LeafOrLeafSequence:
if self.indicator.pedal_activity:
pedal_class = abjad.StartPianoPedal
else:
pedal_class = abjad.StopPianoPedal
abjad.attach(pedal_class(self.indicator.pedal_type), leaf)
return leaf
[docs] def process_leaf_tuple(
self,
leaf_tuple: tuple[abjad.Leaf, ...],
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> tuple[abjad.Leaf, ...]:
# don't attach pedal down at start
if previous_attachment is not None or self.indicator.is_active:
return super().process_leaf_tuple(leaf_tuple, previous_attachment)
else:
return leaf_tuple
[docs]class Hairpin(abjad_parameters.abc.ToggleAttachment):
niente_literal = abjad.LilyPondLiteral(r"\once \override Hairpin.circled-tip = ##t")
[docs] def process_leaf(
self,
leaf: abjad.Leaf,
_: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> LeafOrLeafSequence:
if self.indicator.symbol == "!":
abjad.attach(
abjad.StopHairpin(),
leaf,
)
else:
if self.indicator.niente:
abjad.attach(self.niente_literal, leaf)
abjad.attach(
abjad.StartHairpin(self.indicator.symbol),
leaf,
)
return leaf
def _process_espressivo(
self,
leaf_tuple: tuple[abjad.Leaf, ...],
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> tuple[abjad.Leaf, ...]:
leaf_count = len(leaf_tuple)
if leaf_count >= 2:
crescendo_leaf = leaf_tuple[0]
if self.indicator.niente:
abjad.attach(self.niente_literal, crescendo_leaf)
abjad.attach(abjad.StartHairpin("<"), crescendo_leaf)
decrescendo_leaf = leaf_tuple[int(len(leaf_tuple) // 2)]
if self.indicator.niente:
abjad.attach(self.niente_literal, decrescendo_leaf)
abjad.attach(abjad.StartHairpin(">"), decrescendo_leaf)
elif leaf_count == 1:
abjad.attach(abjad.Articulation("espressivo"), leaf_tuple[0])
return leaf_tuple
[docs] def process_leaf_tuple(
self,
leaf_tuple: tuple[abjad.Leaf, ...],
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> tuple[abjad.Leaf, ...]:
if self.indicator.symbol == "<>":
return self._process_espressivo(leaf_tuple, previous_attachment)
else:
return super().process_leaf_tuple(leaf_tuple, previous_attachment)
[docs]class BartokPizzicato(
abjad_parameters.abc.BangFirstAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.LilyPondLiteral("\\snappizzicato", site="after"),
leaf,
)
return leaf
[docs]class BreathMark(
abjad_parameters.abc.BangFirstAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.LilyPondLiteral("\\breathe", site="before"),
leaf,
)
return leaf
[docs]class Fermata(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.Fermata(self.indicator.type),
leaf,
)
return leaf
[docs]class Prall(
abjad_parameters.abc.BangFirstAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.LilyPondLiteral(r"^\prall", site="after"),
leaf,
)
return leaf
[docs]class Tie(
abjad_parameters.abc.BangLastAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
if isinstance(leaf, (abjad.Chord, abjad.Note)):
abjad.attach(
abjad.Tie(),
leaf,
)
return leaf
[docs]class DurationLineTriller(
abjad_parameters.abc.BangEachAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
if isinstance(leaf, (abjad.Chord, abjad.Note)):
abjad.attach(
abjad.LilyPondLiteral(r"\once \override DurationLine.style = #'trill"),
leaf,
)
return leaf
[docs]class DurationLineDashed(
abjad_parameters.abc.BangEachAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
if isinstance(leaf, (abjad.Chord, abjad.Note)):
abjad.attach(
abjad.LilyPondLiteral(
r"\once \override DurationLine.style = #'dashed-line"
),
leaf,
)
return leaf
[docs]class Glissando(
abjad_parameters.abc.BangLastAttachment,
):
thickness = 3
minimum_length = 5
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.LilyPondLiteral(
"\\override Glissando.thickness = #'{}".format(self.thickness)
),
leaf,
)
abjad.attach(
abjad.LilyPondLiteral(
"\\override Glissando.minimum-length = #{}".format(self.minimum_length)
),
leaf,
)
abjad.attach(
abjad.LilyPondLiteral("\\override Glissando.breakable = ##t"),
leaf,
)
abjad.attach(
abjad.LilyPondLiteral("\\override Glissando.after-line-breaking = ##t"),
leaf,
)
# Prevent duration line from getting printed when we print a glissando
abjad.attach(
abjad.LilyPondLiteral("\\once \\override DurationLine.style = #'none"), leaf
)
command = "\\override "
command += "Glissando.springs-and-rods = #ly:spanner::set-spacing-rods"
abjad.attach(abjad.LilyPondLiteral(command), leaf)
abjad.attach(
abjad.Glissando(allow_ties=True),
leaf,
)
return leaf
[docs]class BendAfter(abjad_parameters.abc.BangLastAttachment):
def _attach_bend_after_to_note(self, note: abjad.Note):
abjad.attach(
abjad.LilyPondLiteral(
"\\once \\override BendAfter.thickness = #'{}".format(
self.indicator.thickness
)
),
note,
)
abjad.attach(
abjad.LilyPondLiteral(
f"\\once \\override BendAfter.minimum-length = #{self.indicator.minimum_length}"
),
note,
)
abjad.attach(
abjad.LilyPondLiteral("\\once \\override DurationLine.style = #'none"), note
)
abjad.attach(abjad.BendAfter(bend_amount=self.indicator.bend_amount), note)
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
if isinstance(leaf, abjad.Chord):
indicator_list = abjad.get.indicators(leaf)
container = abjad.Container([], simultaneous=True)
for note_head in leaf.note_heads:
note = abjad.Note("c", leaf.written_duration)
note.note_head._written_pitch = note_head.written_pitch
self._attach_bend_after_to_note(note)
for indicator in indicator_list:
abjad.attach(indicator, note)
voice = abjad.Voice([note])
container.append(voice)
return container
elif isinstance(leaf, abjad.Note):
self._attach_bend_after_to_note(leaf)
return leaf
[docs]class LaissezVibrer(
abjad_parameters.abc.BangLastAttachment,
):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.LaissezVibrer(),
leaf,
)
return leaf
[docs]class BarLine(abjad_parameters.abc.BangLastAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.BarLine(self.indicator.abbreviation),
leaf,
)
return leaf
[docs]class Clef(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.Clef(self.indicator.name),
leaf,
)
return leaf
[docs]class Ottava(abjad_parameters.abc.ToggleAttachment):
[docs] def process_leaf(
self,
leaf: abjad.Leaf,
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> LeafOrLeafSequence:
abjad.attach(
abjad.Ottava(self.indicator.octave_count, site="before"),
leaf,
)
return leaf
[docs] def process_leaf_tuple(
self,
leaf_tuple: tuple[abjad.Leaf, ...],
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> tuple[abjad.Leaf, ...]:
# don't attach ottava = 0 at start (this is the default notation)
if previous_attachment is not None or self.indicator.octave_count != 0:
return super().process_leaf_tuple(leaf_tuple, previous_attachment)
else:
return leaf_tuple
[docs]class Markup(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.Markup(self.indicator.content),
leaf,
direction=self.indicator.direction,
)
return leaf
[docs]class RehearsalMark(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
abjad.RehearsalMark(markup=self.indicator.markup),
leaf,
)
return leaf
[docs]class MarginMarkup(abjad_parameters.abc.BangFirstAttachment):
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
command = "\\set {}.instrumentName = \\markup ".format(self.indicator.context)
command += "{ " + self.indicator.content + " }" # type: ignore
abjad.attach(
abjad.LilyPondLiteral(command),
leaf,
)
return leaf
[docs]class Ornamentation(abjad_parameters.abc.BangFirstAttachment):
_direction_to_ornamentation_command = {
"up": """
#'((moveto 0 0)
(lineto 0.5 0)
(curveto 0.5 0 1.5 1.75 2.5 0)
(lineto 3.5 0))""",
"down": """
#'((moveto 0 0)
(lineto 0.5 0)
(curveto 0.5 0 1.5 -1.75 2.5 0)
(lineto 3.5 0))""",
}
def _make_markup(self) -> abjad.Markup:
return abjad.Markup(
r"\markup { "
r"\vspace #-0.25 { \fontsize #-4 { "
rf"\rounded-box {{ {self.indicator.count} "
r"\hspace #-0.4 \path #0.25 "
f"{self._direction_to_ornamentation_command[self.indicator.direction]}"
"}}}}"
)
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(
self._make_markup(),
leaf,
direction=abjad.enums.UP,
)
return leaf
[docs]@dataclasses.dataclass()
class Dynamic(abjad_parameters.abc.ToggleAttachment):
dynamic_indicator: str = "mf" # TODO(for future usage add typing.Literal)
[docs] @classmethod
def from_indicator_collection(
cls, indicator_collection: music_parameters.abc.IndicatorCollection, **kwargs
) -> typing.Optional[abjad_parameters.abc.AbjadAttachment]:
"""Always return None.
Dynamic can't be initialised from IndicatorCollection.
"""
return None
@property
def is_active(self) -> bool:
return True
[docs] def process_leaf(
self,
leaf: abjad.Leaf,
previous_attachment: typing.Optional[abjad_parameters.abc.AbjadAttachment],
) -> LeafOrLeafSequence:
abjad.attach(abjad.Dynamic(self.dynamic_indicator), leaf)
return leaf
[docs]@dataclasses.dataclass()
class Tempo(abjad_parameters.abc.BangFirstAttachment):
reference_duration: typing.Optional[tuple[int, int]] = (1, 4)
units_per_minute: int | tuple[int, int] | None = 60
textual_indication: typing.Optional[str] = None
# TODO(for future usage add typing.Literal['rit.', 'acc.'])
dynamic_change_indication: typing.Optional[str] = None
stop_dynamic_change_indicaton: bool = False
print_metronome_mark: bool = True
[docs] @classmethod
def from_indicator_collection(
cls, indicator_collection: music_parameters.abc.IndicatorCollection, **kwargs
) -> typing.Optional[abjad_parameters.abc.AbjadAttachment]:
"""Always return None.
Tempo can't be initialised from IndicatorCollection.
"""
return None
@property
def is_active(self) -> bool:
return True
def _attach_metronome_mark(self, leaf: abjad.Leaf) -> None:
if self.print_metronome_mark:
abjad.attach(
abjad.MetronomeMark(
reference_duration=self.reference_duration,
units_per_minute=self.units_per_minute,
textual_indication=self.textual_indication,
),
leaf,
)
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
self._attach_metronome_mark(leaf)
if self.dynamic_change_indication is not None:
dynamic_change_indication = abjad.StartTextSpan(
left_text=abjad.Markup(self.dynamic_change_indication)
)
abjad.attach(dynamic_change_indication, leaf)
return leaf
[docs]class DynamicChangeIndicationStop(abjad_parameters.abc.BangFirstAttachment):
[docs] @classmethod
def from_indicator_collection(
cls, indicator_collection: music_parameters.abc.IndicatorCollection, **kwargs
) -> typing.Optional[abjad_parameters.abc.AbjadAttachment]:
"""Always return None.
DynamicChangeIndicationStop can't be initialised from IndicatorCollection.
"""
return None
@property
def is_active(self) -> bool:
return True
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(abjad.StopTextSpan(), leaf)
return leaf
[docs]class GraceNoteConsecution(abjad_parameters.abc.BangFirstAttachment):
def __init__(self, grace_note_consecution: abjad.BeforeGraceContainer):
self._grace_note_consecution = grace_note_consecution
[docs] @classmethod
def from_indicator_collection(
cls, indicator_collection: music_parameters.abc.IndicatorCollection, **kwargs
) -> typing.Optional[abjad_parameters.abc.AbjadAttachment]:
"""Always return None.
GraceNoteConsecution can't be initialised from IndicatorCollection.
"""
return None
@property
def is_active(self) -> bool:
return True
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
for (
indicator_to_detach
) in (
abjad_parameters.constants.INDICATORS_TO_DETACH_FROM_MAIN_LEAF_AT_GRACE_NOTES_TUPLE
):
detached_indicator = abjad.detach(indicator_to_detach, leaf)
abjad.attach(detached_indicator, self._grace_note_consecution[0])
abjad.attach(self._grace_note_consecution, leaf)
return leaf
[docs]class AfterGraceNoteConsecution(abjad_parameters.abc.BangLastAttachment):
def __init__(self, after_grace_note_consecution: abjad.AfterGraceContainer):
self._after_grace_note_consecution = after_grace_note_consecution
[docs] @classmethod
def from_indicator_collection(
cls, indicator_collection: music_parameters.abc.IndicatorCollection, **kwargs
) -> typing.Optional[abjad_parameters.abc.AbjadAttachment]:
"""Always return None.
AfterGraceNoteConsecution can't be initialised from IndicatorCollection.
"""
return None
@property
def is_active(self) -> bool:
return True
[docs] def process_leaf(self, leaf: abjad.Leaf) -> LeafOrLeafSequence:
abjad.attach(self._after_grace_note_consecution, leaf)
return leaf
def set_note_head_style(
leaf: abjad.Chord, note_head_index: int = 0, style: str = "#'harmonic"
):
abjad.tweak(
leaf.note_heads[note_head_index],
abjad.Tweak(rf"\tweak NoteHead.style {style}"),
)
# Auto define all due to many classes
__all__ = tuple(
name
for name, cls in globals().items()
if inspect.isclass(cls)
and not inspect.isabstract(cls)
and abjad_parameters.abc.AbjadAttachment in inspect.getmro(cls)
)