def from_pitch_carriers(cls, pitch_carrier_1, pitch_carrier_2): '''Makes numbered interval from `pitch_carrier_1` and `pitch_carrier_2`. :: >>> pitchtools.NumberedInterval.from_pitch_carriers( ... NamedPitch(-2), ... NamedPitch(12), ... ) NumberedInterval(14) Returns numbered interval. ''' from abjad.tools import pitchtools # get pitches pitch_1 = pitchtools.get_named_pitch_from_pitch_carrier( pitch_carrier_1) pitch_2 = pitchtools.get_named_pitch_from_pitch_carrier( pitch_carrier_2) # get difference in semitones number = abs(pitchtools.NumberedPitch(pitch_2)) - \ abs(pitchtools.NumberedPitch(pitch_1)) # change 1.0, 2.0, ... into 1, 2, ... number = mathtools.integer_equivalent_number_to_integer(number) # return numbered interval return cls(number)
def from_pitch_carriers(cls, pitch_carrier_1, pitch_carrier_2): '''Makes numbered interval from `pitch_carrier_1` and `pitch_carrier_2`. :: >>> pitchtools.NumberedInterval.from_pitch_carriers( ... NamedPitch(-2), ... NamedPitch(12), ... ) NumberedInterval(14) Returns numbered interval. ''' from abjad.tools import pitchtools # get pitches pitch_1 = pitchtools.get_named_pitch_from_pitch_carrier( pitch_carrier_1) pitch_2 = pitchtools.get_named_pitch_from_pitch_carrier( pitch_carrier_2) # get difference in semitones number = pitchtools.NumberedPitch(pitch_2).pitch_number - \ pitchtools.NumberedPitch(pitch_1).pitch_number # change 1.0, 2.0, ... into 1, 2, ... number = mathtools.integer_equivalent_number_to_integer(number) # return numbered interval return cls(number)
def from_pitch_carriers(cls, pitch_carrier_1, pitch_carrier_2): '''Calculate named interval from `pitch_carrier_1` to `pitch_carrier_2`: :: >>> pitchtools.NamedInterval.from_pitch_carriers( ... NamedPitch(-2), ... NamedPitch(12), ... ) NamedInterval('+M9') Returns named interval. ''' from abjad.tools import pitchtools pitch_1 = pitchtools.get_named_pitch_from_pitch_carrier(pitch_carrier_1) pitch_2 = pitchtools.get_named_pitch_from_pitch_carrier(pitch_carrier_2) degree_1 = pitch_1.diatonic_pitch_number degree_2 = pitch_2.diatonic_pitch_number named_interval_number = abs(degree_1 - degree_2) + 1 numbered_interval_number = abs( pitchtools.NumberedPitch(pitch_1).pitch_number - pitchtools.NumberedPitch(pitch_2).pitch_number ) absolute_named_interval = \ pitchtools.spell_numbered_interval_number( named_interval_number, numbered_interval_number) if pitch_2 < pitch_1: named_interval = -absolute_named_interval else: named_interval = absolute_named_interval return cls(named_interval)
def _get_intervals_in_subrun(subrun_source): from abjad.tools import pitchtools subrun_source = list(subrun_source) result = [0] for first, second in sequencetools.iterate_sequence_nwise(subrun_source): first_pitch = pitchtools.get_named_pitch_from_pitch_carrier(first) second_pitch = pitchtools.get_named_pitch_from_pitch_carrier(second) interval = pitchtools.NumberedPitch(second_pitch).pitch_number - \ pitchtools.NumberedPitch(first_pitch).pitch_number result.append(interval + result[-1]) result.pop(0) return result
def _get_intervals_in_subrun(subrun_source): from abjad.tools import pitchtools subrun_source = list(subrun_source) result = [0] for first, second in sequencetools.iterate_sequence_pairwise_strict( subrun_source): first_pitch = pitchtools.get_named_pitch_from_pitch_carrier(first) second_pitch = pitchtools.get_named_pitch_from_pitch_carrier(second) interval = abs(pitchtools.NumberedPitch(second_pitch)) - \ abs(pitchtools.NumberedPitch(first_pitch)) result.append(interval + result[-1]) result.pop(0) return result
def color_note_head_by_numbered_pitch_class_color_map(pitch_carrier): r'''Color `pitch_carrier` note head: :: >>> note = Note("c'4") :: >>> labeltools.color_note_head_by_numbered_pitch_class_color_map(note) Note("c'4") .. doctest:: >>> print(format(note)) \once \override NoteHead #'color = #(x11-color 'red) c'4 :: >>> show(note) # doctest: +SKIP Numbered pitch-class color map: :: 0: red 1: MediumBlue 2: orange 3: LightSlateBlue 4: ForestGreen 5: MediumOrchid 6: firebrick 7: DeepPink 8: DarkOrange 9: IndianRed 10: CadetBlue 11: SeaGreen 12: LimeGreen Numbered pitch-class color map can not be changed. Raise type error when `pitch_carrier` is not a pitch carrier. Raise extra pitch error when `pitch_carrier` carries more than 1 note head. Raise missing pitch error when `pitch_carrier` carries no note head. Return `pitch_carrier`. ''' pitch = pitchtools.get_named_pitch_from_pitch_carrier(pitch_carrier) color = _pc_number_to_color(pitch.numbered_pitch_class.pitch_class_number) if color is not None: override(pitch_carrier).note_head.color = color return pitch_carrier
def color_note_head_by_numbered_pitch_class_color_map(pitch_carrier): r'''Color `pitch_carrier` note head: :: >>> note = Note("c'4") :: >>> labeltools.color_note_head_by_numbered_pitch_class_color_map(note) Note("c'4") .. doctest:: >>> f(note) \once \override NoteHead #'color = #(x11-color 'red) c'4 :: >>> show(note) # doctest: +SKIP Numbered pitch-class color map: :: 0: red 1: MediumBlue 2: orange 3: LightSlateBlue 4: ForestGreen 5: MediumOrchid 6: firebrick 7: DeepPink 8: DarkOrange 9: IndianRed 10: CadetBlue 11: SeaGreen 12: LimeGreen Numbered pitch-class color map can not be changed. Raise type error when `pitch_carrier` is not a pitch carrier. Raise extra pitch error when `pitch_carrier` carries more than 1 note head. Raise missing pitch error when `pitch_carrier` carries no note head. Return `pitch_carrier`. ''' pitch = pitchtools.get_named_pitch_from_pitch_carrier(pitch_carrier) color = _pc_number_to_color(abs(pitch.numbered_pitch_class)) if color is not None: pitch_carrier.override.note_head.color = color return pitch_carrier
def get_numbered_pitch_class_from_pitch_carrier(pitch_carrier): '''Get numbered pitch-class from `pitch_carrier`: :: >>> note = Note("cs'4") >>> pitchtools.get_numbered_pitch_class_from_pitch_carrier(note) NumberedPitchClass(1) Raise missing pitch error on empty chords. Raise extra pitch error on many-note chords. Returns numbered pitch-class. ''' from abjad.tools import pitchtools pitch = pitchtools.get_named_pitch_from_pitch_carrier(pitch_carrier) pitch_class = pitchtools.NumberedPitchClass(pitch) return pitch_class
def _initialize_by_pitch_carrier(self, expr): from abjad.tools import pitchtools named_pitch = pitchtools.get_named_pitch_from_pitch_carrier( expr) self._initialize_by_named_pitch(named_pitch)
def list_named_pitches_in_expr(expr): '''List named pitches in `expr`: :: >>> staff = Staff("c'4 d'4 e'4 f'4") >>> beam = spannertools.Beam() >>> attach(beam, staff[:]) :: >>> for x in pitchtools.list_named_pitches_in_expr(beam): ... x ... NamedPitch("c'") NamedPitch("d'") NamedPitch("e'") NamedPitch("f'") Returns tuple. ''' from abjad.tools import pitchtools from abjad.tools import scoretools from abjad.tools import spannertools # TODO: remove try-except try: result = pitchtools.get_named_pitch_from_pitch_carrier(expr) return pitchtools.PitchSegment( items=(result,), item_class=pitchtools.NamedPitch, ) except (TypeError, ValueError): result = [] if hasattr(expr, 'written_pitches'): result.extend(expr.written_pitches) # for pitch arrays elif hasattr(expr, 'pitches'): result.extend(expr.pitches) elif isinstance(expr, spannertools.Spanner): for leaf in expr._leaves: if hasattr(leaf, 'written_pitch') and \ not isinstance(leaf, scoretools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) elif isinstance(expr, pitchtools.PitchSet): result.extend(sorted(list(expr))) elif isinstance(expr, (list, tuple, set)): for x in expr: result.extend(list_named_pitches_in_expr(x)) else: for leaf in iterate(expr).by_class(scoretools.Leaf): if hasattr(leaf, 'written_pitch') and not isinstance(leaf, scoretools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) return pitchtools.PitchSegment( items=result, item_class=pitchtools.NamedPitch, )
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
def insert_and_transpose_nested_subruns_in_pitch_class_number_list( notes, subrun_tokens, ): '''Insert and transpose nested subruns in `pitch_class_number_list` according to `subrun_tokens`: :: >>> notes = [Note(p, (1, 4)) for p in [0, 2, 7, 9, 5, 11, 4]] >>> subrun_tokens = [(0, [2, 4]), (4, [3, 1])] >>> pitchtools.insert_and_transpose_nested_subruns_in_pitch_class_number_list( ... notes, subrun_tokens) >>> t = [] >>> for x in notes: ... try: ... t.append(x.written_pitch.pitch_number) ... except AttributeError: ... t.append([y.written_pitch.pitch_number for y in x]) >>> t [0, [5, 7], 2, [4, 0, 6, 11], 7, 9, 5, [10, 6, 8], 11, [7], 4] Set `subrun_tokens` to a list of zero or more ``(index, length_list)`` pairs. For each ``(index, length_list)`` pair in *subrun_tokens* the function will read *index* mod ``len(notes)`` and insert a subrun of length ``length_list[0]`` immediately after ``notes[index]``, a subrun of length ``length_list[1]`` immediately after ``notes[index+1]``, and, in general, a subrun of ``length_list[i]`` immediately after ``notes[index+i]``, for ``i < length(length_list)``. New subruns are wrapped with lists. These wrapper lists are designed to allow inspection of the structural changes to *notes* immediately after the function returns. For this reason most calls to this function will be followed by ``notes = sequencetools.flatten_sequence(notes)``: :: >>> for note in notes: note ... Note("c'4") [Note("f'4"), Note("g'4")] Note("d'4") [Note("e'4"), Note("c'4"), Note("fs'4"), Note("b'4")] Note("g'4") Note("a'4") Note("f'4") [Note("bf'4"), Note("fs'4"), Note("af'4")] Note("b'4") [Note("g'4")] Note("e'4") This function is designed to work on a built-in Python list of notes. This function is **not** designed to work on Abjad voices, staves or other containers because the function currently implements no spanner-handling. That is, this function is designed to be used during precomposition when other, similar abstract pitch transforms may be common. Returns list of integers and / or floats. ''' from abjad.tools import scoretools from abjad.tools import pitchtools assert isinstance(notes, list) assert all(isinstance(x, scoretools.Note) for x in notes) assert isinstance(subrun_tokens, list) len_notes = len(notes) instructions = [] for subrun_token in subrun_tokens: pairs = _make_index_length_pairs(subrun_token) for anchor_index, subrun_length in pairs: anchor_note = notes[anchor_index % len_notes] anchor_pitch = pitchtools.get_named_pitch_from_pitch_carrier( anchor_note) anchor_written_duration = anchor_note.written_duration source_start_index = anchor_index + 1 source_stop_index = source_start_index + subrun_length + 1 cyclic_notes = datastructuretools.CyclicTuple(notes) subrun_source = cyclic_notes[source_start_index:source_stop_index] subrun_intervals = _get_intervals_in_subrun(subrun_source) new_notes = _make_new_notes(anchor_pitch, anchor_written_duration, subrun_intervals) instruction = (anchor_index, new_notes) instructions.append(instruction) for anchor_index, new_notes in reversed(sorted(instructions)): notes.insert(anchor_index + 1, new_notes)
def list_named_pitches_in_expr(expr): '''List named pitches in `expr`: :: >>> staff = Staff("c'4 d'4 e'4 f'4") >>> beam = spannertools.Beam() >>> attach(beam, staff[:]) :: >>> for x in pitchtools.list_named_pitches_in_expr(beam): ... x ... NamedPitch("c'") NamedPitch("d'") NamedPitch("e'") NamedPitch("f'") Returns tuple. ''' from abjad.tools import pitchtools from abjad.tools import scoretools from abjad.tools import spannertools # TODO: remove try-except try: result = pitchtools.get_named_pitch_from_pitch_carrier(expr) return pitchtools.PitchSegment( items=(result, ), item_class=pitchtools.NamedPitch, ) except (TypeError, ValueError): result = [] if hasattr(expr, 'written_pitches'): result.extend(expr.written_pitches) # for pitch arrays elif hasattr(expr, 'pitches'): result.extend(expr.pitches) elif isinstance(expr, spannertools.Spanner): for leaf in expr._leaves: if hasattr(leaf, 'written_pitch') and \ not isinstance(leaf, scoretools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) elif isinstance(expr, pitchtools.PitchSet): result.extend(sorted(list(expr))) elif isinstance(expr, (list, tuple, set)): for x in expr: result.extend(list_named_pitches_in_expr(x)) else: for leaf in iterate(expr).by_class(scoretools.Leaf): if hasattr(leaf, 'written_pitch') and not isinstance( leaf, scoretools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) return pitchtools.PitchSegment( items=result, item_class=pitchtools.NamedPitch, )
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:: >>> print(format(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: message = 'must be pitch, note, note-head or chord.' raise TypeError(message) if wrap: pairs = sequencetools.iterate_sequence_nwise( pitch_carriers, wrapped=True) else: pairs = sequencetools.iterate_sequence_nwise(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
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_nwise( pitch_carriers, wrapped=True) else: pairs = sequencetools.iterate_sequence_nwise(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 = \ pitchtools.NumberedPitch(second_pitch).pitch_number - \ pitchtools.NumberedPitch(first_pitch).pitch_number result.append(signed_interval) return result
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
def insert_and_transpose_nested_subruns_in_pitch_class_number_list(notes, subrun_indicators): '''Insert and transpose nested subruns in `pitch_class_number_list` according to `subrun_indicators`: :: >>> notes = [Note(p, (1, 4)) for p in [0, 2, 7, 9, 5, 11, 4]] >>> subrun_indicators = [(0, [2, 4]), (4, [3, 1])] >>> pitchtools.insert_and_transpose_nested_subruns_in_pitch_class_number_list( ... notes, subrun_indicators) >>> t = [] >>> for x in notes: ... try: ... t.append(x.written_pitch.pitch_number) ... except AttributeError: ... t.append([y.written_pitch.pitch_number for y in x]) >>> t [0, [5, 7], 2, [4, 0, 6, 11], 7, 9, 5, [10, 6, 8], 11, [7], 4] Set `subrun_indicators` to a list of zero or more ``(index, length_list)`` pairs. For each ``(index, length_list)`` pair in *subrun_indicators* the function will read *index* mod ``len(notes)`` and insert a subrun of length ``length_list[0]`` immediately after ``notes[index]``, a subrun of length ``length_list[1]`` immediately after ``notes[index+1]``, and, in general, a subrun of ``length_list[i]`` immediately after ``notes[index+i]``, for ``i < length(length_list)``. New subruns are wrapped with lists. These wrapper lists are designed to allow inspection of the structural changes to *notes* immediately after the function returns. For this reason most calls to this function will be followed by ``notes = sequencetools.flatten_sequence(notes)``: :: >>> for note in notes: note ... Note("c'4") [Note("f'4"), Note("g'4")] Note("d'4") [Note("e'4"), Note("c'4"), Note("fs'4"), Note("b'4")] Note("g'4") Note("a'4") Note("f'4") [Note("bf'4"), Note("fs'4"), Note("af'4")] Note("b'4") [Note("g'4")] Note("e'4") This function is designed to work on a built-in Python list of notes. This function is **not** designed to work on Abjad voices, staves or other containers because the function currently implements no spanner-handling. That is, this function is designed to be used during precomposition when other, similar abstract pitch transforms may be common. Returns list of integers and / or floats. ''' from abjad.tools import notetools from abjad.tools import pitchtools assert isinstance(notes, list) assert all(isinstance(x, notetools.Note) for x in notes) assert isinstance(subrun_indicators, list) len_notes = len(notes) instructions = [] for subrun_indicator in subrun_indicators: pairs = _make_index_length_pairs(subrun_indicator) for anchor_index, subrun_length in pairs: anchor_note = notes[anchor_index % len_notes] anchor_pitch = pitchtools.get_named_pitch_from_pitch_carrier(anchor_note) anchor_written_duration = anchor_note.written_duration source_start_index = anchor_index + 1 source_stop_index = source_start_index + subrun_length + 1 subrun_source = sequencetools.iterate_sequence_cyclically_from_start_to_stop( notes, source_start_index, source_stop_index) subrun_intervals = _get_intervals_in_subrun(subrun_source) new_notes = _make_new_notes( anchor_pitch, anchor_written_duration, subrun_intervals) instruction = (anchor_index, new_notes) instructions.append(instruction) for anchor_index, new_notes in reversed(sorted(instructions)): notes.insert(anchor_index + 1, new_notes)