def rebuild_secondary_chord(self, secondary_chord, base_tonality): if self.secondary_shift_type == SecondaryShiftType.Standard: orig_principal_chord_template = secondary_chord.chord_template.principal_chord_template if not isinstance(orig_principal_chord_template, TertianChordTemplate): raise Exception('Secondary chord requires TertianChordTemplate for this operation.') new_scale_degree = ((orig_principal_chord_template.scale_degree - 1) + self.step_increment) % 7 + 1 new_principal_chord_template = TertianChordTemplate(orig_principal_chord_template.diatonic_basis, new_scale_degree, orig_principal_chord_template.chord_type, orig_principal_chord_template.tension_intervals, orig_principal_chord_template.inversion, orig_principal_chord_template.inversion_interval) secondary_chord_template = SecondaryChordTemplate(new_principal_chord_template, secondary_chord.chord_template.secondary_scale_degree, secondary_chord.chord_template.secondary_modality) new_secondary_chord = SecondaryChord(secondary_chord_template, base_tonality) return new_secondary_chord else: orig_template = secondary_chord.chord_template new_degree = ((orig_template.secondary_scale_degree - 1) + self.step_increment) % 7 + 1 secondary_chord_template = SecondaryChordTemplate(orig_template.principal_chord_template, new_degree, orig_template.secondary_modality) new_secondary_chord = SecondaryChord(secondary_chord_template, base_tonality) return new_secondary_chord
def test_secondary_chord(self): print('----- test_secondary_tonality -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chort_t_i = TertianChordTemplate.parse('tI') chord_i = chort_t_i.create_chord(diatonic_tonality) chord_v_ii = SecondaryChordTemplate.parse('V/ii').create_chord( diatonic_tonality) chord_vi_v = SecondaryChordTemplate.parse('vi/V').create_chord( diatonic_tonality) chord_t_ii = TertianChordTemplate.parse('tii') chord_ii = chord_t_ii.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord_i, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_v_ii, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_vi_v, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_ii, Duration(1))) TestTFlip.print_hct(hc_track) tune = [('C:5', (1, 1)), ('E:5', (1, 1)), ('E:5', (1, 1)), ('G:5', (1, 1))] line = TestTFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TDiatonicReflection(line, hc_track, cue) temporal_extent = Interval(Fraction(0), Fraction(4)) score_line, score_hct = tflip.apply(temporal_extent, cue) TestTFlip.print_notes(score_line) TestTFlip.print_hct(score_hct) notes = score_line.get_all_notes() assert len(notes) == 4 assert str(notes[0].diatonic_pitch) == 'E:5' assert str(notes[1].diatonic_pitch) == 'C#:5' assert str(notes[2].diatonic_pitch) == 'C:5' assert str(notes[3].diatonic_pitch) == 'A:4' hc_list = score_hct.hc_list() assert len(hc_list) == 4 assert hc_list[1].chord.primary_chord.chord_template.scale_degree == 7 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'C#', 'E', 'G'} assert hc_list[1].chord.primary_chord.chord_template.inversion == 3 assert hc_list[2].chord.primary_chord.chord_template.scale_degree == 7 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'C', 'F#', 'A'} assert hc_list[2].chord.primary_chord.chord_template.inversion == 3
def remap_chord(self, hc): from tonalmodel.interval import Interval as TonalInterval chord = hc.chord if not isinstance(chord, SecondaryChord): f = self.__hc_flip_map[hc] if hc in self.__hc_flip_map.keys() else \ ChromaticPitchReflectionFunction(hc.tonality, self.cue_pitch, self.domain_pitch_range) # FlipOnTonality(hc.tonality, self.cue_pitch, self.domain_pitch_range) new_chord_tones = [f.tonal_function[t[0]] for t in chord.tones] chords = ChordClassifier.classify_all_roots( new_chord_tones, f.range_tonality) if chords is not None and len(chords) > 0: return chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join( str(t.diatonic_symbol) for t in new_chord_tones))) else: if hc in self.__hc_flip_map.keys(): secondary_function = self.__hc_flip_map[hc].tonal_function else: secondary_function = self._build_secondary_flip_function( hc).tonal_function base_f = self._build_chromatic_reflection(hc) root_mapped_tonality = base_f.range_tonality mapped_denominator = TonalInterval.calculate_tone_interval( root_mapped_tonality.root_tone, secondary_function. range_tonality.root_tone).diatonic_distance + 1 # Alternatively, in the else part, we could have done: # secondary_function = f.tonal_function.create_adapted_function(secondary_tonality, secondary_tonality) # but to be consistent within the logic, we go for the reflection_tests constructiobn of # the secondary function # as embodied in tFlip._build_secondary_flip_function() new_chord_tones = [secondary_function[t[0]] for t in chord.tones] secondary_tonality = secondary_function.range_tonality chords = ChordClassifier.classify_all_roots( new_chord_tones, secondary_tonality) if chords is not None and len(chords) > 0: new_chord = chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join( str(t.diatonic_symbol) for t in new_chord_tones))) # mapped_numerator = TonalInterval.calculate_tone_interval( # new_chord.root_tone, # secondary_function.range_tonality.root_tone).diatonic_distance + 1 secondary_chord_template = SecondaryChordTemplate( new_chord.chord_template, mapped_denominator, secondary_tonality.modality.modality_type) secondary_chord = SecondaryChord(secondary_chord_template, root_mapped_tonality, secondary_function.range_tonality) return secondary_chord
def test_standards(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("G")) template = SecondaryChordTemplate.parse('V/ii') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'E, G#, B' template = SecondaryChordTemplate.parse('V/IV') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'G, B, D' diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("G")) template = SecondaryChordTemplate.parse('V/ii') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'E, G#, B' diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("Bb")) template = SecondaryChordTemplate.parse('VI/ii') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'A, C, Eb'
def test_interesting(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("F")) template = SecondaryChordTemplate.parse('V/V[NaturalMinor]') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'G, Bb, D'
def test_sample(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) template = SecondaryChordTemplate.parse('qVIPPaa/iv[Major]') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'D, G, C, F#, B#' template = SecondaryChordTemplate.parse('qIIIPPaa/V[MelodicMinor]') print(template) t_chord = template.create_chord(diatonic_tonality) print(t_chord) s = ', '.join(str(tone[0].diatonic_symbol) for tone in t_chord.tones) print(s) assert s == 'Bb, Eb, Ab, D, G#'
def test_book_examples(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("A")) template = SecondaryChordTemplate.parse('V/V') if template: print('succeeded') chord = template.create_chord(diatonic_tonality) print(chord) else: print("failed") template = SecondaryChordTemplate.parse('III/II') chord = template.create_chord(diatonic_tonality) print(chord) template = SecondaryChordTemplate.parse('CMaj7/II') chord = template.create_chord(diatonic_tonality) print(chord) template = SecondaryChordTemplate.parse('V/V[NaturalMinor]') chord = template.create_chord(diatonic_tonality) print(chord) template = SecondaryChordTemplate.parse('V/V[Phrygian]') chord = template.create_chord(diatonic_tonality) print(chord) template = SecondaryChordTemplate.parse('QVIPPAP@2/V') chord = template.create_chord(diatonic_tonality) print(chord)
def construct_secondary_chord_template(self, primary_template, secondary_numeral_str, secondary_modality): numeral = LineConstructor.NUMERAL_MAP[secondary_numeral_str] if secondary_modality is not None: if secondary_modality in LineConstructor.MODALITY_SHORT_NAME_MAP: modality = LineConstructor.MODALITY_SHORT_NAME_MAP[secondary_modality] elif secondary_modality[0] == '!': modality = ModalityType(secondary_modality[1:]) else: modality = ModalityType(secondary_modality) else: modality = None return SecondaryChordTemplate(primary_template, numeral, modality)
def test_secondary_chord(self): print('----- test_secondary_tonality -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicFoundation.get_tone("C")) chort_t_i = TertianChordTemplate.parse('tI') chord_i = chort_t_i.create_chord(diatonic_tonality) chord_v_ii = SecondaryChordTemplate.parse('V/ii').create_chord( diatonic_tonality) chord_vi_v = SecondaryChordTemplate.parse('vi/V').create_chord( diatonic_tonality) chord_t_ii = TertianChordTemplate.parse('tii') chord_ii = chord_t_ii.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord_i, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_v_ii, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_vi_v, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_ii, Duration(1))) TestTChromaticFlip.print_hct(hc_track) tune = [('C:5', (1, 1)), ('E:5', (1, 1)), ('E:5', (1, 1)), ('G:5', (1, 1))] line = TestTChromaticFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TChromaticReflection(line, hc_track, cue) score_line, score_hct = tflip.apply() TestTChromaticFlip.print_notes(score_line) TestTChromaticFlip.print_hct(score_hct)
def remap_chord(self, hc): chord = hc.chord chord_tonality = hc.tonality if not isinstance(chord, SecondaryChord): f = self.hc_flip_map[hc] if hc in self.hc_flip_map.keys() else \ DiatonicPitchReflectionFunction(hc.tonality, self.cue_pitch, self.domain_pitch_range) new_chord_tones = [f.tonal_function[t[0]] for t in chord.tones] chords = ChordClassifier.classify_all_roots( new_chord_tones, chord_tonality) if chords is not None and len(chords) > 0: return chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join(str(t) for t in new_chord_tones))) else: secondary_tonality = chord.secondary_tonality if hc in self.hc_flip_map.keys(): secondary_function = self.hc_flip_map[hc].tonal_function else: secondary_function = self._build_secondary_flip_function( hc).tonal_function # Alternatively, in the else part, we could have done: # secondary_function = f.tonal_function.create_adapted_function(secondary_tonality, secondary_tonality) # but to be consistent within the logic, we go for the reflection_tests constructiobn # of the secondary function # as embodied in tFlip._build_secondary_flip_function() new_chord_tones = [secondary_function[t[0]] for t in chord.tones] chords = ChordClassifier.classify_all_roots( new_chord_tones, secondary_tonality) if chords is not None and len(chords) > 0: new_chord = chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join(str(t) for t in new_chord_tones))) secondary_chord_template = SecondaryChordTemplate( new_chord.chord_template, chord.chord_template.secondary_scale_degree, secondary_tonality.modality.modality_type) secondary_chord = SecondaryChord(secondary_chord_template, chord_tonality) return secondary_chord
def remap_chord(self, hc, new_tonality): chord = hc.chord chord_tonality = new_tonality f, _ = self._build_shift_function(hc) if not isinstance(chord, SecondaryChord): new_chord_tones = [f.tonal_function[t[0]] for t in chord.tones] chords = ChordClassifier.classify_all_roots( new_chord_tones, chord_tonality) if chords is not None and len(chords) > 0: return chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join(t.diatonic_symbol for t in new_chord_tones))) else: new_chord_tones = [f.tonal_function[t[0]] for t in chord.tones] chords = ChordClassifier.classify_all_roots( new_chord_tones, f.range_tonality) if chords is not None and len(chords) > 0: new_chord = chords[0] else: raise Exception( 'Cannot remap/classify chord {0} based on chord.'.format( ', '.join(str(t) for t in new_chord_tones))) temp_range_tonality = Tonality.create(self.range_modality_type if self.range_modality_type is not None else hc.tonality.modality_type, self.root_shift_interval.get_end_tone(hc.tonality.diatonic_tone), self.modal_index if self.modal_index is not None else hc.tonality.modal_index) if self.root_shift_interval else \ hc.tonality secondary_chord_template = SecondaryChordTemplate( new_chord.chord_template, chord.chord_template.secondary_scale_degree, chord.secondary_tonality.modality.modality_type) secondary_chord = SecondaryChord(secondary_chord_template, temp_range_tonality) return secondary_chord
def generic_chord_template_parse(chord_txt): """ Generic text parse into chord template. Args: chord_txt: String Returns: ChordTemplate or None if fails. """ # Try parsing chord text through known chord templates. # If all fail, just return None. from harmonicmodel.secondary_chord_template import SecondaryChordTemplate, SecondaryChordException try: chord_template = SecondaryChordTemplate.parse(chord_txt) return chord_template except SecondaryChordException: pass from harmonicmodel.tertian_chord_template import TertianChordTemplate, TertianChordException try: chord_template = TertianChordTemplate.parse(chord_txt) return chord_template except TertianChordException: pass from harmonicmodel.secundal_chord_template import SecundalChordTemplate, SecundalChordException try: chord_template = SecundalChordTemplate.parse(chord_txt) return chord_template except SecundalChordException: pass from harmonicmodel.quartal_chord_template import QuartalChordTemplate try: chord_template = QuartalChordTemplate.parse(chord_txt) return chord_template except QuartalChordTemplate: return None