Source code for auxjad.get.leaves_are_tieable

from collections.abc import Iterable
from typing import Union

import abjad


[docs]def leaves_are_tieable(leaves: Union[abjad.Selection, Iterable[abjad.Component], Iterable[abjad.LogicalTie], ], *, only_identical_pitches: bool = False, ) -> bool: r"""Returns a :obj:`bool` representing whether or not two or more input leaves have any identical pitch(es) and thus can be tied. Input argument can be a single |abjad.Selection| with multiple leaves, or an iterable with elements of type |abjad.Leaf| or child classes. Basic usage: When one or more pitches of a leave is also present in the next one, the function returns ``True``: >>> leaf1 = abjad.Note(r"c'4") >>> leaf2 = abjad.Note(r"c'4") >>> auxjad.get.leaves_are_tieable([leaf1, leaf2]) True .. note:: Auxjad automatically adds this function as an extension function to |abjad.get|. It can thus be used from either |auxjad.get|_ or |abjad.get| namespaces. Therefore, the two lines below are equivalent: >>> leaf1 = abjad.Note(r"c'4") >>> leaf2 = abjad.Note(r"c'4") >>> auxjad.get.leaves_are_tieable([leaf1, leaf2]) True >>> abjad.get.leaves_are_tieable([leaf1, leaf2]) True Durations: Durations do not affect the comparison. >>> leaf1 = abjad.Note(r"c'2.") >>> leaf2 = abjad.Note(r"c'16") >>> leaf3 = abjad.Note(r"f'''16") >>> auxjad.get.leaves_are_tieable([leaf1, leaf2]) True >>> auxjad.get.leaves_are_tieable([leaf1, leaf3]) False >>> auxjad.get.leaves_are_tieable([leaf2, leaf3]) False Chords: Handles chords. >>> chord1 = abjad.Chord(r"<c' e' g'>4") >>> chord2 = abjad.Chord(r"<c' e' g'>16") >>> chord3 = abjad.Chord(r"<f''' fs'''>16") >>> auxjad.get.leaves_are_tieable([chord1, chord2]) True >>> auxjad.get.leaves_are_tieable([chord1, chord3]) False >>> auxjad.get.leaves_are_tieable([chord2, chord3]) False ``only_identical_pitches``: By default, if any pitch in a leaf (be it either a note or chord) can be tied to the next leaf, the function returns ``True``: >>> chord1 = abjad.Chord(r"<c' e' g'>4") >>> chord2 = abjad.Chord(r"<c' e' g' bf'>4") >>> note = abjad.Note(r"c'4") >>> auxjad.get.leaves_are_tieable([chord1, chord2]) True >>> auxjad.get.leaves_are_tieable([chord2, note]) True Set the argument ``only_identical_pitches`` to ``True`` so that the function only returns ``True`` for identical pitch collections: >>> chord1 = abjad.Chord(r"<c' e' g'>4") >>> chord2 = abjad.Chord(r"<c' e' g' bf'>4") >>> note = abjad.Note(r"c'4") >>> auxjad.get.leaves_are_tieable([chord1, chord2], ... only_identical_pitches=True, ... ) False >>> auxjad.get.leaves_are_tieable([chord2, note], ... only_identical_pitches=True, ... ) False >>> chord3 = abjad.Chord(r"<c' e' g' bf'>4") >>> chord4 = abjad.Chord(r"<c' e' g' bf'>4") >>> auxjad.get.leaves_are_tieable([chord3, chord4], ... only_identical_pitches=True, ... ) True Rests: If rests are input, the return value is ``False``. It also handles multi-measure rests. >>> leaf = abjad.Note(r"c'4") >>> rest = abjad.Rest(r"r4") >>> auxjad.get.leaves_are_tieable([leaf, rest]) False Parentage: Leaves can also be part of |abjad.Container|'s or child classes. >>> container = abjad.Container(r"r4 <c' e'>4 <c' e'>2") >>> auxjad.get.leaves_are_tieable([container[1], container[2]]) True Multiple leaves: It accepts more than two leaves and will return ``True`` if all leaves can be tied sequentially (i.e. leaf one to leaf two, leaf two to leaf three, etc.): >>> leaf1 = abjad.Note(r"c'4") >>> leaf2 = abjad.Note(r"c'4") >>> leaf3 = abjad.Note(r"c'2.") >>> auxjad.get.leaves_are_tieable([leaf1, leaf2, leaf3]) True Logical ties: Accepts leaves as well as |abjad.LogicalTie|'s: >>> leaf = abjad.Note(r"c'2.") >>> staff = abjad.Staff(r"c'4 ~ c'16") >>> logical_tie = abjad.select(staff).logical_tie(0) >>> auxjad.get.leaves_are_tieable([leaf, logical_tie]) True Selections: Accepts a single |abjad.Selection| as input and will return ``True`` if all leaves can be tied sequentially (i.e. leaf one to leaf two, leaf two to leaf three, etc.): >>> staff = abjad.Staff(r"c'2 c'4. c'8") >>> auxjad.get.leaves_are_tieable(staff[:]) True >>> staff = abjad.Staff(r"c'2 c'4. d'8") >>> auxjad.get.leaves_are_tieable(staff[:]) False """ if not isinstance(leaves, (abjad.Selection, Iterable)): raise TypeError("argument must be 'abjad.Selection' or an iterable of " "'abjad.Component's or 'abjad.LogicalTie's") for leaf in leaves: if not isinstance(leaf, (abjad.Component, abjad.LogicalTie)): raise TypeError("argument must be 'abjad.Selection' or an " "iterable of 'abjad.Component's or " "'abjad.LogicalTie's") if not isinstance(only_identical_pitches, bool): raise TypeError("'only_identical_pitches' must be 'bool'") if len(leaves) < 2: raise ValueError("argument must contain two or more leaves") for index, leaf1 in enumerate(leaves[:-1]): for leaf2 in leaves[index + 1:]: if isinstance(leaf1, abjad.LogicalTie): leaf1 = leaf1[0] elif isinstance(leaf2, abjad.LogicalTie): leaf2 = leaf2[0] elif isinstance(leaf1, abjad.Rest): return False elif isinstance(leaf1, abjad.MultimeasureRest): return False elif (isinstance(leaf1, (abjad.Note, abjad.Chord)) and isinstance(leaf2, (abjad.Note, abjad.Chord))): try: pitches_1 = [leaf1.written_pitch] except AttributeError: pitches_1 = [p for p in leaf1.written_pitches] pitches_1.sort() try: pitches_2 = [leaf2.written_pitch] except AttributeError: pitches_2 = [p for p in leaf2.written_pitches] pitches_2.sort() if only_identical_pitches and pitches_1 != pitches_2: return False elif not any([p in pitches_2 for p in pitches_1]): return False else: return False # leaf1_graces = abjad.get.before_grace_container(leaf1) # leaf2_graces = abjad.get.before_grace_container(leaf2) # if not isinstance(leaf1_graces, type(leaf2_graces)): # return False return True