def shift_change_modal_index_modality_and_shift(): print('----- Shift Change Modal Index, modality, shift Example -----') source_expression = '{<C-Major: I> iC:4 C qD E <:IV> iF G hA <:V> ig b qf g <:VI> ie e qd ic d <:i> h@c}' t_shift = TShift.create(source_expression) print('Shift examples based on:') print_line(t_shift.source_line) print() print('Shift to modal index 1 (dorian)') target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('M:2'), modal_index=1) print_line(target_line) print_hct(target_hct) print() t_shift = TShift(target_line, target_hct) print('Shift P:4 to modal index 2 (phrygian) of MelodicMinor') target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('P:4'), range_modality_type=ModalityType.MelodicMinor, modal_index=2) print_line(target_line) print_hct(target_hct) print()
def test_book_examples(self): # Interval Creation interval = Interval(5, IntervalType.Perfect) print(interval) interval = Interval.parse("m:10") print(interval) interval = Interval.create_interval(DiatonicPitch.parse("a:3"), DiatonicPitch.parse("f#:4")) print(interval) # Interval Addition/Subtraction i1 = Interval(5, IntervalType.Perfect) i2 = Interval.parse("M:3") interval = i1 + i2 print(interval) interval = i1 - i2 print(interval) interval += i2 print(interval) interval -= i2 print(interval) # compute end and start interval = Interval(5, IntervalType.Perfect) pitch = interval.get_end_pitch(DiatonicPitch.parse("F#:5")) print(pitch) pitch = interval.get_start_pitch(DiatonicPitch.parse("C:5")) print(pitch)
def test_inversion(self): interval_strs = ['d:1', 'P:1', 'A:1', 'd:2', 'm:2', 'M:2', 'A:2', 'd:3', 'm:3', 'M:3', 'A:3', 'd:4', 'P:4', 'A:4', 'd:5', 'P:5', 'A:5', 'd:6', 'm:6', 'M:6', 'A:6', 'd:7', 'm:7', 'M:7', 'A:7', 'd:8', 'P:8', 'A:8'] answers = ['A:8', 'P:8', 'd:8', 'A:7', 'M:7', 'm:7', 'd:7', 'A:6', 'M:6', 'm:6', 'd:6', 'A:5', 'P:5', 'd:5', 'A:4', 'P:4', 'd:4', 'A:3', 'M:3', 'm:3', 'd:3', 'A:2', 'M:2', 'm:2', 'd:2', 'A:1', 'P:1', 'd:1'] intervals = [Interval.parse(s) for s in interval_strs] print('+++++') for interval, answer in zip(intervals, answers): print('{0} --> {1}'.format(interval, interval.inversion())) assert str(interval.inversion()) == answer print('-----') interval = Interval.parse('A:12') inversion = interval.inversion() print('int={0} inv={1}'.format(interval, inversion)) # Test augmented and negative intervals interval_strs = ['A:15', 'P:15', 'd:15', 'A:14', 'M:14', 'm:14', 'd:14', 'A:13', 'M:13', 'm:13', 'd:13', 'A:12', 'P:12', 'd:12', 'A:11', 'P:11', 'd:11', 'A:10', 'M:10', 'm:10', 'd:10', 'A:9', 'M:9', 'm:9', 'd:9', ] answers = ['d:1', 'P:1', 'A:1', 'd:2', 'm:2', 'M:2', 'A:2', 'd:3', 'm:3', 'M:3', 'A:3', 'd:4', 'P:4', 'A:4', 'd:5', 'P:5', 'A:5', 'd:6', 'm:6', 'M:6', 'A:6', 'd:7', 'm:7', 'M:7', 'A:7'] intervals = [Interval.parse(s) for s in interval_strs] print('+++++') for interval, answer in zip(intervals, answers): print('{0} --> {1} {2}'.format(interval, interval.inversion(), answer)) assert str(interval.inversion()) == answer print('-----') interval_strs = ['-d:1', '-P:1', '-A:1', '-d:2', '-m:2', '-M:2', '-A:2', '-d:3', '-m:3', '-M:3', '-A:3', '-d:4', '-P:4', '-A:4', '-d:5', '-P:5', '-A:5', '-d:6', '-m:6', '-M:6', '-A:6', '-d:7', '-m:7', '-M:7', '-A:7', '-d:8', '-P:8', '-A:8'] answers = ['d:8', 'P:8', 'A:8', '-A:7', '-M:7', '-m:7', '-d:7', '-A:6', '-M:6', '-m:6', '-d:6', '-A:5', '-P:5', '-d:5', '-A:4', '-P:4', '-d:4', '-A:3', '-M:3', '-m:3', '-d:3', '-A:2', '-M:2', '-m:2', '-d:2', 'd:1', 'P:1', 'A:1'] intervals = [Interval.parse(s) for s in interval_strs] print('+++++') for interval, answer in zip(intervals, answers): print('{0} --> {1}'.format(interval, interval.inversion())) assert str(interval.inversion()) == answer print('-----') interval_strs = ['-A:15', '-P:15', '-d:15', '-A:14', '-M:14', '-m:14', '-d:14', '-A:13', '-M:13', '-m:13', '-d:13', '-A:12', '-P:12', '-d:12', '-A:11', '-P:11', '-d:11', '-A:10', '-M:10', '-m:10', '-d:10', '-A:9', '-M:9', '-m:9', '-d:9', ] answers = ['A:1', 'P:1', 'd:1', 'd:2', 'm:2', 'M:2', 'A:2', 'd:3', 'm:3', 'M:3', 'A:3', 'd:4', 'P:4', 'A:4', 'd:5', 'P:5', 'A:5', 'd:6', 'm:6', 'M:6', 'A:6', 'd:7', 'm:7', 'M:7', 'A:7'] intervals = [Interval.parse(s) for s in interval_strs] print('+++++') for interval, answer in zip(intervals, answers): print('{0} --> {1} {2}'.format(interval, interval.inversion(), answer)) print('-----')
def test_interval_exception(self): i1 = Interval.parse('d:4') i2 = Interval.parse('d:3') try: i = i1 + i2 except IntervalException as e: print('caught exception ' + str(e)) assert e else: assert i is not None
def test_parse(self): interval = Interval.parse('P:5') assert str(interval) == 'P:5' assert str(Interval.parse('A:8')) == 'A:8' assert str(Interval.parse('d:8')) == 'd:8' assert str(Interval.parse('M:3')) == 'M:3' assert str(Interval.parse('m:6')) == 'm:6' assert Interval.parse('-d:1') == Interval.parse('A:1') assert Interval.parse('-A:1') == Interval.parse('d:1')
def create_instrument(inst_node, parent): low = high = '' up_down = None transpose_interval = None articulations = [] for c in inst_node: if c.tag == 'Range': for lh in c: if lh.tag == 'Low': low = lh.text elif lh.tag == 'High': high = lh.text elif c.tag == 'Transpose': updown_txt = c.get('direction') if updown_txt != 'up' and updown_txt != 'down': raise Exception( 'Illegal transpose up/down must be \'up\' or \'down\' now \'{0}\'' .format(updown_txt)) up_down = updown_txt == 'up' transpose_interval = Interval.parse(c.get('interval')) elif c.tag == 'Articulations': articulations = InstrumentCatalog._parse_articulations(c) instrument = Instrument(inst_node.get('name'), inst_node.get('key'), low, high, up_down, transpose_interval, parent) instrument.extend_articulations(articulations) return instrument
def cue_examples(): print('-------------- Cue examples --------------------------') source_expression = '{<Bb-Major: I> sBb:4 A G F qEb D sF g iA i@Bb sF <:IVMaj7> ' \ 'ir Eb sEb F G A iBb sEb:5 F i@Eb C ' \ '<:IIIMin7> sR F:5 Eb D C Bb:4 C:5 D i@Eb sC sr G:4 A G <:I> sG:5 F Eb D D C Bb:4 A ir q@G}' t_flip = TDiatonicReflection.create(source_expression, DiatonicPitch.parse('Eb:4')) print('Flip examples based on:') print_line(t_flip.source_line) print_hct(t_flip.source_hct) print() print('Flip on Eb:4 (Figure 16.12)') target_line, target_hct = t_flip.apply() print_line(target_line) print_hct(target_hct) print() print('Shift up an octave (Figure 16.13)') t_shift = TShift(target_line, target_hct, TonalInterval.parse('P:8')) final_line, final_hct = t_shift.apply() print_line(final_line) print_hct(final_hct)
def example2(): print('----- Debug meaning of modal index change and hct -----') # example tonality with modal index # Create a harmonic minor tonality of some basis root which as Mixolydian has F as the root. # The answer is Bb-HarmonicMinor F(4) source_expression = '{<C-Major: I> iC:4}' t_shift = TShift.create(source_expression) print('Shift examples based on:') print_line(t_shift.source_line) print() print('Shift to modal index 4 (Mixolydian)') # This makes C the Mixolydian of F-Major target_line, target_hct = t_shift.apply(modal_index=4) print_line(target_line) print_hct(target_hct) print() # if you wanted G Mixolydian based on C print('Shift as if moving to modal index 4 (Mixolydian) in C') target_line, target_hct = t_shift.apply( root_shift_interval=TonalInterval.parse('P:5'), modal_index=4) print_line(target_line) print_hct(target_hct) print()
def shift_modulating_sequence_example(): print('----- Shift sequence standard example (Figure 15.14) -----') source_expression = '{<C-Major: IV> sf:4 a b C:5 <:V/ii> sa:4 e:5 tc# b:4 sC#:5 <:ii> sd tc a:4 sb:4 a}' lge = LineGrammarExecutor() source_instance_line, source_instance_hct = lge.parse(source_expression) print_score('\n[0]: ', source_instance_line, source_instance_hct) t_shift = TShift.create(source_expression) target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('M:2'), range_modality_type=ModalityType.Major) print_score('\n[1]: ', target_line, target_hct) t_shift = TShift(target_line, target_hct) target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('M:2'), range_modality_type=ModalityType.Major) print_score('\n[2]: ', target_line, target_hct)
def shift_details_on_secondary_chord(): print('----- Book example of shifted secondary tonality (Figure 15.6) -----') source_expression = '{<C-Major: V/iii> iD#:4 F# G A qD#:5 B:4}' t_shift = TShift.create(source_expression, TonalInterval.parse('M:3')) target_line, target_hct = t_shift.apply(range_modality_type=ModalityType.MelodicMinor) print(t_shift.source_hct) print(target_line) print(target_hct)
def tonality_mode_change(): print('----- Book example of shifted tonality on modal not 0 (Figure 15.5) -----') source_expression = '{<D-Major(1): I> iE:4 F# G A qE B}' t_shift = TShift.create(source_expression, TonalInterval.parse('P:4')) target_line, target_hct = t_shift.apply(range_modality_type=ModalityType.MelodicMinor, modal_index=2) print(t_shift.source_hct) print(target_line) print(target_hct)
def test_whole_note_scale_inrements(self): for i in range(0, 6): intervals = ['P:1'] for count in range(0, 6): if i == count: intervals.append('d:3') else: intervals.append('M:2') # test result answer = Interval.parse('P:1') answers = [answer] iterintervals = iter(intervals) next(iterintervals) for x in iterintervals: xi = Interval.parse(x) answer += xi answers.append(answer) incrementals = ', '.join(t for t in intervals) results = ', '.join(str(t) for t in answers) print('{0} --> {1}'.format(incrementals, results)) print('end of test')
def shift_sequence_tonal_example(): print('----- Shift sequence tonal example -----') source_expression = '{<C-Major: IV> qf:4 a b C:5 <:V/ii> a:4 e:5 id C# <:ii> qd c b:4 a}' lge = LineGrammarExecutor() source_instance_line, source_instance_hct = lge.parse(source_expression) print_score('\n[0]: ', source_instance_line, source_instance_hct) t_shift = TShift.create(source_expression) target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('M:2'), range_modality_type=ModalityType.MelodicMinor) print(target_line) print(target_hct) print() t_shift = TShift(target_line, target_hct) target_line, target_hct = t_shift.apply(root_shift_interval=TonalInterval.parse('M:2'), range_modality_type=ModalityType.MelodicMinor) print(target_line) print(target_hct) print()
def test_HW_Oct_scale_inrements(self): prime = ['P:1', 'm:2', 'M:2', 'm:2', 'M:2', 'm:2', 'M:2', 'm:2', 'M:2'] for i in range(0, 4): intervals = ['P:1'] for count in range(1, 9): if 2 * i + 1 == count: intervals.append('A:1') else: intervals.append(prime[count]) # test result answer = Interval.parse('P:1') answers = [answer] iterintervals = iter(intervals) next(iterintervals) for x in iterintervals: xi = Interval.parse(x) answer += xi answers.append(answer) incrementals = ', '.join(t for t in intervals) results = ', '.join(str(t) for t in answers) print('{0} --> {1}'.format(incrementals, results)) print('end of test')
def test_reduction(self): interval_strs = ['d:1', 'P:1', 'A:1', 'M:2', 'M:3', 'P:4', 'P:5', 'M:6', 'M:7', 'd:8', 'P:8', 'A:8', 'M:9', 'M:10', 'P:11', 'P:12', 'M:13', 'M:14', 'd:15', 'P:15', 'A:15', '-d:1', '-P:1', '-A:1', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-d:8', '-P:8', '-A:8', '-M:9', '-M:10', '-P:11', '-P:12', '-M:13', '-M:14', '-d:15', '-P:15', '-A:15'] intervals = [Interval.parse(i) for i in interval_strs] answers = ['d:1', 'P:1', 'A:1', 'M:2', 'M:3', 'P:4', 'P:5', 'M:6', 'M:7', 'd:8', 'P:8', 'A:8', 'M:2', 'M:3', 'P:4', 'P:5', 'M:6', 'M:7', 'd:8', 'P:8', 'A:8', 'A:1', 'P:1', 'd:1', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-d:8', '-P:8', '-A:8', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-d:8', '-P:8', '-A:8'] for interval, answer in zip(intervals, answers): reduction = interval.reduction() print('reduce({0}) --> {1}, answer = {2}'.format(interval, reduction, answer)) assert str(reduction) == answer, 'reduce({0}) --> {1}, answer = {2}'.format(interval, reduction, answer)
def add_intervals(interval_strs): intervals = [Interval.parse(x) for x in interval_strs] result = [] for a in intervals: for b in intervals: # noinspection PyBroadException try: c = a + b print('{0} + {1} = {2}'.format(a, b, c)) result.append(c) except Exception: print('{0} + {1} = X'.format(a, b)) result.append(None) return result
def simple_shift_example(): print('----- Simple Shift Example -----') source_expression = '{<C-Major: I> iC:4 C qD E <:IV> iF G hA <:V> ig b qf g <:VI> ie e qd ic d <:I> h@c}' t_shift = TShift.create(source_expression, TonalInterval.parse('M:3')) print('Shift examples based on:') print_line(t_shift.source_line) print() print('Shift up M:3 (Figure 15.8)') target_line, target_hct = t_shift.apply() print_line(target_line) print_hct(target_hct) print() t_shift = TShift.create(source_expression, TonalInterval.parse('-m:2')) target_line, target_hct = t_shift.apply() print('Shift down m:2 (Figure 15.9)') print_line(target_line) print_hct(target_hct) print()
def __init__(self, modality_type, incremental_interval_strs): """ Constructor. :param modality_type: :param incremental_interval_strs: """ if isinstance(modality_type, int): self.__modality_type = ModalityType(modality_type) elif not isinstance(modality_type, ModalityType): raise Exception('Illegal modality type argument {0}.'.format(type(modality_type))) else: self.__modality_type = modality_type if not isinstance(incremental_interval_strs, list): raise Exception('Illegal incremental intervals argument type {0}', type(incremental_interval_strs)) self.__incremental_intervals = [Interval.parse(interval) for interval in incremental_interval_strs]
def find_modality(tones): answers = list() if len(tones) == 5: for t in [ModalityType.MajorPentatonic]: modality_spec = PentatonicModality.MODALITY_DEFINITION_MAP[t] p1 = Interval.parse('P:1') for scale_start in range(0, 5): intervals = [p1] + [ Interval.calculate_tone_interval( tones[(scale_start + i) % 5], tones[(scale_start + i + 1) % 5]) for i in range(0, len(tones)) ] if intervals == modality_spec.incremental_intervals: answers.append( PentatonicModality.create(t, (-scale_start) % len(tones))) return answers
def build_incremental_intervals(scale): from tonalmodel.diatonic_pitch import DiatonicPitch from tonalmodel.interval import Interval partition = 4 iter_scale = iter(scale) first = next(iter_scale) prior_pitch = DiatonicPitch(partition, first) prior = TONES.index(first.diatonic_letter) intervals = [Interval.parse('P:1')] for dt in iter_scale: if TONES.index(dt.diatonic_letter) - prior < 0: partition += 1 prior = TONES.index(dt.diatonic_letter) current_pitch = DiatonicPitch(partition, dt) intervals.append(Interval.create_interval(prior_pitch, current_pitch)) prior_pitch = current_pitch return intervals
def shift_change_modality(): print('----- Shift Change Modality Example -----') source_expression = '{<C-Major: I> iC:4 C qD E <:IV> iF G hA <:V> ig b qf g <:VI> ie e qd ic d <:i> h@c}' t_shift = TShift.create(source_expression, TonalInterval.parse('P:4')) print('Shift examples based on:') print_line(t_shift.source_line) print() print('Shift up P:4, modality MelodicMinor (Figure 5.10)') target_line, target_hct = t_shift.apply(range_modality_type=ModalityType.MelodicMinor) print_line(target_line) print_hct(target_hct) print() print('Shift up P:4, modality NaturalMinor (Figure 15.11)') target_line, target_hct = t_shift.apply(range_modality_type=ModalityType.NaturalMinor) print_line(target_line) print_hct(target_hct) print()
def __init__(self, domain_tonality, domain_pitch_range, root_shift_interval=None, inherent_modality_type=None, modal_index=0): """ Constructor. :param domain_tonality: :param domain_pitch_range: :param root_shift_interval: interval mapping first domain tone to first range tone. :param inherent_modality_type: alternative modality type (not modal index) :param modal_index: alternative index """ self.__root_shift_interval = Interval.parse( 'P:1') if root_shift_interval is None else root_shift_interval range_modality_type = domain_tonality.modality.modality_type if inherent_modality_type is None \ else inherent_modality_type self.__domain_tonality = domain_tonality self.__domain_pitch_range = domain_pitch_range self.__modal_index = modal_index # Take the root tone from the domain tonality, shift it by the interval, to produce new_root. # That new root has to be the modal_index-th tone in some new tonality. new_root = self.__root_shift_interval.get_end_tone( domain_tonality.root_tone) self.__tonal_function = CrossTonalityShiftTonalFunction( domain_tonality, new_root, self.__modal_index, range_modality_type) self.__range_tonality = self.tonal_function.range_tonality if domain_tonality.cardinality != self.__range_tonality.cardinality: raise Exception( 'domain and range tonalities must have same cardinality') self.__range_pitch_range = None GeneralPitchFunction.__init__(self, self._build_pitch_map())
def __init__(self, source_line, source_hct, default_root_shift_interval=None, default_modal_index=None, default_range_modality_type=None): """ Constructor :param source_line: Melodic Line being shifted :param source_hct: Harmonic Context Track being shifted :param default_root_shift_interval: Interval of shift from old to new key :param default_modal_index: modal index for key note to serve as root of key :param default_range_modality_type: specifies modality type of new key. If none, use original. Note: default_range_modality_type applies to any key in source_hct hc's. """ if default_root_shift_interval is None: default_root_shift_interval = TonalInterval.parse('P:1') self.__source_line = source_line self.__source_hct = source_hct self.__domain_pitch_range = TShift.compute_pitch_range(source_line) self.__default_root_shift_interval_interval = default_root_shift_interval self.__default_modal_index = default_modal_index self.__default_range_modality_type = default_range_modality_type self.temporal_extent = None self.keep_hct = None self.pre_extent = None self.post_extent = None self.hc_pitch_function_map = dict() self.root_shift_interval = None self.modal_index = None self.range_modality_type = None Transformation.__init__(self)
def find_modality(tones): answers = list() if len(tones) == 7: for t in [ ModalityType.Major, ModalityType.NaturalMinor, ModalityType.MelodicMinor, ModalityType.HarmonicMinor, ModalityType.HarmonicMajor ]: modality_spec = DiatonicModality.MODALITY_DEFINITION_MAP[t] p1 = Interval.parse('P:1') for scale_start in range(0, 7): intervals = [p1] + [ Interval.calculate_tone_interval( tones[(scale_start + i) % 7], tones[(scale_start + i + 1) % 7]) for i in range(0, len(tones)) ] if intervals == modality_spec.incremental_intervals: answers.append( DiatonicModality.create(t, (-scale_start) % len(tones))) return answers
def test_negation(self): assert Interval.parse('-d:1').negation() == Interval.parse('d:1') assert Interval.parse('-A:1').negation() == Interval.parse('A:1')
def test_negative_intervals(self): interval = Interval(-3, IntervalType.Major) assert interval.diatonic_distance == -2 assert interval.chromatic_distance == -4 assert str(interval) == '-M:3' print(interval) interval = Interval.parse('-P:5') assert interval.diatonic_distance == -4 assert interval.chromatic_distance == -7 assert str(interval) == '-P:5' print(interval) pitch_a = DiatonicPitch(5, 'C') pitch_b = DiatonicPitch(4, 'C') interval = Interval.create_interval(pitch_a, pitch_b) print(interval) assert interval.interval_type == IntervalType(IntervalType.Perfect) assert interval.diatonic_distance == -7 pitch_a = DiatonicPitch(5, 'C') pitch_b = DiatonicPitch(4, 'Cb') interval = Interval.create_interval(pitch_a, pitch_b) print(interval) assert interval.interval_type == IntervalType(IntervalType.Augmented) assert interval.diatonic_distance == -7 assert str(interval) == '-A:8' pitch_a = DiatonicPitch(5, 'C') pitch_b = DiatonicPitch(4, 'C#') interval = Interval.create_interval(pitch_a, pitch_b) print(interval) assert interval.interval_type == IntervalType(IntervalType.Diminished) assert interval.diatonic_distance == -7 assert str(interval) == '-d:8' pitch_a = DiatonicPitch(5, 'C') lower_pitches = [DiatonicPitch(4, i) for i in list('CDEFGAB')] answers = ['-P:8', '-m:7', '-m:6', '-P:5', '-P:4', '-m:3', '-m:2'] for (p, a) in zip(lower_pitches, answers): interval = Interval.create_interval(pitch_a, p) assert str(interval) == a lower_pitches = [DiatonicPitch(4, i) for i in 'Cb,Db,Eb,Fb,Gb,Ab,Bb'.split(',')] answers = ['-A:8', '-M:7', '-M:6', '-A:5', '-A:4', '-M:3', '-M:2'] for (p, a) in zip(lower_pitches, answers): interval = Interval.create_interval(pitch_a, p) assert str(interval) == a lower_pitches = [DiatonicPitch(4, i) for i in 'C#,D#,E#,F#,G#,A#,B#'.split(',')] answers = ['-d:8', '-d:7', '-d:6', '-d:5', '-d:4', '-d:3', '-d:2'] for (p, a) in zip(lower_pitches, answers): interval = Interval.create_interval(pitch_a, p) assert str(interval) == a interval = Interval.parse('-M:3') p = DiatonicPitch(4, 'Ab') end_p = interval.get_end_pitch(p) print(end_p) assert str(end_p) == 'Fb:4' interval = Interval.parse('-P:5') p = DiatonicPitch(4, 'D') end_p = interval.get_end_pitch(p) print(end_p) assert str(end_p) == 'G:3' interval_strs = ['-P:1', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-P:8', '-M:9', '-M:10', '-P:11', '-P:12', '-M:13', '-M:14', '-P:15'] intervals = [Interval.parse(i) for i in interval_strs] p = DiatonicPitch(4, 'G') answers = ['G:4', 'F:4', 'Eb:4', 'D:4', 'C:4', 'Bb:3', 'Ab:3', 'G:3', 'F:3', 'Eb:3', 'D:3', 'C:3', 'Bb:2', 'Ab:2', 'G:2' ] end_ps = [] for interval in intervals: end_p = interval.get_end_pitch(p) print(end_p) end_ps.append(end_p) for end_p, answer in zip(end_ps, answers): assert str(end_p) == answer # Negation tests interval_strs = ['P:1', 'M:2', 'M:3', 'P:4', 'P:5', 'M:6', 'M:7', 'P:8', 'M:9', 'M:10', 'P:11', 'P:12', 'M:13', 'M:14', 'P:15', '-P:1', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-P:8', '-M:9', '-M:10', '-P:11', '-P:12', '-M:13', '-M:14', '-P:15'] intervals = [Interval.parse(i) for i in interval_strs] count = 1 for interval, i_str in zip(intervals, interval_strs): neg_interval = interval.negation() if count <= 15: assert str(neg_interval) == ('-' if count > 1 else '') + i_str else: assert str(neg_interval) == i_str[1:] count += 1 interval_strs = ['-P:1', '-M:2', '-M:3', '-P:4', '-P:5', '-M:6', '-M:7', '-P:8', '-M:9', '-M:10', '-P:11', '-P:12', '-M:13', '-M:14', '-P:15'] intervals = [Interval.parse(i) for i in interval_strs] p = DiatonicPitch(4, 'G') answers = ['G:4', 'A:4', 'B:4', 'C:5', 'D:5', 'E:5', 'F#:5', 'G:5', 'A:5', 'B:5', 'C:6', 'D:6', 'E:6', 'F#:6', 'G:6' ] end_ps = [] print('+++++') for interval in intervals: end_p = interval.get_start_pitch(p) print(end_p) end_ps.append(end_p) print('-----') for end_p, answer in zip(end_ps, answers): assert str(end_p) == answer
def parse(expression_text): """ Parse an input string into a parts of HCExpression Args: expression_text: string input representing hc expression Returns: HC Expression parts. """ if not expression_text: raise Exception( 'Unable to parse hc expression string to completion: {0}'. format(expression_text)) m = HCExpression.HC_EXPRESSION.match(expression_text) if not m: raise Exception( 'Unable to parse hc expression string to completion: {0}'. format(expression_text)) ref_0 = m.group(HCExpression.GROUP_REFERENCE_0) ref_0_p = m.group(HCExpression.GROUP_REFERENCE_0P) key_ltr = m.group(HCExpression.GROUP_KEY_LTR) # scale_distance = m.group(HCExpression.GROUP_SCALE_DISTANCE) interval_distance = m.group(HCExpression.GROUP_INTERVAL_DISTANCE) if interval_distance: try: interval_distance = Interval.parse(interval_distance) except Exception as e: print('Exception parsing interval {0} - {1}'.format( interval_distance, e)) return modality_name = m.group(HCExpression.GROUP_MODALITY_NAME) ref_1 = m.group(HCExpression.GROUP_REFERENCE_1) ref_1_p = m.group(HCExpression.GROUP_REFERENCE_1P) modal_index = m.group(HCExpression.GROUP_MODAL_INDEX) modal_index_ref = m.group(HCExpression.GROUP_MODAL_REFERENCE) explicit_chord_degree = m.group( HCExpression.GROUP_EXPLICIT_CHORD_DEGREE) chord_degree_reff = m.group(HCExpression.GROUP_CHORD_DEGREE_REFERENCE) chord_degree_reff_p = m.group( HCExpression.GROUP_CHORD_DEGREE_REFERENCE_PAREND) chord_explicit_name = m.group(HCExpression.GROUP_CHORD_NAME) key = int(ref_0) if ref_0 else int(ref_0_p) if ref_0_p else key_ltr key_modality = int(ref_1) if ref_1 else int( ref_1_p) if ref_1_p else modality_name if modality_name else None if key_modality == 'Minor': key_modality = 'MelodicMinor' if key_modality == 'Natural': key_modality = 'NaturalMinor' if key_modality == 'Melodic': key_modality = 'MelodicMinor' if key_modality == 'Harmonic': key_modality = 'HarmonicMinor' chord_numeral = int(chord_degree_reff) if chord_degree_reff else int(chord_degree_reff_p) \ if chord_degree_reff_p else explicit_chord_degree if explicit_chord_degree else None key_modifier = interval_distance if interval_distance else None # key_modifier = interval_distance if interval_distance else int(scale_distance) if scale_distance else None modality_index = int(modal_index_ref) if modal_index_ref else str( modal_index) if modal_index else None chord_type = chord_explicit_name if chord_explicit_name else None # interited qualities if isinstance(key, int): key_modality = key if key_modality is None else key_modality # chord type inherits from chord_numeral if not none, else from key. if chord_type is None: if chord_numeral is not None: chord_type = chord_numeral if isinstance( chord_numeral, int) else None else: chord_type = key chord_numeral = key if chord_numeral is None else chord_numeral if chord_numeral is None: chord_numeral = 'i' if key_modality is None: key_modality = 'Major' logging.info('{0}, {1}, {2}, {3}'.format(key, key_modality, chord_numeral, key_modifier, modality_index, chord_type)) return key, key_modality, chord_numeral, key_modifier, modality_index, chord_type
def chromatic_reflection(): print('Chromatic_Reflection') source_expression = '{<Bb-Major: I> sBb:4 A G F iEb D sF g iA i@Bb sF <:IVMaj7> ' \ 'ir Eb sEb F G A iBb sEb:5 F i@Eb C ' \ '<:IIIMin7> sR F:5 Eb D C Bb:4 C:5 D i@Eb sC sr G:4 A G <:I> sG:5 F Eb D D C Bb:4 A ir q@G}' t_flip = TChromaticReflection.create(source_expression, DiatonicPitch.parse('G:4')) print('Flip examples based on:') print_line(t_flip.source_line) print_hct(t_flip.source_hct) print() print('Flip on G:4 ') target_line, target_hct = t_flip.apply() print_line(target_line) print_hct(target_hct) print() print('Shift up an octave (Figure 16.16)') t_shift = TShift(target_line, target_hct, TonalInterval.parse('P:8')) final_line, final_hct = t_shift.apply() print_line(final_line) print_hct(final_hct) # Center-Tone to upper t_flip = TChromaticReflection.create(source_expression, DiatonicPitch.parse('G:4'), FlipType.UpperNeighborOfPair) print('Flip examples based on:') print_line(t_flip.source_line) print_hct(t_flip.source_hct) print() print('Upper Flip on G:4 ') target_line, target_hct = t_flip.apply() print_line(target_line) print_hct(target_hct) print() print('Shift up an octave (Figure 16.17)') t_shift = TShift(target_line, target_hct, TonalInterval.parse('P:8')) final_line, final_hct = t_shift.apply() print_line(final_line) print_hct(final_hct) # Center-Tone to lower t_flip = TChromaticReflection.create(source_expression, DiatonicPitch.parse('G:4'), FlipType.LowerNeighborOfPair) print('Flip examples based on:') print_line(t_flip.source_line) print_hct(t_flip.source_hct) print() print('Lower Flip on G:4 (Figure 16.18)') target_line, target_hct = t_flip.apply() print_line(target_line) print_hct(target_hct) print() print('Shift up an octave:') t_shift = TShift(target_line, target_hct, TonalInterval.parse('P:8')) final_line, final_hct = t_shift.apply() print_line(final_line) print_hct(final_hct)