def list_octave_transpositions(self, pitch_carrier): r"""Lists octave transpositions of `pitch_carrier` in pitch range. .. container:: example :: >>> chord = Chord("<c' d' e'>4") >>> pitch_range = pitchtools.PitchRange.from_pitches(0, 48) >>> result = pitch_range.list_octave_transpositions(chord) :: >>> for chord in result: ... chord ... Chord("<c' d' e'>4") Chord("<c'' d'' e''>4") Chord("<c''' d''' e'''>4") Chord("<c'''' d'''' e''''>4") Returns a list of `pitch_carrier` objects. """ from abjad.tools import pitchtools from abjad.tools import scoretools if isinstance(pitch_carrier, collections.Iterable): if all(isinstance(x, (int, float)) for x in pitch_carrier): return self._list_numeric_octave_transpositions(pitch_carrier) prototype = (scoretools.Chord, pitchtools.PitchSet) if not isinstance(pitch_carrier, prototype): message = 'must be chord or pitch-set: {!r}' message = message.format(pitch_carrier) raise TypeError(message) result = [] interval = pitchtools.NumberedInterval(-12) while True: pitch_carrier_copy = copy.copy(pitch_carrier) candidate = pitchtools.transpose_pitch_carrier_by_interval( pitch_carrier_copy, interval) if candidate in self: result.append(candidate) interval -= pitchtools.NumberedInterval(12) else: break result.reverse() interval = pitchtools.NumberedInterval(0) while True: pitch_carrier_copy = copy.copy(pitch_carrier) candidate = pitchtools.transpose_pitch_carrier_by_interval( pitch_carrier_copy, interval) if candidate in self: result.append(candidate) interval += pitchtools.NumberedInterval(12) else: break return result
def spread(self): r'''Spread of interval segment. The maximum interval spanned by any combination of the intervals within a numbered interval segment. :: >>> pitchtools.IntervalSegment([1, 2, -3, 1, -2, 1]).spread NumberedInterval(4) :: >>> pitchtools.IntervalSegment([1, 1, 1, 2, -3, -2]).spread NumberedInterval(5) Returns numbered interval. ''' from abjad.tools import pitchtools current = maximum = minimum = 0 for x in self: current += float(x) if maximum < current: maximum = current if current < minimum: minimum = current return pitchtools.NumberedInterval(maximum - minimum)
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.NamedPitch.from_pitch_carrier(pitch_carrier_1) pitch_2 = pitchtools.NamedPitch.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) numbered_interval = pitchtools.NumberedInterval( numbered_interval_number, ) absolute_named_interval = numbered_interval.to_named_interval( named_interval_number) if pitch_2 < pitch_1: named_interval = -absolute_named_interval else: named_interval = absolute_named_interval return cls(named_interval)
def _transpose_pitch_carrier_by_numbered_interval(pitch_carrier, numbered_interval): mci = pitchtools.NumberedInterval(numbered_interval) if isinstance(pitch_carrier, pitchtools.Pitch): number = pitch_carrier.pitch_number + mci.semitones return type(pitch_carrier)(number) elif isinstance(pitch_carrier, numbers.Number): pitch_carrier = pitchtools.NumberedPitch(pitch_carrier) result = _transpose_pitch_carrier_by_numbered_interval( pitch_carrier, mci) return result.pitch_number elif isinstance(pitch_carrier, scoretools.Note): new_note = copy.copy(pitch_carrier) number = pitchtools.NumberedPitch( pitch_carrier.written_pitch).pitch_number number += mci.number new_pitch = pitchtools.NamedPitch(number) new_note.written_pitch = new_pitch return new_note elif isinstance(pitch_carrier, scoretools.Chord): new_chord = copy.copy(pitch_carrier) pairs = zip(new_chord.note_heads, pitch_carrier.note_heads) for new_nh, old_nh in pairs: number = \ pitchtools.NumberedPitch(old_nh.written_pitch).pitch_number number += mci.number new_pitch = pitchtools.NamedPitch(number) new_nh.written_pitch = new_pitch return new_chord else: return pitch_carrier
def __add__(self, argument): r'''Adds `argument` to numbered pitch-class. .. container:: example :: >>> pitch_class = abjad.NumberedPitchClass(9) :: >>> pitch_class + abjad.NumberedInterval(0) NumberedPitchClass(9) :: >>> pitch_class + abjad.NumberedInterval(1) NumberedPitchClass(10) :: >>> pitch_class + abjad.NumberedInterval(2) NumberedPitchClass(11) :: >>> pitch_class + abjad.NumberedInterval(3) NumberedPitchClass(0) Returns new numbered pitch-class. ''' from abjad.tools import pitchtools interval = pitchtools.NumberedInterval(argument) return type(self)(self.number + interval.number % 12)
def label_leaves_in_expr_with_numbered_interval_classes( expr, markup_direction=Up): r"""Label leaves in `expr` with numbered interval classes: :: >>> notes = scoretools.make_notes( ... [0, 25, 11, -4, -14, -13, 9, 10, 6, 5], ... [Duration(1, 8)], ... ) >>> staff = Staff(notes) >>> labeltools.label_leaves_in_expr_with_numbered_interval_classes( ... staff) .. doctest:: >>> print(format(staff)) \new Staff { c'8 ^ \markup { +1 } cs'''8 ^ \markup { -2 } b'8 ^ \markup { -3 } af8 ^ \markup { -10 } bf,8 ^ \markup { +1 } b,8 ^ \markup { +10 } a'8 ^ \markup { +1 } bf'8 ^ \markup { -4 } fs'8 ^ \markup { -1 } f'8 } :: >>> show(staff) # doctest: +SKIP Returns none. """ for note in iterate(expr).by_class(scoretools.Note): logical_voice_iterator = iterate(note).by_logical_voice_from_component( scoretools.Leaf, ) try: next(logical_voice_iterator) next_leaf = next(logical_voice_iterator) if isinstance(next_leaf, scoretools.Note): mdi = note.written_pitch - next_leaf.written_pitch mci = pitchtools.NumberedInterval(mdi) mcic = pitchtools.NumberedIntervalClass(mci) markup = markuptools.Markup(mcic, markup_direction) attach(markup, note) except StopIteration: pass
def __add__(self, expr): r'''Adds `expr` to numbered pitch-class. :: >>> pitch_class = pitchtools.NumberedPitchClass(9) >>> interval = pitchtools.NumberedInterval(4) >>> pitch_class + interval NumberedPitchClass(1) Returns new numbered pitch-class. ''' from abjad.tools import pitchtools interval = pitchtools.NumberedInterval(expr) return type(self)(self.pitch_class_number + interval.number % 12)
def __sub__(self, argument): r'''Subtracts `argument` from numbered pitch. .. container:: example >>> abjad.NumberedPitch(12) - abjad.NumberedPitch(12) NumberedInterval(0) >>> abjad.NumberedPitch(12) - abjad.NumberedPitch(13) NumberedInterval(1) >>> abjad.NumberedPitch(13) - abjad.NumberedPitch(12) NumberedInterval(-1) Returns numbered interval. ''' from abjad.tools import pitchtools if isinstance(argument, type(self)): return pitchtools.NumberedInterval.from_pitch_carriers( self, argument) interval = pitchtools.NumberedInterval(argument) interval = -interval return interval.transpose(self)
def instantiate_pitch_and_interval_test_collection(): r'''Instantiate pitch and interval test collection: :: >>> for x in pitchtools.instantiate_pitch_and_interval_test_collection(): x ... NumberedInversionEquivalentIntervalClass(1) NamedInversionEquivalentIntervalClass('+M2') NumberedInterval(1) NumberedIntervalClass(1) NamedInterval('+M2') NamedIntervalClass('+M2') NamedPitch('c') NamedPitchClass('c') NumberedPitch(1) NumberedPitchClass(1) Use to test pitch and interval interface consistency. Returns list. ''' from abjad.tools import pitchtools result = [] result.append(pitchtools.NumberedInversionEquivalentIntervalClass(1)) result.append(pitchtools.NamedInversionEquivalentIntervalClass('M2')) result.append(pitchtools.NumberedInterval(1)) result.append(pitchtools.NumberedIntervalClass(1)) result.append(pitchtools.NamedInterval('M2')) result.append(pitchtools.NamedIntervalClass('M2')) result.append(pitchtools.NamedPitch('c')) result.append(pitchtools.NamedPitchClass('c')) result.append(pitchtools.NumberedPitch(1)) result.append(pitchtools.NumberedPitchClass(1)) return result
def transpose_pitch_carrier_by_interval(pitch_carrier, interval): '''Transpose `pitch_carrier` by named `interval`: :: >>> chord = Chord("<c' e' g'>4") :: >>> pitchtools.transpose_pitch_carrier_by_interval( ... chord, '+m2') Chord("<df' f' af'>4") Transpose `pitch_carrier` by numbered `interval`: :: >>> chord = Chord("<c' e' g'>4") :: >>> pitchtools.transpose_pitch_carrier_by_interval(chord, 1) Chord("<cs' f' af'>4") Returns non-pitch-carrying input unchaged: :: >>> rest = Rest('r4') :: >>> pitchtools.transpose_pitch_carrier_by_interval(rest, 1) Rest('r4') Return `pitch_carrier`. ''' from abjad.tools import pitchtools from abjad.tools import scoretools def _transpose_pitch_by_named_interval(pitch, mdi): pitch_number = pitch.pitch_number + mdi.semitones diatonic_pitch_class_number = \ (pitch.diatonic_pitch_class_number + mdi.staff_spaces) % 7 diatonic_pitch_class_name = \ pitchtools.PitchClass._diatonic_pitch_class_number_to_diatonic_pitch_class_name[ diatonic_pitch_class_number] named_pitch = pitchtools.NamedPitch(pitch_number, diatonic_pitch_class_name) return type(pitch)(named_pitch) def _transpose_pitch_carrier_by_named_interval(pitch_carrier, named_interval): mdi = pitchtools.NamedInterval(named_interval) if isinstance(pitch_carrier, pitchtools.Pitch): return _transpose_pitch_by_named_interval(pitch_carrier, mdi) elif isinstance(pitch_carrier, scoretools.Note): new_note = copy.copy(pitch_carrier) new_pitch = _transpose_pitch_by_named_interval( pitch_carrier.written_pitch, mdi) new_note.written_pitch = new_pitch return new_note elif isinstance(pitch_carrier, scoretools.Chord): new_chord = copy.copy(pitch_carrier) for new_nh, old_nh in \ zip(new_chord.note_heads, pitch_carrier.note_heads): new_pitch = _transpose_pitch_by_named_interval( old_nh.written_pitch, mdi) new_nh.written_pitch = new_pitch return new_chord else: return pitch_carrier def _transpose_pitch_carrier_by_numbered_interval(pitch_carrier, numbered_interval): mci = pitchtools.NumberedInterval(numbered_interval) if isinstance(pitch_carrier, pitchtools.Pitch): number = pitch_carrier.pitch_number + mci.semitones return type(pitch_carrier)(number) elif isinstance(pitch_carrier, numbers.Number): pitch_carrier = pitchtools.NumberedPitch(pitch_carrier) result = _transpose_pitch_carrier_by_numbered_interval( pitch_carrier, mci) return result.pitch_number elif isinstance(pitch_carrier, scoretools.Note): new_note = copy.copy(pitch_carrier) number = pitchtools.NumberedPitch( pitch_carrier.written_pitch).pitch_number number += mci.number new_pitch = pitchtools.NamedPitch(number) new_note.written_pitch = new_pitch return new_note elif isinstance(pitch_carrier, scoretools.Chord): new_chord = copy.copy(pitch_carrier) pairs = zip(new_chord.note_heads, pitch_carrier.note_heads) for new_nh, old_nh in pairs: number = \ pitchtools.NumberedPitch(old_nh.written_pitch).pitch_number number += mci.number new_pitch = pitchtools.NamedPitch(number) new_nh.written_pitch = new_pitch return new_chord else: return pitch_carrier diatonic_types = (pitchtools.NamedInterval, str) if isinstance(interval, diatonic_types): interval = \ pitchtools.NamedInterval(interval) return _transpose_pitch_carrier_by_named_interval( pitch_carrier, interval) else: interval = \ pitchtools.NumberedInterval(interval) return _transpose_pitch_carrier_by_numbered_interval( pitch_carrier, interval)