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 find_tertian_chords(self): results = list() for chord_type, interval_list in TertianChordTemplate.TERTIAN_CHORD_TYPE_MAP.items( ): chord_tones = list() for interval in interval_list: chord_tones.append(interval.get_end_tone(self.root_tone)) if set(chord_tones) <= set(self.chord_tones): if self.chord_tones[0] not in chord_tones: continue ct = TertianChordType(chord_type) results.append((ct, chord_tones)) results.sort(key=lambda x: len(x[1]), reverse=True) rr = [x for x in results if len(x[1]) == len(results[0][1])] chords = list() if len(rr): for answer in rr: # inversion computed - must be a chordal tone # if self.chord_tones[0] not in answer[1]: # raise Exception('Inversion tone \'{0}\' must be a chord tone in [{1}]'.format( # self.chord_tones[0], ', '.join(v.diatonic_symbol for v in answer[1]))) inversion = answer[1].index(self.chord_tones[0]) + 1 tensions = list() remainder = set(self.chord_tones) - set(answer[1]) for r in remainder: p1 = DiatonicPitch(4, self.root_tone) p2 = DiatonicPitch( 5 if DiatonicPitch.crosses_c(self.root_tone, r) else 4, r) interval = Interval.create_interval(p1, p2) if interval.diatonic_distance < 5: # We don't want M:13 nor M:14 interval = Interval(interval.diatonic_distance + 8, interval.interval_type) tensions.append(interval) if self.tonality is not None: index = self.tonality.annotation.index(self.root_tone) \ if self.root_tone in self.tonality.annotation else None if index is None: continue # raise Exception('Root tone {0} is not in tonality {1}'.format(self.root_tone, self.tonality)) template = TertianChordTemplate(None, index + 1, answer[0], tensions, inversion) else: template = TertianChordTemplate(self.root_tone, None, answer[0], tensions, inversion) chords.append(TertianChord(template, self.tonality)) return chords
def test_inversion_pattern(self): ctxt = 'CMaj+9@(9)' template = TertianChordTemplate.parse(ctxt) if template: print('succeeded') chord = template.create_chord() print(chord) else: print("failed") # Another way to do the same from tonalmodel.interval import Interval, IntervalType from tonalmodel.diatonic_tone_cache import DiatonicToneCache template = TertianChordTemplate(DiatonicToneCache.get_cache().get_tone('C'), None, TertianChordType.to_type('Maj'), [Interval(9, IntervalType.Major)], None, Interval(9, IntervalType.Major)) chord = template.create_chord() print(chord) # reuse template = TertianChordTemplate.parse('IVMin') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicToneCache.get_cache().get_tone("Db")) chord = template.create_chord(diatonic_tonality) print(chord) diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicToneCache.get_cache().get_tone("F")) chord = template.create_chord(diatonic_tonality) print(chord) diatonic_tonality = Tonality.create(ModalityType.HarmonicMinor, DiatonicToneCache.get_cache().get_tone("C")) chord = template.create_chord(diatonic_tonality) print(chord)
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 __create_chord_on_diatonic_without_type(self, diatonic_tone): from tonalmodel.tonality import Tonality from tonalmodel.modality import ModalityType from harmonicmodel.tertian_chord_template import TertianChordTemplate diatonic_tonality = Tonality.create(ModalityType.Major, diatonic_tone) tone_scale = diatonic_tonality.annotation self.chord_basis = [] base_tone = None for i in range(0, 3): tone = tone_scale[(2 * i) % (len(tone_scale) - 1)] if i == 0: base_tone = tone pitch_a = DiatonicPitch(1, diatonic_tone) b_octave = 2 if base_tone.diatonic_index > tone.diatonic_index else 1 pitch_b = DiatonicPitch(b_octave, tone.diatonic_symbol) interval = Interval.create_interval(pitch_a, pitch_b) self.chord_basis.append(interval) self.__tones.append((tone, interval)) self.__set_inversion() self.__chord_type = TertianChordTemplate.get_chord_type( self.chord_basis)
def policy_creator(modality_type, modality_tone, tertian_chord_txt, low_pitch_txt, hi_pitch_txt): diatonic_tonality = Tonality.create(modality_type, modality_tone) chord = TertianChordTemplate.parse(tertian_chord_txt).create_chord(diatonic_tonality) hc = HarmonicContext(diatonic_tonality, chord, Duration(1, 2)) pitch_range = PitchRange(DiatonicPitch.parse(low_pitch_txt).chromatic_distance, DiatonicPitch.parse(hi_pitch_txt).chromatic_distance) return PolicyContext(hc, pitch_range)
def test_triad_generation(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) ret_types = [TertianChordType.Maj, TertianChordType.Min, TertianChordType.Min, TertianChordType.Maj, TertianChordType.Maj, TertianChordType.Min, TertianChordType.Dim] for i in range(1, 8): chord = TertianChordTemplate.get_triad(diatonic_tonality, i) print(chord) assert chord.chord_type.value == ret_types[i - 1]
def test_chord_parse(self): ltrs = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) i = 1 for t in ltrs: chord_t = TertianChordTemplate.parse('t' + t) assert chord_t.scale_degree == i, '{0} vs {1}'.format(chord_t.scale_degree, i) chord = chord_t.create_chord(diatonic_tonality) tones = chord.tones print('{0} {1}'.format(', '.join(tone[0].diatonic_symbol for tone in tones), chord.chord_type)) i += 1 ltrs = ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii'] i = 1 for t in ltrs: chord_t = TertianChordTemplate.parse('T' + t) assert chord_t.scale_degree == i, '{0} vs {1}'.format(chord_t.scale_degree, i) chord = chord_t.create_chord(diatonic_tonality) tones = chord.tones print('{0} {1}'.format(', '.join(tone[0].diatonic_symbol for tone in tones), chord.chord_type)) i += 1 tones = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'ab', 'bb', 'cb', 'db', 'eb', 'fb', 'gb', 'a#', 'b#', 'c#', 'd#', 'e#', 'f#', 'g#'] for t in tones: chord_t = TertianChordTemplate.parse(t) print(chord_t) tone = chord_t.diatonic_basis cap_t = t[0:1].upper() + (t[1:2] if len(t) == 2 else '') assert cap_t == tone.diatonic_symbol torsions = ['+9+b11', '+2', '+b2', '+#2'] for t in torsions: template = TertianChordTemplate.parse('TIII' + t) print(template) template = TertianChordTemplate.parse('IVMaj7+b9@3') assert template print(template) assert template.inversion == 3
def test_basic_setup(self): c = InstrumentCatalog.instance() violin = c.get_instrument("violin") # Add notes to the score vnote0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) vnote1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) vnote2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) vnote3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) vnote4 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) vnote5 = Note(DiatonicPitch(4, 'f'), Duration(1, 8)) # Set up a violin voice with 6 8th notes vline = Line([vnote0, vnote1, vnote2, vnote3, vnote4, vnote5]) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) hc_track = HarmonicContextTrack() diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track.append(HarmonicContext(diatonic_tonality, chord, Duration(2))) score = LiteScore(vline, hc_track, violin, tempo_seq, ts_seq) bp = score.beat_position(Position(0)) print(bp) assert bp.beat_number == 0 bp = score.beat_position(Position(5, 8)) print(bp) assert bp.measure_number == 0 assert bp.beat_number == Fraction(5, 2) assert int(bp.beat_number) == 2 assert bp.beat_number - bp.beat == Fraction(1, 2) tse = score.time_signature_sequence.floor_event(Position(5, 8)) assert tse is not None print(tse.object.beat_type(bp.beat)) assert tse.object.beat_type(bp.beat) == BeatType.Weak assert bp.beat_fraction == Fraction(1, 2) bp = score.beat_position(Position(1, 16)) print(bp) tse = score.time_signature_sequence.floor_event(Position(1, 16)) print(tse.object.beat_type(bp.beat)) assert tse.object.beat_type(bp.beat) == BeatType.Strong
def test_duplicate(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("Db")) template = TertianChordTemplate.parse('DbDom7+8') chord = template.create_chord(diatonic_tonality) print(chord) tones = chord.tones print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, ['Db', 'F', 'Ab', 'Cb', 'Db']), 'Fail #{0}, {1}'.format( 'DbDom7+8', ', '.join(tone[0].diatonic_symbol for tone in tones)) template = TertianChordTemplate.parse('DbDom7+8@4') chord = template.create_chord(diatonic_tonality) tones = chord.tones print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, ['Cb', 'Db', 'F', 'Ab', 'Db']), \ 'Fail #{0}, {1}'.format('DbDom7+8', ', '.join(tone[0].diatonic_symbol for tone in tones)) tones = chord.sorted_tones() print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, ['Db', 'F', 'Ab', 'Cb', 'Db']), \ 'Fail #{0}, {1}'.format('DbDom7+8', ', '.join(tone[0].diatonic_symbol for tone in tones))
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 test_append(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord1 = chord_t.create_chord(diatonic_tonality) chord_t = TertianChordTemplate.parse('tV') chord2 = chord_t.create_chord(diatonic_tonality) chord_t = TertianChordTemplate.parse('tVI') chord3 = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord1, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord2, Duration(1, 4))) hc_track.append( HarmonicContext(diatonic_tonality, chord3, Duration(1, 3))) assert len(hc_track) == 3 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 4) assert hc_track[Position(3, 4)].duration == Duration(1, 3) print(hc_track)
def test_inversion(self): ctype = 'ADom7' chords = {1: ['A', 'C#', 'E', 'G'], 2: ['C#', 'A', 'E', 'G'], 3: ['E', 'A', 'C#', 'G'], 4: ['G', 'A', 'C#', 'E']} diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) for i in range(1, 5): template = TertianChordTemplate.parse(ctype + '@' + str(i)) chord = template.create_chord(diatonic_tonality) tones = chord.tones print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, chords[i]), \ 'Fail #{0}, {1}'.format(ctype + '@' + str(i), ', '.join(tone[0].diatonic_symbol for tone in tones))
def __init__(self, secondary_chord_template, diatonic_tonality, secondary_tonality=None): """ Constructor. :param secondary_chord_template: SecondaryChordTemplate :param diatonic_tonality: DiatonicTonality (used in scale degree chord formation) :param secondary_tonality: Used to represent denominator tonality Note: The means for determining the secondary tonality is not necessarily clean. The standard technique involves inferring the modality from the triad built on the i-th tone of the base modality. However, the actual technique to be used can be a variable. The secondary_tonality argument is meant for cases where the standard technique does not hold up - and provides a means for specifying the exact secondary tonality when the standard technique does not apply. """ Chord.__init__(self, secondary_chord_template, diatonic_tonality) # Build the tonality upon which the primary chord is based diatonic_basis = self.diatonic_tonality.get_tone( self.chord_template.secondary_scale_degree - 1) # if no secondary modality specified? # Use diatonic_tonality + secondary scale degree. Determine the triad type of the natural triad there, and # if major, use major modality. If minor, use melodic minor modality. Otherwise flag an error. if not self.chord_template.secondary_modality: triad = TertianChordTemplate.get_triad( diatonic_tonality, self.chord_template.secondary_scale_degree) if triad: modality = ModalityType.Major if triad.chord_type.value == TertianChordType.Maj or \ triad.chord_type.value == TertianChordType.Aug else \ ModalityType.MelodicMinor if triad.chord_type.value == TertianChordType.Min or \ triad.chord_type.value == TertianChordType.Dim else None if modality is None: raise Exception( 'Illegal secondary modality for secondary chord') else: raise Exception( 'Cannot determine secondary modality for secondary chord') else: modality = self.chord_template.secondary_modality self.__secondary_tonality = Tonality.create(modality, diatonic_basis) \ if not secondary_tonality else secondary_tonality # Create the principal chord self.__primary_chord = self.chord_template.principal_chord_template.create_chord( self.secondary_tonality)
def test_append_first(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append_first( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append_first( HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) hc_track.append_first( HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) assert len(hc_track) == 3 assert hc_track[Position(0)].duration == Duration(1, 3) assert hc_track[Position(1, 3)].duration == Duration(1, 4) assert hc_track[Position(7, 12)].duration == Duration(1, 2)
def build_vst_midi_list(): """ :return: """ c = InstrumentCatalog.instance() # Add notes to the score vnote0 = Note(DiatonicPitch(4, 'a'), Duration(1, 8)) vnote1 = Note(DiatonicPitch(4, 'b'), Duration(1, 8)) vnote2 = Note(DiatonicPitch(4, 'c'), Duration(1, 8)) vnote3 = Note(DiatonicPitch(4, 'd'), Duration(1, 8)) vnote4 = Note(DiatonicPitch(4, 'e'), Duration(1, 8)) vnote5 = Note(DiatonicPitch(4, 'f'), Duration(1, 8)) # Set up a violin voice with 6 8th notes vline = Line([vnote0, vnote1, vnote2, vnote3, vnote4, vnote5]) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) hc_track = HarmonicContextTrack() diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track.append(HarmonicContext(diatonic_tonality, chord, Duration(2))) score = Score() score.tempo_sequence.add(TempoEvent(Tempo(60), Position(0))) score.time_signature_sequence.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4)), Position(0))) violin = c.get_instrument("violin") violin_instrument_voice = InstrumentVoice(violin, 1) score.add_instrument_voice(violin_instrument_voice) violin_instrument_voice.voice(0).pin(vline) return ScoreToVstMidiConverter.convert_score(score, {0: 0}), score
def test_stationary_diatonic_tone_chords(self): ltr = 'A' answers = {'Maj': ['A', 'C#', 'E'], 'MajSus2': ['A', 'B', 'E'], 'MajSus4': ['A', 'D', 'E'], 'MajSus': ['A', 'D', 'E'], 'Min': ['A', 'C', 'E'], 'Dim': ['A', 'C', 'Eb'], 'Aug': ['A', 'C#', 'E#'], 'Maj7': ['A', 'C#', 'E', 'G#'], 'Maj7Sus2': ['A', 'B', 'E', 'G#'], 'Maj7Sus4': ['A', 'D', 'E', 'G#'], 'Maj7Sus': ['A', 'D', 'E', 'G#'], 'Min7': ['A', 'C', 'E', 'G'], 'Dom7': ['A', 'C#', 'E', 'G'], 'Dom7Sus2': ['A', 'B', 'E', 'G'], 'Dom7Sus4': ['A', 'D', 'E', 'G'], 'Dom7Sus': ['A', 'D', 'E', 'G'], 'Dim7': ['A', 'C', 'Eb', 'Gb'], 'HalfDim7': ['A', 'C', 'Eb', 'G'], 'MinMaj7': ['A', 'C', 'E', 'G#'], 'AugMaj7': ['A', 'C#', 'E#', 'G#'], 'Aug7': ['A', 'C#', 'E#', 'G'], 'DimMaj7': ['A', 'C', 'Eb', 'G#'], 'Dom7Flat5': ['A', 'C#', 'Eb', 'G'], 'Maj6': ['A', 'C#', 'E', 'F#'], 'Min6': ['A', 'C', 'E', 'F#'], 'Fr': ['F##', 'A', 'B', 'D#'], 'Ger': ['F##', 'A', 'C', 'D#'], 'It': ['F', 'A', 'D#'], 'N6': ['F', 'Bb', 'D'], } diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) for ctype, value in list(answers.items()): template = TertianChordTemplate.parse(ltr + ctype) chord = template.create_chord(diatonic_tonality) tones = chord.tones print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, value), 'Fail #{0}, {1}'.format( ctype, ', '.join(tone[0].diatonic_symbol for tone in tones))
def test_remove(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) remove_item = hc_track[Position(1, 2)] hc_track.remove(remove_item) assert len(hc_track) == 2 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 3)
def test_tensions(self): c_type = 'DbDom7' answers = {'+9': ['Db', 'F', 'Ab', 'Cb', 'Eb'], '+b9': ['Db', 'F', 'Ab', 'Cb', 'Ebb'], '+#9': ['Db', 'F', 'Ab', 'Cb', 'E'], '+bb9': ['Db', 'F', 'Ab', 'Cb', 'Ebbb'], '+9+11+13': ['Db', 'F', 'Ab', 'Cb', 'Eb', 'Gb', 'Bb'], '+b9+#13': ['Db', 'F', 'Ab', 'Cb', 'Ebb', 'B'], '+6': ['Db', 'F', 'Ab', 'Cb', 'Bb'], '+8': ['Db', 'F', 'Ab', 'Cb', 'Db'], } diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("Db")) for t, value in list(answers.items()): template = TertianChordTemplate.parse(c_type + t) chord = template.create_chord(diatonic_tonality) tones = chord.tones print(', '.join(tone[0].diatonic_symbol for tone in tones)) assert TestTertianTemplateChord.verify(tones, value), \ 'Fail #{0}, {1}'.format(c_type + '+' + t, ', '.join(tone[0].diatonic_symbol for tone in tones))
def __create_chord_on_scale_degree(self): from harmonicmodel.tertian_chord_template import TertianChordTemplate root_index = self.chord_template.scale_degree - 1 tone_scale = self.diatonic_tonality.annotation self.chord_basis = [] base_tone = None for i in range(0, 3): tone = tone_scale[(root_index + 2 * i) % (len(tone_scale) - 1)] if i == 0: base_tone = tone pitch_a = DiatonicPitch(1, tone_scale[root_index].diatonic_symbol) b_octave = 2 if base_tone.diatonic_index > tone.diatonic_index else 1 pitch_b = DiatonicPitch(b_octave, tone.diatonic_symbol) interval = Interval.create_interval(pitch_a, pitch_b) self.chord_basis.append(interval) self.__tones.append((tone, interval)) self.__set_inversion() self.__chord_type = TertianChordTemplate.get_chord_type( self.chord_basis)
def test_replace(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 4))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 3))) hc_track.replace( Position(1, 2), HarmonicContext(diatonic_tonality, chord, Duration(1, 8))) assert len(hc_track) == 3 assert hc_track.duration == Duration(23, 24) # 1/2 + 1/8 + 1/3 assert hc_track[Position(0)].duration == Duration(1, 2) assert hc_track[Position(1, 2)].duration == Duration(1, 8) assert hc_track[Position(5, 8)].duration == Duration(1, 3)
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
def test_book_examples(self): template = TertianChordTemplate.parse('CN6') if template: print('succeeded') chord = template.create_chord() print(chord) else: print("failed") diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("F")) template = TertianChordTemplate.parse('IVDom7@2') chord = template.create_chord(diatonic_tonality) print(chord) template = TertianChordTemplate.parse('EbDimMaj7+9') chord = template.create_chord() print(chord) template = TertianChordTemplate.parse('EbDimMaj7+9@(9)') chord = template.create_chord() print(chord) template = TertianChordTemplate.parse('C') chord = template.create_chord() print(chord) template = TertianChordTemplate.parse('VI') chord = template.create_chord(diatonic_tonality) print(chord) # Create a template for CMajM9, with the M9 as root template = TertianChordTemplate.parse('CMaj+9@(9)') if template: print('succeeded') chord = template.create_chord() print(chord) # CMajM:9@(M:9) [D, C, E, G]
def test_simple_setup(self): print('--- test_simple_setup') line = Line() notes = [ Note(DiatonicPitch.parse('a:4'), Duration(1, 4)), Note(DiatonicPitch.parse('b:4'), Duration(1, 4)), Note(DiatonicPitch.parse('c:4'), Duration(1, 4)), Note(DiatonicPitch.parse('d:4'), Duration(1, 4)), Note(DiatonicPitch.parse('e:4'), Duration(1, 2)), Note(DiatonicPitch.parse('f:4'), Duration(1, 2)), ] location = 0 for note in notes: line.pin(note, Offset(location)) location += note.duration.duration tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60, Duration(1, 4)), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(3, Duration(1, 4), 'sww'), Position(0))) diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_t = TertianChordTemplate.parse('tIV') chord = chord_t.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 1))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord, Duration(1, 2))) c = InstrumentCatalog.instance() violin = c.get_instrument("violin") score = LiteScore(line, hc_track, violin, tempo_seq, ts_seq) constraints = [ OnBeatConstraint(notes[1], BeatType.Strong), StepSequenceConstraint(notes, [1, 1, 1, -1, -1]) ] solver = MelodicConstraintSolver.create(score, constraints) cheat = {notes[2]: DiatonicPitch.parse('E:5')} results = solver.solve(cheat) assert results is not None assert results.beat_results is not None assert results.pitch_results is not None print(len(results.beat_results)) print(len(results.pitch_results)) assert 1 == len(results.beat_results) assert 1 == len(results.pitch_results) new_line = results.apply(next(iter(results.beat_results)), next(iter(results.pitch_results))) assert new_line is not None print(new_line) all_notes = new_line.get_all_notes() assert 'C:5' == str(all_notes[0].diatonic_pitch) assert 'D:5' == str(all_notes[1].diatonic_pitch) assert 'E:5' == str(all_notes[2].diatonic_pitch) assert 'F:5' == str(all_notes[3].diatonic_pitch) assert 'E:5' == str(all_notes[4].diatonic_pitch) assert 'D:5' == str(all_notes[5].diatonic_pitch) assert Position(3, 4) == all_notes[1].get_absolute_position()
def test_hct_rebuild_imperfect_overlap(self): print('----- test_hct_rebuild_imperfect_overlap -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("D")) chord_t_i = TertianChordTemplate.parse('tI') chord_i = chord_t_i.create_chord(diatonic_tonality) chord_t_iv = TertianChordTemplate.parse('tIV') chord_iv = chord_t_iv.create_chord(diatonic_tonality) chord_t_v = TertianChordTemplate.parse('tV') chord_v = chord_t_v.create_chord(diatonic_tonality) chord_t_vi = TertianChordTemplate.parse('tVI') chord_vi = chord_t_vi.create_chord(diatonic_tonality) hc_track = HarmonicContextTrack() hc_track.append( HarmonicContext(diatonic_tonality, chord_i, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_iv, Duration(1))) hc_track.append( HarmonicContext(diatonic_tonality, chord_v, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_vi, Duration(1))) TestTFlip.print_hct(hc_track) line_str = '{<D-Major: I> hA:5 <:IV> B C# <:V> qD E <:VI> hF# qG A}' lge = LineGrammarExecutor() target_line, target_hct = lge.parse(line_str) TestTFlip.print_hct(target_hct) cue = DiatonicPitch(5, 'f#') tflip = TDiatonicReflection(target_line, target_hct, cue) temporal_extent = Interval(Fraction(1, 4), Fraction(9, 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) == 8 assert str(notes[0].diatonic_pitch) == 'A:5' assert str(notes[1].diatonic_pitch) == 'C#:5' assert str(notes[2].diatonic_pitch) == 'B:5' assert str(notes[3].diatonic_pitch) == 'A:5' assert str(notes[4].diatonic_pitch) == 'G:5' assert str(notes[5].diatonic_pitch) == 'F#:5' assert str(notes[6].diatonic_pitch) == 'G:5' assert str(notes[7].diatonic_pitch) == 'A:5' hc_list = score_hct.hc_list() assert len(hc_list) == 6 assert hc_list[0].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[0].chord.tones} == {'D', 'F#', 'A'} assert hc_list[0].chord.chord_template.inversion == 1 assert hc_list[1].chord.chord_template.scale_degree == 1 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'D', 'F#', 'A'} assert hc_list[1].chord.chord_template.inversion == 3 assert hc_list[2].chord.chord_template.scale_degree == 5 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'E', 'A', 'C#'} assert hc_list[2].chord.chord_template.inversion == 3 assert hc_list[3].chord.chord_template.scale_degree == 4 assert {t[0].diatonic_symbol for t in hc_list[3].chord.tones} == {'D', 'G', 'B'} assert hc_list[3].chord.chord_template.inversion == 3 assert hc_list[4].chord.chord_template.scale_degree == 3 assert {t[0].diatonic_symbol for t in hc_list[4].chord.tones} == {'C#', 'F#', 'A'} assert hc_list[4].chord.chord_template.inversion == 3 assert hc_list[5].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[5].chord.tones} == {'B', 'D', 'F#'} assert hc_list[5].chord.chord_template.inversion == 1
def test_mozart(self): print('----- Mozart -----') diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chort_t_i = TertianChordTemplate.parse('tI') chord_i = chort_t_i.create_chord(diatonic_tonality) chort_t_v = TertianChordTemplate.parse('tVMaj7') chord_v = chort_t_v.create_chord(diatonic_tonality) chord_t_i_1 = TertianChordTemplate.parse('tI') chord_i_1 = chord_t_i_1.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, Duration(1, 2))) hc_track.append( HarmonicContext(diatonic_tonality, chord_i_1, Duration(1, 2))) TestTFlip.print_hct(hc_track) tune = [('C:5', (1, 2)), ('E:5', (1, 4)), ('G:5', (1, 4)), ('B:4', (3, 8)), ('C:5', (1, 16)), ('D:5', (1, 16)), ('C:5', (1, 4))] line = TestTFlip.build_line(tune) cue = DiatonicPitch(5, 'd') tflip = TDiatonicReflection(line, hc_track, cue) temporal_extent = Interval(Fraction(0), Fraction(2)) 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) == 7 assert str(notes[0].diatonic_pitch) == 'E:5' assert str(notes[1].diatonic_pitch) == 'C:5' assert str(notes[2].diatonic_pitch) == 'A:4' assert str(notes[3].diatonic_pitch) == 'F:5' assert str(notes[4].diatonic_pitch) == 'E:5' assert str(notes[5].diatonic_pitch) == 'D:5' assert str(notes[6].diatonic_pitch) == 'E:5' hc_list = score_hct.hc_list() assert len(hc_list) == 3 assert hc_list[0].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[0].chord.tones} == {'E', 'A', 'C'} assert hc_list[0].chord.chord_template.inversion == 3 assert hc_list[1].chord.chord_template.scale_degree == 2 assert {t[0].diatonic_symbol for t in hc_list[1].chord.tones} == {'A', 'D', 'F', 'Bb'} assert hc_list[1].chord.chord_template.inversion == 3 assert hc_list[2].chord.chord_template.scale_degree == 6 assert {t[0].diatonic_symbol for t in hc_list[2].chord.tones} == {'E', 'A', 'C'} assert hc_list[2].chord.chord_template.inversion == 3