def list_numbered_interval_numbers_pairwise(pitch_carriers, wrap=False):
    r'''List numbered interval numbers pairwise between `pitch_carriers`:

    ::

        >>> staff = Staff("c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")

    ..  doctest::

        >>> print format(staff)
        \new Staff {
            c'8
            d'8
            e'8
            f'8
            g'8
            a'8
            b'8
            c''8
        }

    ::

        >>> pitchtools.list_numbered_interval_numbers_pairwise(
        ... staff)
        [2, 2, 1, 2, 2, 2, 1]

    ::

        >>> pitchtools.list_numbered_interval_numbers_pairwise(
        ... staff, wrap=True)
        [2, 2, 1, 2, 2, 2, 1, -12]

    ::

        >>> notes = [
        ...     Note("c'8"), Note("d'8"), Note("e'8"), Note("f'8"),
        ...     Note("g'8"), Note("a'8"), Note("b'8"), Note("c''8")]

    ::

        >>> notes.reverse()

    ::

        >>> pitchtools.list_numbered_interval_numbers_pairwise(
        ... notes)
        [-1, -2, -2, -2, -1, -2, -2]

    ::

        >>> pitchtools.list_numbered_interval_numbers_pairwise(
        ... notes, wrap=True)
        [-1, -2, -2, -2, -1, -2, -2, 12]

    When ``wrap = False`` do not return ``pitch_carriers[-1] - pitch_carriers[0]``
    as last in series.

    When ``wrap = True`` do return ``pitch_carriers[-1] - pitch_carriers[0]``
    as last in series.

    Returns list.
    '''
    from abjad.tools import pitchtools

    result = []

    if len(pitch_carriers) == 0:
        return result
    elif len(pitch_carriers) == 1:
        if pitchtools.Pitch.is_pitch_carrier(pitch_carriers[0]):
            return result
        else:
            message = 'must be pitch, not, note-head or chord.'
            raise TypeError(message)

    if wrap:
        pairs = sequencetools.iterate_sequence_pairwise_wrapped(pitch_carriers)
    else:
        pairs = sequencetools.iterate_sequence_pairwise_strict(pitch_carriers)

    for first_carrier, second_carrier in pairs:
        first_pitch = pitchtools.get_named_pitch_from_pitch_carrier(first_carrier)
        second_pitch = pitchtools.get_named_pitch_from_pitch_carrier(second_carrier)
        signed_interval = abs(pitchtools.NumberedPitch(second_pitch)) - \
            abs(pitchtools.NumberedPitch(first_pitch))
        result.append(signed_interval)

    return result
示例#2
0
    def _apply_spanners(self, leaves):

        spanner_references = {
            spannertools.Beam: None,
            spannertools.Slur: None,
        }

        first_leaf = leaves[0]
        for leaf, next_leaf in \
            sequencetools.iterate_sequence_pairwise_wrapped(leaves):

            span_events = self._get_span_events(leaf)
            for current_class, directions in span_events.iteritems():

                starting, stopping = [], []
                for direction in directions:
                    if direction is Left:
                        starting.append(Left)
                    else:
                        stopping.append(Right)

                # apply undirected events immediately, 
                # and do not maintain a reference to them
                if current_class is spannertools.Tie:
                    if next_leaf is first_leaf:
                        message = 'unterminated {} at {}.'
                        message = message.format(current_class.__name__, leaf)
                        raise Exception(message)
                    previous_tie = [
                        x for x in leaf._get_spanners() 
                        if isinstance(x, spannertools.Tie)
                        ]
                    if previous_tie:
                        previous_tie[0]._append(next_leaf)
                    else:
                        tie = spannertools.Tie()
                        attach(tie, (leaf, next_leaf))

                elif current_class is spannertools.Beam:
                    # A beam may begin and end on the same leaf
                    # but only one beam spanner may cover any given leaf,
                    # and starting events are processed before ending ones
                    for _ in starting:
                        if spanner_references[current_class] is not None:
                            message = 'already have beam.'
                            raise Exception(message)
                        else:
                            spanner_references[current_class] = current_class()
                    for _ in stopping:
                        if spanner_references[current_class] is not None:
                            spanner_references[current_class]._append(leaf)
                            spanner_references[current_class] = None

                elif current_class is spannertools.Slur:
                    # Slurs process stop events before start events,
                    # they must contain more than one leaf,
                    # but they can stop on a leaf and start on the same leaf.
                    for _ in stopping:
                        if spanner_references[current_class] is not None:
                            spanner_references[current_class]._append(leaf)
                            spanner_references[current_class] = None
                        else:
                            message = 'can not end: {}.'
                            message = message.format(current_class.__name)
                            raise Exception(message)
                    for _ in starting:
                        if spanner_references[current_class] is None:
                            spanner_references[current_class] = current_class()
                        else:
                            message = 'already have: {}.'
                            message = message.format(current_class.__name)
                            raise Exception(message)

            # append leaf to all tracked spanners,
            for current_class, instance in spanner_references.iteritems():
                if instance is not None:
                    instance._append(leaf)

        # check for unterminated spanners
        for current_class, instance in spanner_references.iteritems():
            if instance is not None:
                message = 'unterminated {}.'
                message = message.format(current_class.__name__)
                raise Exception(message)
def list_numbered_inversion_equivalent_interval_classes_pairwise(pitch_carriers, wrap=False):
    r'''List numbered inversion-equivalent interval-classes pairwise between
    `pitch_carriers`:

    ::

        >>> staff = Staff("c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")

    ..  doctest::

        >>> f(staff)
        \new Staff {
            c'8
            d'8
            e'8
            f'8
            g'8
            a'8
            b'8
            c''8
        }

    ::

        >>> result = pitchtools.list_numbered_inversion_equivalent_interval_classes_pairwise(
        ... staff, wrap=False)

    ::

        >>> for x in result: x
        ...
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)

    ::

        >>> result = pitchtools.list_numbered_inversion_equivalent_interval_classes_pairwise(
        ... staff, wrap=True)

    ::

        >>> for x in result: x
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(0)

    ::

        >>> notes = staff.select_leaves()
        >>> notes = list(reversed(notes))

    ::

        >>> result = pitchtools.list_numbered_inversion_equivalent_interval_classes_pairwise(
        ... notes, wrap=False)

    ::

        >>> for x in result: x
        ...
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)

    ::

        >>> result = pitchtools.list_numbered_inversion_equivalent_interval_classes_pairwise(
        ... notes, wrap=True)

    ::

        >>> for x in result: x
        ...
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(1)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(2)
        NumberedInversionEquivalentIntervalClass(0)

    When ``wrap=False`` do not return ``pitch_carriers[-1] - pitch_carriers[0]`` as last in series.

    When ``wrap=True`` do return ``pitch_carriers[-1] - pitch_carriers[0]`` as last in series.

    Returns list.
    '''
    from abjad.tools import pitchtools

    result = []

    if len(pitch_carriers) == 0:
        return result
    elif len(pitch_carriers) == 1:
        if pitchtools.Pitch.is_pitch_carrier(pitch_carriers[0]):
            return result
        else:
            raise TypeError('must be Abjad pitch, note, note head or chord.')

    if wrap:
        pairs = sequencetools.iterate_sequence_pairwise_wrapped(pitch_carriers)
    else:
        pairs = sequencetools.iterate_sequence_pairwise_strict(pitch_carriers)

    for first_carrier, second_carrier in pairs:
        first_pitch = pitchtools.get_named_pitch_from_pitch_carrier(first_carrier)
        second_pitch = pitchtools.get_named_pitch_from_pitch_carrier(second_carrier)
        mdi = second_pitch - first_pitch
        iecic = pitchtools.NumberedInversionEquivalentIntervalClass(mdi)
        result.append(iecic)

    return result
示例#4
0
    def _apply_spanners(self, music):

        # get local reference to methods
        _get_span_events = self._get_span_events
        _span_event_name_to_spanner_class = self._span_event_name_to_spanner_class

        # dictionary of spanner classes and instances
        all_spanners = {}

        # traverse all leaves
        leaves = music.select_leaves(allow_discontiguous_leaves=True)
        first_leaf = None
        if leaves:
            first_leaf = leaves[0]
        for leaf, next_leaf in sequencetools.iterate_sequence_pairwise_wrapped(leaves):

            span_events = _get_span_events(leaf)
            directed_events = {}

            # sort span events into directed and undirected groups
            for span_event in span_events:
                spanner_class = _span_event_name_to_spanner_class(span_event.name)

                # group directed span events by their Abjad spanner class
                if hasattr(span_event, "span_direction"):
                    if spanner_class not in directed_events:
                        directed_events[spanner_class] = [span_event]
                    else:
                        directed_events[spanner_class].append(span_event)
                    if spanner_class not in all_spanners:
                        all_spanners[spanner_class] = []

                # or apply undirected event immediately (i.e. ties, glisses)
                elif next_leaf is not first_leaf:  # so long as we are not wrapping yet
                    previous_spanners = [x for x in leaf._get_spanners() if isinstance(x, spanner_class)]
                    if previous_spanners:
                        previous_spanners[0].append(next_leaf)
                    else:
                        if hasattr(span_event, "direction") and hasattr(spanner_class, "direction"):
                            spanner = spanner_class(direction=span_event.direction)
                            attach(spanner, [leaf, next_leaf])
                        else:
                            spanner = spanner_class()
                            attach(spanner, [leaf, next_leaf])

                # otherwise throw an error
                else:
                    raise Exception("Unterminated %s at %s." % (spanner_class.__name__, leaf))

            # check for DynamicMarks, and terminate any hairpin
            dynamics = leaf._get_marks(contexttools.DynamicMark)
            if dynamics and spannertools.HairpinSpanner in all_spanners and all_spanners[spannertools.HairpinSpanner]:
                all_spanners[spannertools.HairpinSpanner][0].append(leaf)
                all_spanners[spannertools.HairpinSpanner].pop()

            # loop through directed events, handling each as necessary
            for spanner_class, events in directed_events.iteritems():

                starting_events, stopping_events = [], []
                for x in events:
                    if x.span_direction == "start":
                        starting_events.append(x)
                    else:
                        stopping_events.append(x)

                if spanner_class is spannertools.BeamSpanner:
                    # A beam may begin and end on the same leaf
                    # but only one beam spanner may cover any given leaf,
                    # and starting events are processed before ending ones
                    for event in starting_events:
                        if all_spanners[spanner_class]:
                            raise Exception("Already have beam.")
                        if hasattr(event, "direction"):
                            all_spanners[spanner_class].append(spanner_class(direction=event.direction))
                        else:
                            all_spanners[spanner_class].append(spanner_class())
                    for _ in stopping_events:
                        if all_spanners[spanner_class]:
                            all_spanners[spanner_class][0].append(leaf)
                            all_spanners[spanner_class].pop()

                elif spanner_class is spannertools.HairpinSpanner:
                    # Dynamic events can be ended many times,
                    # but only one may start on a given leaf,
                    # and the event must start and end on separate leaves.
                    # If a hairpin already exists and another starts,
                    # the pre-existant spanner is ended.
                    for _ in stopping_events:
                        if all_spanners[spanner_class]:
                            all_spanners[spanner_class][0].append(leaf)
                            all_spanners[spanner_class].pop()
                    if 1 == len(starting_events):
                        if all_spanners[spanner_class]:
                            all_spanners[spanner_class][0].append(leaf)
                            all_spanners[spanner_class].pop()
                        shape = "<"
                        event = starting_events[0]
                        if event.name == "DecrescendoEvent":
                            shape = ">"
                        if hasattr(event, "direction"):
                            all_spanners[spanner_class].append(spanner_class([], shape, direction=event.direction))
                        else:
                            all_spanners[spanner_class].append(spanner_class([], shape))
                    elif 1 < len(starting_events):
                        raise Exception("Simultaneous dynamic-span events.")

                elif spanner_class in [
                    spannertools.SlurSpanner,
                    spannertools.PhrasingSlurSpanner,
                    spannertools.TextSpanner,
                    spannertools.TrillSpanner,
                ]:
                    # These engravers process stop events before start events,
                    # they must contain more than one leaf,
                    # however, they can stop on a leaf and start on the same leaf.
                    for _ in stopping_events:
                        if all_spanners[spanner_class]:
                            all_spanners[spanner_class][0].append(leaf)
                            all_spanners[spanner_class].pop()
                        else:
                            raise Exception("Cannot end %s." % spanner_class.__name__)
                    for event in starting_events:
                        if not all_spanners[spanner_class]:
                            if hasattr(event, "direction") and hasattr(spanner_class, "direction"):
                                all_spanners[spanner_class].append(spanner_class(direction=event.direction))
                            else:
                                all_spanners[spanner_class].append(spanner_class())
                        else:
                            raise Exception("Already have %s." % spanner_class.__name__)

                elif spanner_class is spannertools.HorizontalBracketSpanner:
                    # Brackets can nest, meaning
                    # multiple brackets can begin or end on a leaf
                    # but cannot both begin and end on the same leaf
                    # and therefore a bracket cannot cover a single leaf
                    has_starting_events = bool(len(starting_events))
                    for _ in starting_events:
                        all_spanners[spanner_class].append(spanner_class())
                    if stopping_events:
                        if not has_starting_events:
                            for _ in stopping_events:
                                if all_spanners[spanner_class]:
                                    all_spanners[spanner_class][-1].append(leaf)
                                    all_spanners[spanner_class].pop()
                                else:
                                    raise Exception("Do not have that many brackets.")
                        else:
                            raise Exception("Conflicting note group events.")

            # append leaf to all tracked spanners,
            for spanner_class, instances in all_spanners.iteritems():
                for instance in instances:
                    instance.append(leaf)

        # check for unterminated spanners
        for spanner_class, instances in all_spanners.iteritems():
            if instances:
                raise Exception("Unterminated %s." % spanner_class.__name__)