def _analyze_incomplete_chord(expr): from abjad.tools import tonalanalysistools pitches = pitchtools.PitchSegment.from_selection(expr) npcset = pitchtools.PitchClassSet( pitches, item_class=pitchtools.NamedPitchClass) dicv = pitchtools.IntervalClassVector( items=npcset, item_class=pitchtools.NamedInversionEquivalentIntervalClass, ) # TODO: eliminate code duplication # if dicv == TonalAnalysisAgent._make_dicv('c', 'ef'): model_npcs = ['c', 'ef'] quality, extent = 'minor', 'triad' elif dicv == TonalAnalysisAgent._make_dicv('c', 'e'): model_npcs = ['c', 'e'] quality, extent = 'major', 'triad' elif dicv == TonalAnalysisAgent._make_dicv('c', 'ef', 'bff'): model_npcs = ['c', 'ef', 'bff'] quality, extent = 'diminished', 'seventh' elif dicv == TonalAnalysisAgent._make_dicv('c', 'ef', 'bf'): model_npcs = ['c', 'ef', 'bf'] quality, extent = 'minor', 'seventh' elif dicv == TonalAnalysisAgent._make_dicv('c', 'e', 'bf'): model_npcs = ['c', 'e', 'bf'] quality, extent = 'dominant', 'seventh' elif dicv == TonalAnalysisAgent._make_dicv('c', 'e', 'b'): model_npcs = ['c', 'e', 'b'] quality, extent = 'major', 'seventh' else: message = 'can not identify incomplete tertian chord.' raise ValueError(message) bass = min(pitches).named_pitch_class try: npcseg = npcset.order_by( pitchtools.PitchClassSegment( model_npcs, item_class=pitchtools.NamedPitchClass, )) except ValueError: message = 'can not identify incomplete tertian chord.' raise ValueError(message) inversion = npcseg.index(bass) root = npcseg[0] return tonalanalysistools.RootedChordClass( root, quality, extent, inversion, )
def _make_dicv(*named_pitch_classes): pitch_set = pitchtools.PitchSet(named_pitch_classes) return pitchtools.IntervalClassVector( items=pitch_set, item_class=pitchtools.NamedInversionEquivalentIntervalClass, )
def label_vertical_moments_in_expr_with_interval_class_vectors( expr, markup_direction=Down): r'''Labels interval-class vector of every vertical moment in `expr`: :: >>> score = Score([]) >>> staff = Staff("c'8 d'8 e'8 f'8") >>> score.append(staff) >>> staff = Staff(r"""\clef "alto" g4 f4""") >>> score.append(staff) >>> staff = Staff(r"""\clef "bass" c,2""") >>> score.append(staff) :: >>> labeltools.label_vertical_moments_in_expr_with_interval_class_vectors(score) .. doctest:: >>> print(format(score)) \new Score << \new Staff { c'8 d'8 _ \markup { \tiny 0010020 } e'8 f'8 _ \markup { \tiny 1000020 } } \new Staff { \clef "alto" g4 f4 _ \markup { \tiny 0100110 } } \new Staff { \clef "bass" c,2 _ \markup { \tiny 1000020 } } >> :: >>> show(score) # doctest: +SKIP Returns none. ''' for vertical_moment in iterate(expr).by_vertical_moment(): leaves = vertical_moment.leaves pitches = pitchtools.PitchSegment.from_selection(leaves) if not pitches: continue interval_class_vector = pitchtools.IntervalClassVector( pitches, item_class=pitchtools.NumberedInversionEquivalentIntervalClass, ) formatted = _format_interval_class_vector(interval_class_vector) markup = markuptools.Markup(formatted, markup_direction) attach(markup, vertical_moment.start_leaves[-1])