def test_across_tonalities(self): logging.debug('Start test_across_tonalities.') lower_policy_context_1 = TestRelativeDiatonicConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_policy_context_2 = TestRelativeDiatonicConstraint.policy_creator( ModalityType.Major, DiatonicTone('Ab'), 'tI', 'C:2', 'C:8') upper_note_1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) upper_note_2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context_1, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context_2) p_map = dict([(upper_note_1, lower_note_1), (upper_note_2, lower_note_2)]) policy = RelativeDiatonicConstraint(upper_note_1, upper_note_2, Interval(3, IntervalType.Minor), Interval(3, IntervalType.Major)) v_result = policy.values(p_map, upper_note_2) for note in v_result: logging.debug(note) pitches = [note.diatonic_pitch for note in v_result] assert {str(p) for p in pitches} == {'Eb:5', 'F:5', 'G:5', 'Ab:5'} logging.debug('End test_across_tonalities.')
def test_pentatonic_tonal_function(self): t_domain = Tonality.create(ModalityType.MajorPentatonic, DiatonicTone('C')) interval = Interval(3, IntervalType.Major) f = CrossTonalityShiftTonalFunction.create_shift(t_domain, interval) # C, D, E, G. A ==> E, F#, G#, B, C# assert 'E' == f['C'].diatonic_symbol assert 'F#' == f['D'].diatonic_symbol assert 'G#' == f['E'].diatonic_symbol assert 'B' == f['G'].diatonic_symbol assert 'C#' == f['A'].diatonic_symbol assert 'A' == f['F'].diatonic_symbol assert 'D#' == f['B'].diatonic_symbol assert 'A#' == f['F#'].diatonic_symbol assert 'D##' == f['B#'].diatonic_symbol assert 'Ab' == f['Fb'].diatonic_symbol assert 'D' == f['Bb'].diatonic_symbol t_range = Tonality.create(ModalityType.MajorPentatonic, interval.get_end_tone(DiatonicTone('C'))) f = CrossTonalityShiftTonalFunction(t_domain, t_range.annotation[2], 2) # C, D, E, G. A ==> G#, B, C#, E, F# assert 'G#' == f['C'].diatonic_symbol assert 'B' == f['D'].diatonic_symbol assert 'C#' == f['E'].diatonic_symbol assert 'E' == f['G'].diatonic_symbol assert 'F#' == f['A'].diatonic_symbol TestCrossTonalityShiftTonalFunction.print_function(f)
def test_is_chordal(self): logging.debug('Start test_is_chordal') upper_context_note = Note(DiatonicPitch.parse('F:5'), Duration(1, 4)) lower_policy_context = TestChordalToneConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note = ContextualNote(lower_policy_context) parameter_map = dict([(upper_context_note, lower_context_note)]) policy = ChordalPitchConstraint(upper_context_note) v_result = policy.values(parameter_map, upper_context_note) results = {DiatonicTone('D'), DiatonicTone('F#'), DiatonicTone('A')} for note in v_result: print('test_is_chordal; note = {0}'.format(note)) tone = note.diatonic_pitch.diatonic_tone octave = note.diatonic_pitch.octave assert tone in results assert octave in range(2, 9) assert len(v_result) == 6 * 3 for note in v_result: parameter_map[upper_context_note].note = note assert policy.verify(parameter_map) is True logging.debug('End test_is_chordal')
def test_setting_values(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('C')) t_range = Tonality.create(ModalityType.MajorPentatonic, DiatonicTone('A')) # A, B, C#, E, F# # default map between 2 tonalities of unequal cardinality - empty p = { 'C': 'A', 'D': 'A', 'E': 'B', 'F': 'C#', 'G': 'C#', 'A': 'E', 'B': 'F#' } f = TonalFunction(t_domain, t_range, p) assert DiatonicToneCache.get_tone('A') == f['C'] assert DiatonicToneCache.get_tone('A') == f['D'] assert DiatonicToneCache.get_tone('B') == f['E'] assert DiatonicToneCache.get_tone('C#') == f['F'] assert DiatonicToneCache.get_tone('C#') == f['G'] assert DiatonicToneCache.get_tone('E') == f['A'] assert DiatonicToneCache.get_tone('F#') == f['B'] assert [0, 0, 1, 2, 2, 3, 4] == f.extract_template().tonal_order f['C'] = 'B' f['D'] = 'A' f['E'] = 'C#' f['F'] = 'C#' f['G'] = 'F#' f['A'] = 'A' f['B'] = 'E' # del f['D'] # assert f['D'] is None assert [1, 0, 2, 2, 4, 0, 3] == f.extract_template().tonal_order f['C#'] = 'B#' f['Db'] = 'Ab' f['A#'] = 'Eb' assert DiatonicToneCache.get_tone('B#') == f['C#'] assert DiatonicToneCache.get_tone('Ab') == f['Db'] assert DiatonicToneCache.get_tone('Eb') == f['A#'] del f['Db']
def test_diatonic_modal_indexed_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('C')) i = Interval(2, IntervalType.Major) r = PitchRange.create('E:3', 'E:7') f = CrossTonalityShiftPitchFunction(t_domain, r, i, modal_index=4) print('f={0}'.format(f)) TestCrossTonalityShiftPitchFunction.print_map('test_diatonic_function', f) t = f.tonal_function print(t) # test diatonic maps assert 'D:4' == str(f['C:4']) assert 'E:4' == str(f['D:4']) assert 'F#:4' == str(f['E:4']) assert 'G:4' == str(f['F:4']) assert 'A:4' == str(f['G:4']) assert 'B:4' == str(f['A:4']) assert 'C:5' == str(f['B:4']) assert 'D:5' == str(f['C:5']) assert 'M:2' == str(f.root_shift_interval)
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 test_basic_policy(self): logging.debug('Start test_basic_policy') lower_policy_context = TestRelativeScalarStepConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:5'), Duration(1, 8))) lower_note_2 = ContextualNote(lower_policy_context) p_map = dict([(note1, lower_note_1), (note2, lower_note_2)]) # F#:5 --> G Major two below and 3 above policy = RelativeScalarStepConstraint(note1, note2, -2, 3) v_result = policy.values(p_map, note2) pitches = [n.diatonic_pitch for n in v_result] assert len(pitches) == 6 for s in ['D:5', 'E:5', 'F#:5', 'G:5', 'A:5', 'B:5']: assert DiatonicPitch.parse(s) in pitches for note in v_result: logging.debug(note) # Check verify for each answer for n in v_result: lower_note_2.note = n assert policy.verify(p_map) logging.debug('End test_basic_policy')
def test_forward_with_extension(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) cycles = [['E', 'G#', 'A', 'C#'], ('F#', 'D#')] extension = dict() extension['D'] = 'F' extension['F'] = 'G' permutation_function = TonalityPermutationFunction.create( t_domain, cycles, extension) r = PitchRange.create('E:3', 'E:7') f = TonalityPitchFunction(permutation_function, ('E:4', 'E:5'), r, False) TestTonalityPitchFunction.print_map('test_forward_with_extension', f) assert 'G#:5' == str(f['E:4']) assert 'G:5' == str(f['F:4']) assert 'D#:6' == str(f['F#:4']) assert 'A:5' == str(f['G#:4']) assert 'C#:6' == str(f['A:4']) assert 'B:5' == str(f['B:4']) assert 'E:5' == str(f['C#:5']) assert 'E:5' == str(f['B##:4']) assert 'F:5' == str(f['D:5']) assert 'F:5' == str(f['C##:5']) assert 'F#:5' == str(f['D#:5'])
def test_simple_tonality_permutation_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('A')) cycles = [['C#', 'D'], ['E', 'G#']] p = TonalityPermutationFunction.create(t_domain, cycles) assert DiatonicToneCache.get_tone('C#') in p.domain assert DiatonicToneCache.get_tone('D') in p.domain assert DiatonicToneCache.get_tone('E') in p.domain assert DiatonicToneCache.get_tone('G#') in p.domain assert DiatonicToneCache.get_tone('D') == p['C#'] assert DiatonicToneCache.get_tone('C#') == p['D'] assert DiatonicToneCache.get_tone('E') == p['G#'] assert DiatonicToneCache.get_tone('G#') == p['E'] f = TonalityPermutationFunction(TonalityPermutation(t_domain, cycles)) assert DiatonicToneCache.get_tone('C#') in f.domain assert DiatonicToneCache.get_tone('D') in f.domain assert DiatonicToneCache.get_tone('E') in f.domain assert DiatonicToneCache.get_tone('G#') in f.domain assert DiatonicToneCache.get_tone('D') == f['C#'] assert DiatonicToneCache.get_tone('C#') == f['D'] assert DiatonicToneCache.get_tone('E') == f['G#'] assert DiatonicToneCache.get_tone('G#') == f['E']
def test_centered_odd_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) r = PitchRange.create('E:3', 'E:7') f = DiatonicPitchReflectionFunction( t_domain, DiatonicPitch(4, DiatonicToneCache.get_tone('A')), r, FlipType.CenterTone) print('f={0}'.format(f)) TestFlipOnTonality.print_map('test_simple_pitch_function', f) t = f.tonal_function assert 'E' == t['D#'].diatonic_symbol assert 'F#' == t['C#'].diatonic_symbol assert 'G#' == t['B'].diatonic_symbol assert 'A' == t['A'].diatonic_symbol assert 'B' == t['G#'].diatonic_symbol assert 'C#' == t['F#'].diatonic_symbol assert 'D#' == t['E'].diatonic_symbol assert 'D#:5' == str(f['E:4']) assert 'C#:5' == str(f['F#:4']) assert 'A:4' == str(f['A:4']) assert 'G#:4' == str(f['B:4']) assert 'F#:4' == str(f['C#:5']) assert 'E:4' == str(f['D#:5'])
def test_non_centered_even_function(self): t_domain = Tonality.create(ModalityType.WholeTone, DiatonicTone('C')) r = PitchRange.create('E:3', 'E:7') f = DiatonicPitchReflectionFunction( t_domain, DiatonicPitch(4, DiatonicToneCache.get_tone('G#')), r, FlipType.UpperNeighborOfPair) TestFlipOnTonality.print_map('test_non_centered_even_function', f) t = f.tonal_function assert 'C' == t['D'].diatonic_symbol assert 'D' == t['C'].diatonic_symbol assert 'E' == t['A#'].diatonic_symbol assert 'F#' == t['G#'].diatonic_symbol assert 'G#' == t['F#'].diatonic_symbol assert 'A#' == t['E'].diatonic_symbol assert 'C:4' == str(f['D:5']) assert 'D:4' == str(f['C:5']) assert 'E:4' == str(f['A#:4']) assert 'F#:4' == str(f['G#:4']) assert 'G#:4' == str(f['F#:4']) assert 'A#:4' == str(f['E:4']) assert 'C:5' == str(f['D:4'])
def test_reversal_on_policy(self): logging.debug('Start test_reversal_on_policy') lower_policy_context = TestRelativeScalarStepConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('D:5'), Duration(1, 8)) lower_note_1 = ContextualNote(lower_policy_context) lower_note_2 = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('C:5'), Duration(1, 8))) p_map = dict([(note1, lower_note_1), (note2, lower_note_2)]) # F#:5 --> G Major two below and 3 above policy = RelativeScalarStepConstraint(note1, note2, -2, 3) result = policy.values(p_map, note1) pitches = [n.diatonic_pitch for n in result] for pitch in pitches: logging.debug(pitch) # Check that each returned verifies for n in result: lower_note_1.note = n assert policy.verify(p_map) logging.debug('End test_reversal_on_policy')
def test_book_examples(self): template = QuartalChordTemplate.parse('GPerAug') if template: print('succeeded') chord = template.create_chord() print(chord) else: print("failed") diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("Bb")) template = QuartalChordTemplate.parse('IIPerPer@2') chord = template.create_chord(diatonic_tonality) print(chord) template = QuartalChordTemplate.parse('GPPAAPP') chord = template.create_chord() print(chord) template = QuartalChordTemplate.parse('IIIPAPAA@3') chord = template.create_chord(diatonic_tonality) print(chord) template = QuartalChordTemplate.parse('C') chord = template.create_chord() print(chord) template = QuartalChordTemplate.parse('IV') chord = template.create_chord(diatonic_tonality) print(chord)
def test_simple_fixed_pitch(self): logging.debug('Start test_simple_fixed_pitch') note = Note(DiatonicPitch.parse("C:5"), Duration(1, 4)) select_notes = {'A:5', 'C:4', 'Eb:2', 'F#:6'} constraint = FixedPitchSelectSetConstraint( note, {DiatonicPitch.parse(p) for p in select_notes}) policy_context = TestFixedPitchSelectSetConstraint.policy_creator( ModalityType.Major, DiatonicTone('C'), 'tIV', 'C:2', 'C:8') lower_contextual = ContextualNote(policy_context) p_map = PMap() p_map[note] = lower_contextual v_results = constraint.values(p_map, note) assert v_results is not None assert len(v_results) == len(select_notes) for result in v_results: print(str(result)) assert select_notes == {str(n.diatonic_pitch) for n in v_results} assert not constraint.verify(p_map) lower_contextual.note = Note(DiatonicPitch.parse('Eb:2'), Duration(1, 4)) assert constraint.verify(p_map)
def test_is_not_equal(self): logging.debug('Start test_is_not_equal') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) lower_policy_context = TestNotEqualPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note_a = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:6'), Duration(1, 8))) p_map = PMap() p_map[note1] = lower_context_note_a other_source = [] for tone in ['B:5', 'D:5', 'E:5']: n = Note(DiatonicPitch.parse(tone), Duration(1, 8)) lower_context_note = ContextualNote(lower_policy_context) p_map[n] = lower_context_note other_source.append(n) params = list([note1]) params.extend(other_source) policy = NotEqualPitchConstraint(params) for c_note in p_map.unassigned_actors(policy): print(c_note) v_result = policy.values(p_map, c_note) assert v_result is not None assert DiatonicPitch.parse('F#:6') not in { n.diatonic_pitch for n in v_result } p_map[other_source[1]].note = Note(DiatonicPitch.parse('E:6'), Duration(1, 8)) for c_note in p_map.unassigned_actors(policy): print(c_note) v_result = policy.values(p_map, c_note) assert v_result is not None ret_pitches = {n.diatonic_pitch for n in v_result} assert len( ret_pitches.intersection( {DiatonicPitch.parse('F#:6'), DiatonicPitch.parse('E:6')})) == 0 assert policy.verify(p_map) is False p_map[other_source[2]].note = Note(DiatonicPitch.parse('F#:6'), Duration(1, 8)) assert policy.verify(p_map) is False p_map[other_source[0]].note = Note(DiatonicPitch.parse('D:6'), Duration(1, 8)) assert policy.verify(p_map) is False p_map[other_source[2]].note = Note(DiatonicPitch.parse('A:6'), Duration(1, 8)) assert policy.verify(p_map) is True logging.debug('End test_is_not_equal') return
def test_centered_even_function(self): t_domain = Tonality.create(ModalityType.HWOctatonic, DiatonicTone('C')) r = PitchRange.create('E:3', 'E:7') f = DiatonicPitchReflectionFunction( t_domain, DiatonicPitch(4, DiatonicToneCache.get_tone('A')), r, FlipType.CenterTone) TestFlipOnTonality.print_map('test_centered_even_function', f) t = f.tonal_function assert 'C' == t['Gb'].diatonic_symbol assert 'Db' == t['Fb'].diatonic_symbol assert 'Eb' == t['Eb'].diatonic_symbol assert 'Fb' == t['Db'].diatonic_symbol assert 'Gb' == t['C'].diatonic_symbol assert 'G' == t['Bb'].diatonic_symbol assert 'A' == t['A'].diatonic_symbol assert 'Bb' == t['G'].diatonic_symbol assert 'C:4' == str(f['Gb:5']) assert 'Db:4' == str(f['Fb:5']) assert 'Eb:4' == str( f['Eb:5']) # The other stable tone outside of the centered! assert 'Fb:4' == str(f['Db:5']) assert 'Gb:4' == str(f['C:5']) assert 'G:4' == str(f['Bb:4']) assert 'A:4' == str(f['A:4']) assert 'Bb:4' == str(f['G:4']) assert 'C:5' == str(f['Gb:4']) assert 'Db:5' == str(f['Fb:4'])
def test_non_centered_odd_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) r = PitchRange.create('E:3', 'E:7') f = DiatonicPitchReflectionFunction( t_domain, DiatonicPitch(4, DiatonicToneCache.get_tone('F#')), r, FlipType.LowerNeighborOfPair) TestFlipOnTonality.print_map('test_non_centered_odd_function', f) t = f.tonal_function assert 'E' == t['A'].diatonic_symbol assert 'F#' == t['G#'].diatonic_symbol assert 'G#' == t['F#'].diatonic_symbol assert 'A' == t['E'].diatonic_symbol assert 'B' == t['D#'].diatonic_symbol assert 'C#' == t['C#'].diatonic_symbol assert 'D#' == t['B'].diatonic_symbol assert 'C#:4' == str(f['C#:5']) assert 'D#:4' == str(f['B:4']) assert 'E:4' == str(f['A:4']) assert 'F#:4' == str(f['G#:4']) assert 'G#:4' == str(f['F#:4']) assert 'A:4' == str(f['E:4']) assert 'B:4' == str(f['D#:4']) assert 'C#:5' == str(f['C#:4']) assert 'D#:5' == str(f['B:3'])
def test_non_scale_note(self): logging.debug('Start test_non_scale_note') note = Note(DiatonicPitch.parse("Bb:4"), Duration(1, 4)) policy = FixedPitchConstraint(note, DiatonicPitch.parse("Ab:5")) policy_context = TestFixedPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('C'), 'tIV', 'C:2', 'C:8') contextual_note = ContextualNote(policy_context) p_map = PMap() p_map[note] = contextual_note v_result = policy.values(p_map, note) result = next(iter(v_result)) print('test_non_scale_note note= {0}'.format(result)) assert result.diatonic_pitch == DiatonicPitch.parse("Ab:5") assert result.base_duration == Duration(1, 4) contextual_note.note = result result = policy.verify(p_map) assert result is True logging.debug('end test_non_scale_note')
def test_is_equal(self): logging.debug('Start test_is_equal') note1 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) note2 = Note(DiatonicPitch.parse('C:5'), Duration(1, 8)) lower_policy_context = TestEqualPitchConstraint.policy_creator( ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_context_note_a = ContextualNote( lower_policy_context, Note(DiatonicPitch.parse('F#:6'), Duration(1, 8))) lower_context_note_b = ContextualNote(lower_policy_context) parameter_map = dict([(note1, lower_context_note_a), (note2, lower_context_note_b)]) parameter_map = PMap(parameter_map) policy = EqualPitchConstraint([note1, note2]) result = policy.values(parameter_map, note2) actual_note = next(iter(result)) print('test_is_equal; note = {0}'.format(actual_note)) assert actual_note.diatonic_pitch == DiatonicPitch.parse("F#:6") assert actual_note.base_duration == Duration(1, 8) parameter_map[note2].note = actual_note assert policy.verify(parameter_map) is True logging.debug('End test_is_equal')
def test_simple_reverse_pitch_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) cycles = [['E', 'G#', 'A', 'C#'], ('F#', 'D#')] permutation_function = TonalityPermutationFunction.create( t_domain, cycles) r = PitchRange.create('E:3', 'E:7') f = TonalityPitchFunction(permutation_function, ('E:4', 'E:5'), r, True) TestTonalityPitchFunction.print_map( 'test_simple_reverse_pitch_fnction', f) assert 'G#:5' == str(f['E:4']) assert 'D#:6' == str(f['F#:4']) assert 'A:5' == str(f['G#:4']) assert 'C#:6' == str(f['A:4']) assert 'B:5' == str(f['B:4']) assert 'E:5' == str(f['C#:5']) assert 'F#:5' == str(f['D#:5']) assert 'G#:4' == str(f['E:5']) assert 'D#:5' == str(f['F#:5']) assert 'A:4' == str(f['G#:5']) assert 'C#:5' == str(f['A:5']) assert 'B:4' == str(f['B:5']) assert 'E:4' == str(f['C#:6']) assert 'F#:4' == str(f['D#:6'])
def test_additional_octaves(self): t_domain = Tonality.create(ModalityType.MinorPentatonic, DiatonicTone('C')) i = Interval(12, IntervalType.Perfect) r = PitchRange.create('E:3', 'E:7') f = CrossTonalityShiftPitchFunction(t_domain, r, i) print('f={0}'.format(f)) assert 'P:12' == str(f.root_shift_interval) assert 'G:5' == str(f['C:4']) assert 'A:5' == str(f['D:4']) assert 'B:5' == str(f['E:4']) assert 'C:6' == str(f['F:4']) i = Interval(11, IntervalType.Perfect).negation() f = CrossTonalityShiftPitchFunction(t_domain, r, i) print('f={0}'.format(f)) assert '-P:11' == str(f.root_shift_interval) assert 'G:2' == str(f['C:4']) assert 'A:2' == str(f['D:4']) assert 'B:2' == str(f['E:4']) assert 'C:3' == str(f['F:4'])
def test_pentatonic_tonal_function(self): t_domain = Tonality.create(ModalityType.MinorPentatonic, DiatonicTone('C')) i = Interval(5, IntervalType.Perfect) r = PitchRange.create('E:3', 'E:7') f = CrossTonalityShiftPitchFunction(t_domain, r, i) print('f={0}'.format(f)) TestCrossTonalityShiftPitchFunction.print_map( 'test_pentatonic_tonal_function', f) t = f.tonal_function print(t) assert 'G' == t['C'].diatonic_symbol assert 'Bb' == t['Eb'].diatonic_symbol assert 'C' == t['F'].diatonic_symbol assert 'D' == t['G'].diatonic_symbol assert 'F' == t['Bb'].diatonic_symbol assert 'G:5' == str(f['C:5']) assert 'F:5' == str(f['Bb:4']) assert 'D:5' == str(f['G:4']) assert 'C:5' == str(f['F:4']) assert 'Bb:4' == str(f['Eb:4']) assert 'G:4' == str(f['C:4']) # test range d = f.domain_pitch_range print(d) assert d.start_index == DiatonicPitch.parse('E:3').chromatic_distance assert d.end_index == DiatonicPitch.parse('E:7').chromatic_distance r = f.range_pitch_range print(r) assert r.start_index == DiatonicPitch.parse('B:3').chromatic_distance assert r.end_index == DiatonicPitch.parse('B:7').chromatic_distance # test chromatics assert 'G#:5' == str(f['C#:5']) assert 'F#:5' == str(f['B:4']) assert 'E#:5' == str(f['A#:4']) assert 'E:5' == str(f['A:4']) assert 'D#:5' == str(f['G#:4']) assert 'C#:5' == str(f['F#:4']) assert 'B:4' == str(f['E:4']) assert 'A:4' == str(f['D:4']) assert 'A#:4' == str(f['D#:4']) assert 'G#:4' == str(f['C#:4']) assert 'Gb:5' == str(f['Cb:5']) assert 'Fb:5' == str(f['Bbb:4']) assert 'Eb:5' == str(f['Ab:4']) assert 'Db:5' == str(f['Gb:4']) assert 'Cb:5' == str(f['Fb:4']) assert 'Bbb:4' == str(f['Ebb:4']) assert 'Ab:4' == str(f['Db:4']) assert 'Gb:4' == str(f['Cb:4'])
def __build_diatonics(self): """ Builds all diatonic tones for the cache. """ for ltr in DiatonicTone.DIATONIC_LETTERS: for aug in DiatonicTone.AUGMENTATIONS: self.diatonic_map[(ltr + aug).lower()] = DiatonicTone(ltr + aug)
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_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 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_simplified_adapted_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('F')) t_range = Tonality.create(ModalityType.MelodicMinor, DiatonicTone('G')) f = TonalFunction(t_domain, t_range) nt_domain = Tonality.create(ModalityType.Major, DiatonicTone('Ab')) nt_range = Tonality.create(ModalityType.MelodicMinor, DiatonicTone('e')) pf = f.create_adapted_function(nt_domain, nt_range) assert DiatonicToneCache.get_tone('E') == pf['Ab'] assert DiatonicToneCache.get_tone('F#') == pf['Bb'] assert DiatonicToneCache.get_tone('G') == pf['C'] assert DiatonicToneCache.get_tone('A') == pf['Db'] assert DiatonicToneCache.get_tone('B') == pf['Eb'] assert DiatonicToneCache.get_tone('C#') == pf['F'] assert DiatonicToneCache.get_tone('D#') == pf['G']
def test_simple_tonal_function(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('C')) t_range = Tonality.create(ModalityType.Major, DiatonicTone('A')) # default map between 2 tonalities of same cardinality. f = TonalFunction(t_domain, t_range) assert DiatonicToneCache.get_tone('A') == f['C'] assert DiatonicToneCache.get_tone('B') == f['D'] assert DiatonicToneCache.get_tone('C#') == f['E'] assert DiatonicToneCache.get_tone('D') == f['F'] assert DiatonicToneCache.get_tone('E') == f['G'] assert DiatonicToneCache.get_tone('F#') == f['A'] assert DiatonicToneCache.get_tone('G#') == f['B'] skeleton = f.extract_template() assert [0, 1, 2, 3, 4, 5, 6] == skeleton.tonal_order TestTonalFunction.print_function(f)
def test_simple_quartal(self): diatonic_tonality = Tonality.create(ModalityType.Major, DiatonicTone("C")) chord_list = ChordClassifier.classify(['e', 'a', 'd'], 'e', diatonic_tonality) assert 1 == len(chord_list) assert "PerPer" == str(chord_list[0].chord_type) TestChordClassifier.print_chord_list('test_simple_quartal', chord_list) chord_list = ChordClassifier.classify(['e', 'a', 'd', 'Bb'], 'e', diatonic_tonality) assert 0 == len(chord_list)
def parse(chord_string): """ Parse an input string into a TertialChordTemplate. Args: chord_string: string input representing chord Returns: TertianChordTemplate """ if not chord_string: raise TertianChordException('Unable to parse chord string to completion: {0}'.format(chord_string)) m = TertianChordTemplate.TERTIAN_PATTERN.match(chord_string) if not m: raise TertianChordException('Unable to parse chord string to completion: {0}'.format(chord_string)) scale_degree = m.group(TertianChordTemplate.GROUP_SCALE_DEGREE) if scale_degree: scale_degree = ChordTemplate.SCALE_DEGREE_MAP[scale_degree] if m.group(TertianChordTemplate.GROUP_DIATONIC_TONE) is not None: diatonic_basis = DiatonicTone(m.group(TertianChordTemplate.GROUP_DIATONIC_TONE)) else: diatonic_basis = None chord_name = m.group(TertianChordTemplate.GROUP_CHORD) chord_type = None if chord_name: chord_type = TertianChordType.to_type(chord_name) inversion_text = m.group(TertianChordTemplate.GROUP_INVERSION) inversion_tension = m.group(TertianChordTemplate.INVERSION_TENSION) inversion_interval = None inversion = None if inversion_tension: tensions_parse = TertianChordTemplate.INVERSE_TENSION_PATTERN.findall(inversion_tension) for tension in tensions_parse: # should only be 1 aug = DiatonicTone.AUGMENTATION_OFFSET_MAPPING[tension[0]] interval_type = Interval.available_types(int(tension[1]))[aug] inversion_interval = Interval(int(tension[1]), interval_type) logging.info('inversion_interval = {0}'.format(str(inversion_interval))) elif inversion_text: inversion = int(inversion_text) else: inversion = 1 tensions = [] if m.group(TertianChordTemplate.GROUP_TENSIONS): tensions_parse = TertianChordTemplate.TENSION_PATTERN.findall(m.group(TertianChordTemplate.GROUP_TENSIONS)) for tension in tensions_parse: aug = DiatonicTone.AUGMENTATION_OFFSET_MAPPING[tension[2]] if aug not in Interval.available_types(int(tension[3])): raise TertianChordException('Invalid interval specification for tension \'{0}\''.format(tension[0])) interval_type = Interval.available_types(int(tension[3]))[aug] interval = Interval(int(tension[3]), interval_type) tensions.append(interval) return TertianChordTemplate(diatonic_basis, scale_degree, chord_type, tensions, inversion, inversion_interval)