Source code for abjad.parentage

import collections
import fractions

from . import math as _math
from . import score as _score


[docs]class Parentage(collections.abc.Sequence): r''' Parentage of a component. .. container:: example >>> score = abjad.Score() >>> string = r"""\new Voice = "Treble_Voice" { e'4 }""" >>> treble_staff = abjad.Staff(string, name="Treble_Staff") >>> score.append(treble_staff) >>> string = r"""\new Voice = "Bass_Voice" { c4 }""" >>> bass_staff = abjad.Staff(string, name="Bass_Staff") >>> clef = abjad.Clef('bass') >>> abjad.attach(clef, bass_staff[0][0]) >>> score.append(bass_staff) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \new Score << \context Staff = "Treble_Staff" { \context Voice = "Treble_Voice" { e'4 } } \context Staff = "Bass_Staff" { \context Voice = "Bass_Voice" { \clef "bass" c4 } } >> >>> bass_voice = score["Bass_Voice"] >>> note = bass_voice[0] >>> for component in abjad.get.parentage(note): ... component ... Note('c4') Voice('c4', name='Bass_Voice') Staff('{ c4 }', name='Bass_Staff') Score("{ { e'4 } } { { c4 } }", simultaneous=True) ''' ### CLASS VARIABLES ### __slots__ = ("_component", "_components") ### INITIALIZER ### def __init__(self, component=None): components = [] if component is not None: assert isinstance(component, _score.Component), repr(component) components.extend(component._get_parentage()) self._component = component self._components = tuple(components) ### SPECIAL METHODS ###
[docs] def __eq__(self, argument): """ Is true when ``argument`` is a parent with the same components as this parentage. """ if isinstance(argument, type(self)): if len(self) == len(argument): for c, d in zip(self, argument): if c is not d: return False else: return True return False
[docs] def __getitem__(self, argument): """ Gets ``argument``. Returns component or tuple of components. """ return self.components.__getitem__(argument)
[docs] def __len__(self) -> int: """ Gets number of components in parentage. """ return len(self.components)
[docs] def __repr__(self): """ Gets repr. """ return f"{type(self).__name__}(component={self.component!r})"
### PRIVATE METHODS ### @staticmethod def _id_string(component): lhs = component.__class__.__name__ rhs = getattr(component, "name", None) or id(component) return f"{lhs}-{rhs!r}" def _prolations(self): prolations = [] default = fractions.Fraction(1) for parent in self: prolation = getattr(parent, "implied_prolation", default) prolations.append(prolation) return prolations ### PUBLIC PROPERTIES ### @property def component(self) -> _score.Component: r""" Gets component. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... print(f"{repr(component):30} {repr(parentage.component)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Note("c'4") Note("c'4") BeforeGraceContainer("cs'16") BeforeGraceContainer("cs'16") Note("cs'16") Note("cs'16") Note("d'4") Note("d'4") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Chord("<e' g'>16") Chord("<e' g'>16") Note("gs'16") Note("gs'16") Note("a'16") Note("a'16") Note("as'16") Note("as'16") Voice("e'4", name='MusicVoice') Voice("e'4", name='MusicVoice') Note("e'4") Note("e'4") Note("f'4") Note("f'4") AfterGraceContainer("fs'16") AfterGraceContainer("fs'16") Note("fs'16") Note("fs'16") """ return self._component @property def components(self) -> tuple[_score.Component]: r""" Gets components. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... components = parentage.components ... print(f"{repr(component)}:") ... for component_ in components: ... print(f" {repr(component_)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }"): Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice'): Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("c'4"): Note("c'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") BeforeGraceContainer("cs'16"): BeforeGraceContainer("cs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("cs'16"): Note("cs'16") BeforeGraceContainer("cs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("d'4"): Note("d'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }"): Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16"): OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Chord("<e' g'>16"): Chord("<e' g'>16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("gs'16"): Note("gs'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("a'16"): Note("a'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("as'16"): Note("as'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("e'4", name='MusicVoice'): Voice("e'4", name='MusicVoice') Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("e'4"): Note("e'4") Voice("e'4", name='MusicVoice') Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("f'4"): Note("f'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") AfterGraceContainer("fs'16"): AfterGraceContainer("fs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("fs'16"): Note("fs'16") AfterGraceContainer("fs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") """ return self._components @property def orphan(self) -> bool: r""" Is true when component has no parent. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... print(f"{repr(component):30} {repr(parentage.orphan)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") True Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') False Note("c'4") False BeforeGraceContainer("cs'16") False Note("cs'16") False Note("d'4") False Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") False OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") False Chord("<e' g'>16") False Note("gs'16") False Note("a'16") False Note("as'16") False Voice("e'4", name='MusicVoice') False Note("e'4") False Note("f'4") False AfterGraceContainer("fs'16") False Note("fs'16") False """ return self.parent is None @property def parent(self) -> _score.Component | None: r""" Gets parent. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... print(f"{repr(component):30} {repr(parentage.parent)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") None Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("c'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') BeforeGraceContainer("cs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Note("cs'16") BeforeGraceContainer("cs'16") Note("d'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Chord("<e' g'>16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Note("gs'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Note("a'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Note("as'16") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Voice("e'4", name='MusicVoice') Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Note("e'4") Voice("e'4", name='MusicVoice') Note("f'4") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') AfterGraceContainer("fs'16") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Note("fs'16") AfterGraceContainer("fs'16") """ return self.get(n=1) @property def prolation(self) -> fractions.Fraction: r""" Gets prolation. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice( ... r"\times 2/3 { c'4 d' e' } \times 2/3 { f' g' a' }", ... name="MusicVoice" ... ) >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[0][1]) >>> container = abjad.on_beat_grace_container( ... "a'8 b'", music_voice[1][:1] ... ) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[1][2]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { \times 2/3 { c'4 \grace { cs'16 } d'4 e'4 } \times 2/3 { << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t f' a' >8 [ ( b'8 ) ] } \context Voice = "MusicVoice" { \voiceTwo f'4 } >> \oneVoice g'4 \afterGrace a'4 { fs'16 } } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... print(f"{repr(component):30} {repr(parentage.prolation)}") Staff("{ { 2/3 c'4 d'4 e'4 } { 2/3 { { <f' a'>8 b'8 } { f'4 } } g'4 a'4 } }") Fraction(1, 1) Voice("{ 2/3 c'4 d'4 e'4 } { 2/3 { { <f' a'>8 b'8 } { f'4 } } g'4 a'4 }", name='MusicVoice') Fraction(1, 1) Tuplet('3:2', "c'4 d'4 e'4") Fraction(2, 3) Note("c'4") Fraction(2, 3) BeforeGraceContainer("cs'16") Fraction(2, 3) Note("cs'16") Fraction(2, 3) Note("d'4") Fraction(2, 3) Note("e'4") Fraction(2, 3) Tuplet('3:2', "{ { <f' a'>8 b'8 } { f'4 } } g'4 a'4") Fraction(2, 3) Container("{ <f' a'>8 b'8 } { f'4 }") Fraction(2, 3) OnBeatGraceContainer("<f' a'>8 b'8") Fraction(2, 3) Chord("<f' a'>8") Fraction(2, 3) Note("b'8") Fraction(2, 3) Voice("f'4", name='MusicVoice') Fraction(2, 3) Note("f'4") Fraction(2, 3) Note("g'4") Fraction(2, 3) Note("a'4") Fraction(2, 3) AfterGraceContainer("fs'16") Fraction(2, 3) Note("fs'16") Fraction(2, 3) """ prolations = [fractions.Fraction(1)] + self._prolations() products = _math.cumulative_products(prolations) return products[-1] @property def root(self) -> _score.Component: r""" Gets root. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... print(f"{repr(component):30} {repr(parentage.root)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("c'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") BeforeGraceContainer("cs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("cs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("d'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Chord("<e' g'>16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("gs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("a'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("as'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("e'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("e'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("f'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") AfterGraceContainer("fs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("fs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") """ root = self.get(n=-1) assert isinstance(root, _score.Component), repr(root) return root ### PUBLIC METHODS ###
[docs] def count(self, prototype=None) -> int: r""" Gets number of ``prototype`` in parentage. Gets tuplet count: .. container:: example >>> staff = abjad.Staff( ... r"\times 2/3 { c'2 \times 2/3 { d'8 e' f' } } \times 2/3 { c'4 d' e' }" ... ) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \times 2/3 { c'2 \times 2/3 { d'8 e'8 f'8 } } \times 2/3 { c'4 d'4 e'4 } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... count = parentage.count(abjad.Tuplet) ... print(f"{repr(component):55} {repr(count)}") Staff("{ 2/3 c'2 { 2/3 d'8 e'8 f'8 } } { 2/3 c'4 d'4 e'4 }") 0 Tuplet('3:2', "c'2 { 2/3 d'8 e'8 f'8 }") 1 Note("c'2") 1 Tuplet('3:2', "d'8 e'8 f'8") 2 Note("d'8") 2 Note("e'8") 2 Note("f'8") 2 Tuplet('3:2', "c'4 d'4 e'4") 1 Note("c'4") 1 Note("d'4") 1 Note("e'4") 1 .. container:: example Gets voice count: >>> outer_red_voice = abjad.Voice("e''8 d''", name="Red_Voice") >>> inner_red_voice = abjad.Voice("c''4 b' c''8", name="Red_Voice") >>> inner_blue_voice = abjad.Voice("e'4 f' e'8", name="Blue_Voice") >>> container = abjad.Container( ... [inner_red_voice, inner_blue_voice], ... simultaneous=True, ... ) >>> outer_red_voice.append(container) >>> outer_red_voice.extend("d''8") >>> abjad.override(outer_red_voice).NoteHead.color = "#red" >>> command = abjad.VoiceNumber(1) >>> abjad.attach(command, outer_red_voice[0]) >>> abjad.override(inner_blue_voice).NoteHead.color = "#blue" >>> command = abjad.VoiceNumber(2) >>> abjad.attach(command, inner_blue_voice[0]) >>> dynamic = abjad.Dynamic("f") >>> abjad.attach(dynamic, outer_red_voice[0]) >>> abjad.show(outer_red_voice) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(outer_red_voice) >>> print(string) \context Voice = "Red_Voice" \with { \override NoteHead.color = #red } { \voiceOne e''8 \f d''8 << \context Voice = "Red_Voice" { c''4 b'4 c''8 } \context Voice = "Blue_Voice" \with { \override NoteHead.color = #blue } { \voiceTwo e'4 f'4 e'8 } >> d''8 } >>> for leaf in abjad.iterate.leaves(outer_red_voice): ... depth = abjad.get.parentage(leaf).count(abjad.Voice) ... print(leaf, depth) ... Note("e''8") 1 Note("d''8") 1 Note("c''4") 2 Note("b'4") 2 Note("c''8") 2 Note("e'4") 2 Note("f'4") 2 Note("e'8") 2 Note("d''8") 1 .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... count = parentage.count(abjad.Staff) ... print(f"{repr(component):30} {repr(count)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") 1 Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') 1 Note("c'4") 1 BeforeGraceContainer("cs'16") 1 Note("cs'16") 1 Note("d'4") 1 Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") 1 OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") 1 Chord("<e' g'>16") 1 Note("gs'16") 1 Note("a'16") 1 Note("as'16") 1 Voice("e'4", name='MusicVoice') 1 Note("e'4") 1 Note("f'4") 1 AfterGraceContainer("fs'16") 1 Note("fs'16") 1 """ n = 0 if prototype is None: prototype = _score.Component for component in self: if isinstance(component, prototype): n += 1 return n
[docs] def get(self, prototype=None, n=0) -> _score.Component | None: r""" Gets instance ``n`` of ``prototype`` in parentage. .. container:: example >>> outer_red_voice = abjad.Voice("e''8 d''", name="Red_Voice") >>> inner_red_voice = abjad.Voice("c''4 b' c''8", name="Red_Voice") >>> inner_blue_voice = abjad.Voice("e'4 f' e'8", name="Blue_Voice") >>> container = abjad.Container( ... [inner_red_voice, inner_blue_voice], ... simultaneous=True, ... ) >>> outer_red_voice.append(container) >>> outer_red_voice.extend("d''8") >>> abjad.override(outer_red_voice).NoteHead.color = "#red" >>> command = abjad.VoiceNumber(1) >>> abjad.attach(command, outer_red_voice[0]) >>> abjad.override(inner_blue_voice).NoteHead.color = "#blue" >>> command = abjad.VoiceNumber(2) >>> abjad.attach(command, inner_blue_voice[0]) >>> dynamic = abjad.Dynamic("f") >>> abjad.attach(dynamic, outer_red_voice[0]) >>> abjad.show(outer_red_voice) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(outer_red_voice) >>> print(string) \context Voice = "Red_Voice" \with { \override NoteHead.color = #red } { \voiceOne e''8 \f d''8 << \context Voice = "Red_Voice" { c''4 b'4 c''8 } \context Voice = "Blue_Voice" \with { \override NoteHead.color = #blue } { \voiceTwo e'4 f'4 e'8 } >> d''8 } .. container:: example >>> leaf = abjad.get.leaf(inner_red_voice, 0) >>> leaf Note("c''4") >>> parentage = abjad.get.parentage(leaf) Returns self when ``n=0``: >>> parentage.get(abjad.Component, 0) Note("c''4") Returns parents with positive ``n``: >>> parentage.get(abjad.Component, 1) Voice("c''4 b'4 c''8", name='Red_Voice') >>> parentage.get(abjad.Component, 2) Container("{ c''4 b'4 c''8 } { e'4 f'4 e'8 }") >>> parentage.get(abjad.Component, 3) Voice("e''8 d''8 { { c''4 b'4 c''8 } { e'4 f'4 e'8 } } d''8", name='Red_Voice') Returns none with ``n`` greater than score depth: >>> parentage.get(abjad.Component, 4) is None True >>> parentage.get(abjad.Component, 5) is None True >>> parentage.get(abjad.Component, 99) is None True Returns score root with ``n=-1``: >>> parentage.get(abjad.Component, -1) Voice("e''8 d''8 { { c''4 b'4 c''8 } { e'4 f'4 e'8 } } d''8", name='Red_Voice') With other negative ``n``: >>> parentage.get(abjad.Component, -2) Container("{ c''4 b'4 c''8 } { e'4 f'4 e'8 }") >>> parentage.get(abjad.Component, -3) Voice("c''4 b'4 c''8", name='Red_Voice') >>> parentage.get(abjad.Component, -4) Note("c''4") Returns none for sufficiently negative ``n``: >>> parentage.get(abjad.Component, -5) is None True >>> parentage.get(abjad.Component, -7) is None True >>> parentage.get(abjad.Component, -99) is None True .. container:: example Works with nested voices and tuplets: >>> leaf = abjad.get.leaf(inner_red_voice, 0) >>> parentage = abjad.get.parentage(leaf) >>> leaf Note("c''4") Nonnegative ``n``: >>> parentage.get(abjad.Voice, 0) Voice("c''4 b'4 c''8", name='Red_Voice') >>> parentage.get(abjad.Voice, 1) Voice("e''8 d''8 { { c''4 b'4 c''8 } { e'4 f'4 e'8 } } d''8", name='Red_Voice') >>> parentage.get(abjad.Voice, 2) is None True >>> parentage.get(abjad.Voice, 9) is None True Negative ``n``: >>> parentage.get(abjad.Voice, -1) Voice("e''8 d''8 { { c''4 b'4 c''8 } { e'4 f'4 e'8 } } d''8", name='Red_Voice') >>> parentage.get(abjad.Voice, -2) Voice("c''4 b'4 c''8", name='Red_Voice') >>> parentage.get(abjad.Voice, -3) is None True >>> parentage.get(abjad.Voice, -99) is None True .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... result = parentage.get(abjad.Staff) ... print(f"{repr(component):30} {repr(result)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("c'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") BeforeGraceContainer("cs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("cs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("d'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Chord("<e' g'>16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("gs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("a'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("as'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Voice("e'4", name='MusicVoice') Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("e'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("f'4") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") AfterGraceContainer("fs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") Note("fs'16") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") """ if prototype is None: prototype = (_score.Component,) if not isinstance(prototype, tuple): prototype = (prototype,) if 0 <= n: i = 0 for component in self: if isinstance(component, prototype): if i == n: return component i += 1 else: i = -1 for component in reversed(self): if isinstance(component, prototype): if i == n: return component i -= 1 return None
[docs] def logical_voice(self) -> dict: r""" Gets logical voice. Gets logical voice of note: .. container:: example >>> voice = abjad.Voice("c'4 d'4 e'4 f'4", name="MusicVoice") >>> staff = abjad.Staff([voice], name="Music_Staff") >>> score = abjad.Score([staff], name="Score") >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" << \context Staff = "Music_Staff" { \context Voice = "MusicVoice" { c'4 d'4 e'4 f'4 } } >> >>> note = voice[0] >>> parentage = abjad.get.parentage(note) >>> parentage.logical_voice() {'score': "Score-'Score'", 'staff group': '', 'staff': "Staff-'Music_Staff'", 'voice': "Voice-'MusicVoice'"} .. container:: example REGRESSION. Works with grace notes (and containers): >>> voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container_1 = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container_1, voice[1]) >>> container_2 = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container_2, voice[3]) >>> abjad.show(voice) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(voice) >>> print(string) \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 e'4 \afterGrace f'4 { fs'16 } } >>> abjad.get.parentage(voice).logical_voice() {'score': '', 'staff group': '', 'staff': '', 'voice': "Voice-'MusicVoice'"} >>> abjad.get.parentage(container_1).logical_voice() {'score': '', 'staff group': '', 'staff': '', 'voice': "Voice-'MusicVoice'"} >>> abjad.get.parentage(container_1[0]).logical_voice() {'score': '', 'staff group': '', 'staff': '', 'voice': "Voice-'MusicVoice'"} >>> abjad.get.parentage(container_2).logical_voice() {'score': '', 'staff group': '', 'staff': '', 'voice': "Voice-'MusicVoice'"} >>> abjad.get.parentage(container_2[0]).logical_voice() {'score': '', 'staff group': '', 'staff': '', 'voice': "Voice-'MusicVoice'"} """ keys = ("score", "staff group", "staff", "voice") logical_voice = dict.fromkeys(keys, "") for component in self: if isinstance(component, _score.Voice): if not logical_voice["voice"]: logical_voice["voice"] = self._id_string(component) elif isinstance(component, _score.Staff): if not logical_voice["staff"]: logical_voice["staff"] = self._id_string(component) # explicit staff demands a nested voice: # if no explicit voice has been found, # create implicit voice here with random integer if not logical_voice["voice"]: logical_voice["voice"] = str(id(component)) elif isinstance(component, _score.StaffGroup): if not logical_voice["staff group"]: logical_voice["staff group"] = self._id_string(component) elif isinstance(component, _score.Score): if not logical_voice["score"]: logical_voice["score"] = self._id_string(component) logical_voice_ = dict(logical_voice) return logical_voice_
[docs] def score_index(self) -> tuple[int | str, ...]: r""" Gets score index. .. container:: example >>> staff_1 = abjad.Staff(r"\times 2/3 { c''2 b'2 a'2 }") >>> staff_2 = abjad.Staff("c'2 d'2") >>> score = abjad.Score([staff_1, staff_2]) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \new Score << \new Staff { \times 2/3 { c''2 b'2 a'2 } } \new Staff { c'2 d'2 } >> >>> for component in abjad.select.components(score): ... parentage = abjad.get.parentage(component) ... component, parentage.score_index() ... (Score("{ { 2/3 c''2 b'2 a'2 } } { c'2 d'2 }", simultaneous=True), ()) (Staff("{ 2/3 c''2 b'2 a'2 }"), (0,)) (Tuplet('3:2', "c''2 b'2 a'2"), (0, 0)) (Note("c''2"), (0, 0, 0)) (Note("b'2"), (0, 0, 1)) (Note("a'2"), (0, 0, 2)) (Staff("c'2 d'2"), (1,)) (Note("c'2"), (1, 0)) (Note("d'2"), (1, 1)) Score root sets score index to ``()``. .. container:: example REGRESSION. Works with grace notes (and containers): >>> music_voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice") >>> container = abjad.BeforeGraceContainer("cs'16") >>> abjad.attach(container, music_voice[1]) >>> container = abjad.on_beat_grace_container( ... "g'16 gs' a' as'", music_voice[2:3] ... ) >>> abjad.attach(abjad.Articulation(">"), container[0]) >>> container = abjad.AfterGraceContainer("fs'16") >>> abjad.attach(container, music_voice[3]) >>> staff = abjad.Staff([music_voice]) >>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', staff]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \context Voice = "MusicVoice" { c'4 \grace { cs'16 } d'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 \slash \voiceOne < \tweak font-size 0 \tweak transparent ##t e' g' >16 - \accent [ ( gs'16 a'16 as'16 ) ] } \context Voice = "MusicVoice" { \voiceTwo e'4 } >> \oneVoice \afterGrace f'4 { fs'16 } } } >>> for component in abjad.select.components(staff): ... parentage = abjad.get.parentage(component) ... score_index = parentage.score_index() ... print(f"{repr(component):30} {repr(score_index)}") Staff("{ c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4 }") () Voice("c'4 d'4 { { <e' g'>16 gs'16 a'16 as'16 } { e'4 } } f'4", name='MusicVoice') (0,) Note("c'4") (0, 0) BeforeGraceContainer("cs'16") (0, 0, 1, '-G') Note("cs'16") (0, 0, 1, '-G', 0) Note("d'4") (0, 1) Container("{ <e' g'>16 gs'16 a'16 as'16 } { e'4 }") (0, 2) OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") (0, 2, 0) Chord("<e' g'>16") (0, 2, 0, 0) Note("gs'16") (0, 2, 0, 1) Note("a'16") (0, 2, 0, 2) Note("as'16") (0, 2, 0, 3) Voice("e'4", name='MusicVoice') (0, 2, 1) Note("e'4") (0, 2, 1, 0) Note("f'4") (0, 3) AfterGraceContainer("fs'16") (0, 0, 3, '+G') Note("fs'16") (0, 0, 3, '+G', 0) """ result: list[int | str] = [] current = self[0] for parent in self[1:]: if isinstance(current, _score.BeforeGraceContainer): tuple_ = type(self)(current._main_leaf).score_index() list_ = list(tuple_) + ["-G"] result[0:0] = list_ elif isinstance(current, _score.AfterGraceContainer): tuple_ = type(self)(current._main_leaf).score_index() list_ = list(tuple_) + ["+G"] result[0:0] = list_ else: index = parent.index(current) result.insert(0, index) current = parent return tuple(result)