def test_C_Natural_variable_cue_center(self): print('test_C_Natural_variable_cue_center: C-Natural, variable cue') domain_tonality = Tonality.create(ModalityType.NaturalMinor, DiatonicToneCache.get_tone('C')) answers = [['C', 'Bb', 'A', 'G', 'F', 'E', 'D'], ['E', 'D', 'C#', 'B', 'A', 'G#', 'F#'], ['Gb', 'Fb', 'Eb', 'Db', 'Cb', 'Bb', 'Ab'], ['Bb', 'Ab', 'G', 'F', 'Eb', 'D', 'C'], ['D', 'C', 'B', 'A', 'G', 'F#', 'E'], ['Fb', 'Ebb', 'Db', 'Cb', 'Bbb', 'Ab', 'Gb'], ['Ab', 'Gb', 'F', 'Eb', 'Db', 'C', 'Bb']] index = 0 for cue_tone in domain_tonality.annotation[:-1]: f = ChromaticTonalReflectionFunction(domain_tonality, cue_tone, FlipType.CenterTone) TestChromaticTonalReflectionFunction.print_map( domain_tonality, f, cue_tone.diatonic_symbol) for tone, i in zip(domain_tonality.annotation[:-1], range(0, 6)): assert f[tone] == DiatonicToneCache.get_tone(answers[index][i]), \ 'f[{0}]={1} != {2}'.format(tone.diatonic_symbol, f[tone].diatonic_symbol, DiatonicToneCache.get_tone(answers[index][i]).diatonic_symbol) index += 1
def test_enharmonic_fixed_tone(self): logging.debug('Start test_enharmonic_fixed_tone') note = Note(DiatonicPitch.parse("C:5"), Duration(1, 4)) policy = FixedToneConstraint(note, DiatonicToneCache.get_tone("Bbb")) lower_policy_context = TestFixedToneConstraint.policy_creator(ModalityType.Major, DiatonicTone('G'), 'tV', 'C:2', 'C:8') lower_contextual_note = ContextualNote(lower_policy_context) m = dict([(note, lower_contextual_note)]) v_result = policy.values(m, note) assert len(v_result) == 6 for note in v_result: print('test_simple_fixed_tone pitch = {0}'.format(note.diatonic_pitch)) assert note.diatonic_pitch.diatonic_tone == DiatonicToneCache.get_tone('A') assert note.base_duration == Duration(1, 4) lower_contextual_note.note = note result = policy.verify(m) assert result is True lower_contextual_note.note = None logging.debug('End test_enharmonic_fixed_tone')
def __setitem__(self, key, value): if isinstance(key, str): key = DiatonicToneCache.get_tone(key) if key is None: raise Exception('Key \'{0}\' invalid syntax.'.format(key)) elif not isinstance(key, DiatonicTone): raise Exception( 'Key {0} invalid - must be string or DiatonicTone.'.format( key)) domain_tonal = key in self._domain_tones if isinstance(value, str): value = DiatonicToneCache.get_tone(value) if value is None: raise Exception('Value \'{0}\' invalid syntax.'.format(value)) elif value is not None and not isinstance(value, DiatonicTone): raise Exception( 'Range {0} invalid - must be string, DiatonicTone or None.'. format(value)) range_tonal = value in self._range_tones if domain_tonal != range_tonal: raise Exception( 'Both key {0} and value {1} must be in respective tonality or outside for valid setting.' .format(key, value)) super(TonalFunction, self).__setitem__(key, value)
def test_C_major_modal_scales_center_cue(self): print( 'test_C_major_modal_scales_center_cue: CenterTone, cue == root tone, modal on C-Major' ) answers = [['C', 'Bb', 'Ab', 'G', 'F', 'Eb', 'Db'], ['D', 'C', 'B', 'A', 'G', 'F', 'E'], ['E', 'D#', 'C#', 'B', 'A', 'G#', 'F#'], ['F', 'Eb', 'Db', 'Cb', 'Bb', 'Ab', 'Gb'], ['G', 'F', 'Eb', 'D', 'C', 'Bb', 'A'], ['A', 'G', 'F#', 'E', 'D', 'C#', 'B'], ['B', 'A#', 'G#', 'F#', 'E#', 'D#', 'C#']] index = 0 for letter in list('CDEFGAB'): modal_tonality = Tonality.create( ModalityType.Major, DiatonicToneCache.get_tone(letter), index) f = ChromaticTonalReflectionFunction( modal_tonality, DiatonicToneCache.get_tone(letter), FlipType.CenterTone) TestChromaticTonalReflectionFunction.print_map( modal_tonality, f, letter) for tone, i in zip(modal_tonality.annotation[:-1], range(0, 6)): assert f[tone] == DiatonicToneCache.get_tone(answers[index][i]), \ 'f[{0}]={1} != {2}'.format(tone.diatonic_symbol, f[tone].diatonic_symbol, DiatonicToneCache.get_tone(answers[index][i]).diatonic_symbol) index = index + 1
def test_C_Major_variable_cue_lower_neighbor_function(self): print( 'test_C_Major_variable_cue_lower_neighbor_function: C-major, variable cue' ) domain_tonality = Tonality.create(ModalityType.Major, DiatonicToneCache.get_tone('C')) answers = [['D', 'C', 'Bb', 'A', 'G', 'F', 'Eb'], ['F#', 'E', 'D', 'C#', 'B', 'A', 'G'], ['A', 'G', 'F', 'E', 'D', 'C', 'Bb'], ['C', 'Bb', 'Ab', 'G', 'F', 'Eb', 'Db'], ['E', 'D', 'C', 'B', 'A', 'G', 'G'], ['G#', 'F#', 'E', 'D#', 'C#', 'B', 'A'], ['B', 'A', 'G', 'F#', 'E', 'D', 'C']] index = 0 for letter in list('CDEFGAB'): f = ChromaticTonalReflectionFunction( domain_tonality, DiatonicToneCache.get_tone(letter), FlipType.LowerNeighborOfPair) TestChromaticTonalReflectionFunction.print_map( domain_tonality, f, letter) for tone, i in zip(domain_tonality.annotation[:-1], range(0, 6)): assert f[tone] == DiatonicToneCache.get_tone(answers[index][i]), \ 'f[{0}]={1} != {2}'.format(tone.diatonic_symbol, f[tone].diatonic_symbol, DiatonicToneCache.get_tone(answers[index][i]).diatonic_symbol) index += 1
def __getitem__(self, key): if isinstance(key, str): key = DiatonicToneCache.get_tone(ChromaticPermutation.NORMALIZED_MAPPING[DiatonicTone.to_upper(key)]) elif isinstance(key, DiatonicTone): key = DiatonicToneCache.get_tone(ChromaticPermutation.NORMALIZED_MAPPING[key.diatonic_symbol]) else: raise Exception('Key \'{0}\' must be a tone string or DiatonicTone.'.format(key)) return_tone = super(ChromaticPermutation, self).__getitem__(key) return self._to_user_preference[return_tone] if return_tone in self._to_user_preference else return_tone
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 convert_cycles_to_tones(tone_domain, cycles): if cycles is None: return [] if not isinstance(cycles, list): raise Exception('Cycles paramater is not a list.') new_cycles = list() for cycle in cycles: if not isinstance(cycles, list): raise Exception('Cycle \'{0}\' must be a list.'.format(cycle)) new_cycle = list() for tone_rep in cycle: if isinstance(tone_rep, str): tone = DiatonicToneCache.get_tone(tone_rep) if tone is None: raise Exception( 'Tone domain item \'{0}\' illegal syntax.'.format( tone_rep)) elif isinstance(tone_rep, DiatonicTone): tone = tone_rep else: raise Exception( 'Tone domain item \'{0}\' must be string.'.format( tone_rep)) if len(tone_domain) != 0: if tone not in tone_domain: raise Exception( 'Tone \'{0}\' not in explicit tone domain.'.format( tone)) new_cycle.append(tone) new_cycles.append(new_cycle) return new_cycles
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_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_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 __init__(self, domain_tonality, new_root_tone, modal_index=None, inherent_modality_type=None): """ Constructor. :param domain_tonality: Given domain tonality. :param new_root_tone: The root for the new tonality. :param modal_index: The modal index for the new root tone. If none, match to domain_tonality. :param inherent_modality_type: new modality type for behind the new tonality, e.g. major. if None, match to domain tonality. Note: tonality cardinality must match! Note: new_root_tone should be the domain_tonality's modal_index tone. """ modality = inherent_modality_type if inherent_modality_type is not None else domain_tonality.modality_type if isinstance(new_root_tone, str): root_tone_parameter = DiatonicToneCache.get_tone(new_root_tone) else: root_tone_parameter = new_root_tone range_tonality = Tonality.create(modality, root_tone_parameter, modal_index if modal_index is not None else domain_tonality.modal_index) if domain_tonality.cardinality != range_tonality.cardinality: raise Exception('domain and range tonalities must have same cardinality') self._domain_tonality = domain_tonality self._range_tonality = range_tonality self._modal_index = range_tonality.modal_index self.constr_primary_map = self._build_primary_map() TonalFunction.__init__(self, self.domain_tonality, self.range_tonality, self.constr_primary_map, self._build_extension_map())
def __getitem__(self, key): if isinstance(key, str): key = DiatonicToneCache.get_tone(key) if key is None: raise Exception('Key \'{0}\' invalid syntax.'.format(key)) return super(TonalFunction, self).__getitem__(key)
def values(self, p_map, v_note): if v_note != self.actor_note: raise Exception("Illegal v_note {0} for constraints".format(v_note)) if p_map[v_note].note is not None: if p_map[v_note].note.diatonic_pitch.diatonic_tone == self.tone: return {p_map[v_note].note} raise Exception('Fixed Tone Policy Violated has {0} should be {1}'.format( p_map[v_note].note.diatonic_pitch.diatonic_tone, self.tone)) contextual_note = p_map[self.actor_note] policy_context = contextual_note.policy_context pitch_range = contextual_note.policy_context.pitch_range start_partition = max(ChromaticScale.index_to_location(pitch_range.start_index)[0] - 1, 0) end_partition = min(ChromaticScale.index_to_location(pitch_range.end_index)[0] + 1, ChromaticScale.CHROMATIC_END[0]) # Try to find that tone in target's tonality/scale. tone = self.tone for t_str in self.tone.enharmonics(): t = DiatonicToneCache.get_tone(t_str) for scale_tone in PitchScale(policy_context.harmonic_context.tonality, policy_context.pitch_range).tone_scale: if scale_tone == t: tone = t break valid_set = OrderedSet() for i in range(start_partition, end_partition + 1): pitch = DiatonicPitch(i, tone) if pitch_range.is_pitch_inbounds(pitch): note = Note(pitch, self.actor_note.base_duration, self.actor_note.num_dots) valid_set.add(note) return valid_set
def test_is_scalar_with_roles(self): logging.debug('Start test_is_scalar_with_roles') v_note = Note(DiatonicPitch.parse('F:5'), Duration(1, 4)) lower_policy_context = TestScalarPitchConstraint.policy_creator( ModalityType.Major, DiatonicToneCache.get_tone('G'), 'tV', 'G:5', 'G:7') lower_context_note = ContextualNote(lower_policy_context) parameter_map = dict([(v_note, lower_context_note)]) policy = ScalarPitchConstraint(v_note, [3, 5]) v_result = policy.values(parameter_map, v_note) tones = list(lower_policy_context.harmonic_context.tonality.annotation) tones = tones[:-1] for note in v_result: print('test_is_scalar; note = {0}'.format(note)) tone = note.diatonic_pitch.diatonic_tone octave = note.diatonic_pitch.octave assert tone in tones assert tones.index(tone) in [3, 5] assert octave in range(5, 8) assert len(v_result) == 2 * 2 for note in v_result: parameter_map[v_note].note = note assert policy.verify(parameter_map) is True logging.debug('End test_is_scalar_with_roles')
def __getitem__(self, key): if isinstance(key, str): key = DiatonicToneCache.get_tone(key) if key is None: raise Exception('Illegal tone syntax \'{0}\'.'.format(key)) if not isinstance(key, DiatonicTone): raise Exception( 'Key \'{0}\' must be instance of DiatonticTone'.format(key)) return super(TonalPermutation, self).__getitem__(key)
def test_C_pentatonic(self): print('test_C_pentatonic: C-Pentatonic, variable cue') domain_tonality = Tonality.create(ModalityType.MajorPentatonic, DiatonicToneCache.get_tone('C')) tones = domain_tonality.annotation[:-1] cue_tone = tones[1] f = ChromaticTonalReflectionFunction(domain_tonality, cue_tone, FlipType.CenterTone) TestChromaticTonalReflectionFunction.print_map( domain_tonality, f, cue_tone.diatonic_symbol) answers = ['E', 'D', 'C', 'A', 'G'] for tone, i in zip(tones, range(0, 5)): assert f[tone] == DiatonicToneCache.get_tone(answers[i]), \ 'f[{0}]={1} != {2}'.format(tone.diatonic_symbol, f[tone].diatonic_symbol, DiatonicToneCache.get_tone(answers[i]).diatonic_symbol)
def test_only_cycles(self): cycles = [['C', 'D'], ['Eb', 'F#']] p = TonalPermutation(cycles) assert DiatonicToneCache.get_tone('C') in p.tone_domain assert DiatonicToneCache.get_tone('D') in p.tone_domain assert DiatonicToneCache.get_tone('Eb') in p.tone_domain assert DiatonicToneCache.get_tone('F#') in p.tone_domain assert DiatonicToneCache.get_tone('D') == p['C'] assert DiatonicToneCache.get_tone('C') == p['D'] assert DiatonicToneCache.get_tone('Eb') == p['F#'] assert DiatonicToneCache.get_tone('F#') == p['Eb']
def create(modality_type, diatonic_tone, modal_index=0): """ Constructor. :param modality_type: ModalityType being used. :param diatonic_tone: DiatonicTone being used as root. :param modal_index: (origin 0), which of the tonality's tone is the actual root_tone. """ if isinstance(diatonic_tone, str): base_diatonic_tone = DiatonicToneCache.get_tone(diatonic_tone) else: base_diatonic_tone = diatonic_tone return Tonality(ModalityFactory.create_modality(modality_type, modal_index), base_diatonic_tone)
def test_extension_map(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('C')) t_range = Tonality.create(ModalityType.Major, DiatonicTone('A')) extension_map = {'C#': 'A#', 'D#': 'C', 'Gb': 'G#'} # default map between 2 tonalities of same cardinality. f = TonalFunction(t_domain, t_range, None, extension_map) 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'] assert f['Db'] is None assert DiatonicToneCache.get_tone('A#') == f['C#'] assert DiatonicToneCache.get_tone('C') == f['D#'] assert f['Eb'] is None assert DiatonicToneCache.get_tone('G#') == f['Gb'] assert f['F#'] is None
def test_basic_tonal_permutation(self): domain = {'C', 'D', 'Eb', 'F#'} cycles = [['C', 'D'], ['Eb', 'F#']] p = TonalPermutation(cycles, domain) print(p) assert DiatonicToneCache.get_tone('C') in p.tone_domain assert DiatonicToneCache.get_tone('D') in p.tone_domain assert DiatonicToneCache.get_tone('Eb') in p.tone_domain assert DiatonicToneCache.get_tone('F#') in p.tone_domain assert DiatonicToneCache.get_tone('D') == p['C'] assert DiatonicToneCache.get_tone('C') == p['D'] assert DiatonicToneCache.get_tone('Eb') == p['F#'] assert DiatonicToneCache.get_tone('F#') == p['Eb']
def test_simple_tonal_permutation(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) cycles = [['E', 'G#', 'A', 'B'], ('F#', 'G#')] p = TonalityPermutation(t_domain, cycles) assert DiatonicToneCache.get_tone('G#') == p['E'] assert DiatonicToneCache.get_tone('A') == p['F#'] assert DiatonicToneCache.get_tone('F#') == p['G#'] assert DiatonicToneCache.get_tone('B') == p['A'] assert DiatonicToneCache.get_tone('E') == p['B'] assert DiatonicToneCache.get_tone('C#') == p['C#'] assert DiatonicToneCache.get_tone('D#') == p['D#']
def create_score(s_notes, modality, key_tone, chords, instrument, ts): diatonic_tonality = Tonality.create(modality, DiatonicToneCache.get_tone(key_tone)) hc_track = TestTReshape.create_track(chords, diatonic_tonality) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60, Duration(1, 4)), Position(0))) ts_seq.add(TimeSignatureEvent(TimeSignature(ts[0], Duration(1, ts[1]), ts[2]), Position(0))) c = InstrumentCatalog.instance() violin = c.get_instrument(instrument) return LiteScore(TestTReshape.create_line(s_notes), hc_track, violin, tempo_seq, ts_seq)
def create_score_artifacts(modality, key_tone, chords, ts): diatonic_tonality = Tonality.create( modality, DiatonicToneCache.get_tone(key_tone)) hc_track = TestPitchFitFunction.create_track(chords, diatonic_tonality) tempo_seq = TempoEventSequence() ts_seq = EventSequence() tempo_seq.add(TempoEvent(Tempo(60, Duration(1, 4)), Position(0))) ts_seq.add( TimeSignatureEvent(TimeSignature(ts[0], Duration(1, ts[1]), ts[2]), Position(0))) return hc_track, tempo_seq, ts_seq
def get_tone(diatonic_tone_text): """ Fetch a cached diatonic tone based on text representation. Args: diatonic_tone_text: text specification, e.g. Abb Returns: DiatonicTone for specified pitch Exceptions: If specified pitch cannot be parsed. """ return DiatonicToneCache.get_tone(diatonic_tone_text)
def __init__(self, cycles=None): self._to_user_preference = dict() if cycles is None: cycles = list() norm_cycles = list() if len(cycles) == 0: for t in ChromaticPermutation.NORMALIZED_TONES: tone = DiatonicToneCache.get_tone(t) norm_cycles.append([tone]) self._to_user_preference[tone] = tone else: if not isinstance(cycles, list): raise Exception('Cycles must be a list.') for cycle in cycles: if not isinstance(cycle, list): raise Exception('Cycle must be a list {0}.'.format(cycle)) norm_cycle = list() for v in cycle: if not isinstance(v, str): raise Exception('Cycle element must be a string {0}.'.format(v)) tone_txt = DiatonicTone.to_upper(v) if tone_txt is None: raise Exception('Cycle element \'{0}\' not a recognized tone.'.format(v)) tone = DiatonicToneCache.get_tone(ChromaticPermutation.NORMALIZED_MAPPING[tone_txt]) if tone in norm_cycle: raise Exception('Tone \'{0}\' appears twice enharmonically in same cycle.'.format(v)) norm_cycle.append(tone) # User preferred representation of tone is always the first one found. if tone not in self._to_user_preference: self._to_user_preference[tone] = DiatonicToneCache.get_tone(tone_txt) norm_cycles.append(norm_cycle) tone_list = [DiatonicToneCache.get_tone(x) for x in ChromaticPermutation.NORMALIZED_TONES] Permutation.__init__(self, tone_list, norm_cycles)
def test_simple_id(self): t_domain = Tonality.create(ModalityType.Major, DiatonicTone('E')) p = TonalityPermutation(t_domain) print(p) assert DiatonicToneCache.get_tone('E') == p['E'] assert DiatonicToneCache.get_tone('F#') == p['F#'] assert DiatonicToneCache.get_tone('G#') == p['G#'] assert DiatonicToneCache.get_tone('A') == p['A'] assert DiatonicToneCache.get_tone('B') == p['B'] assert DiatonicToneCache.get_tone('C#') == p['C#'] assert DiatonicToneCache.get_tone('D#') == p['D#']
def __delitem__(self, key): if isinstance(key, str): key = DiatonicToneCache.get_tone(key) if key is None: raise Exception('Key \'{0}\' invalid syntax.'.format(key)) elif not isinstance(key, DiatonicTone): raise Exception( 'Key {0} invalid - must be string or DiatonicTone.'.format( key)) if key in self._domain_tones: raise Exception('Tone {0} must not be in tonality {1}'.format( key, self.domain_tonality)) super(TonalFunction, self).__delitem__(key)
def _build_lex_dcom_maps(tonality, scale_origin_str): # lex maps all enharmonics to either tones in the tonality or outside of tonality to some select # representation lex = dict() used = set() for tone in tonality.annotation: enharmonics = DiatonicTone.DIATONIC_OFFSET_ENHARMONIC_MAPPING[tone.placement] for t in enharmonics: lex[DiatonicToneCache.get_tone(t)] = tone used.add(tone.placement) outside = set(range(0, 12)) - used for p in outside: enharmonics = DiatonicTone.DIATONIC_OFFSET_ENHARMONIC_MAPPING[p] select_tone = DiatonicToneCache.get_tone(enharmonics[0]) enharmonics = DiatonicTone.DIATONIC_OFFSET_ENHARMONIC_MAPPING[select_tone.placement] for t in enharmonics: lex[DiatonicToneCache.get_tone(t)] = select_tone # build com which maps the range of lex to the appropriate octave origin_pitch = DiatonicPitch.parse(scale_origin_str) base_octave = origin_pitch.octave com = dict() values = list({v for v in lex.values()}) values.sort(key=lambda x: x.placement) index = values.index(origin_pitch.diatonic_tone) value_list = values if index == 0 else values[index: len(values)] + values[0: index] com[value_list[0]] = octave = base_octave for i in range(1, len(value_list)): octave = octave + 1 if DiatonicPitch.crosses_c(value_list[i - 1], value_list[i], True) \ else octave com[value_list[i]] = octave return lex, com