Beispiel #1
0
 def _reset_pitches(self, as_copy):
     line = self.source_line.clone() if as_copy else self.source_line
     for note in line.get_all_notes():
         if self.temporal_extent.contains(
                 note.get_absolute_position().position):
             hc = self.source_hct.get_hc_by_position(
                 note.get_absolute_position())
             if hc not in self.__hc_flip_map.keys():
                 if isinstance(hc.chord, SecondaryChord):
                     f = self._build_secondary_flip_function(hc)
                 else:
                     low, high = TChromaticReflection._adjust_flip_cue_to_tonality(
                         self.cue_pitch, hc.tonality)
                     if high is None:
                         f = ChromaticPitchReflectionFunction(
                             hc.tonality, self.cue_pitch,
                             self.domain_pitch_range, self.flip_type)
                     else:
                         f = ChromaticPitchReflectionFunction(
                             hc.tonality, low, self.domain_pitch_range,
                             FlipType.LowerNeighborOfPair)
                 self.__hc_flip_map[hc] = f
             else:
                 f = self.__hc_flip_map[hc]
             note.diatonic_pitch = f[note.diatonic_pitch]
     return line
Beispiel #2
0
 def _build_chromatic_reflection(self, hc):
     low, high = TChromaticReflection._adjust_flip_cue_to_tonality(
         self.cue_pitch, hc.tonality)
     if high is None:
         f = ChromaticPitchReflectionFunction(hc.tonality, self.cue_pitch,
                                              self.domain_pitch_range,
                                              self.flip_type)
     else:
         f = ChromaticPitchReflectionFunction(hc.tonality, low,
                                              self.domain_pitch_range,
                                              FlipType.LowerNeighborOfPair)
     return f
Beispiel #3
0
    def remap_chord(self, hc):
        from tonalmodel.interval import Interval as TonalInterval
        chord = hc.chord

        if not isinstance(chord, SecondaryChord):
            f = self.__hc_flip_map[hc] if hc in self.__hc_flip_map.keys() else \
                ChromaticPitchReflectionFunction(hc.tonality, self.cue_pitch, self.domain_pitch_range)
            # FlipOnTonality(hc.tonality, self.cue_pitch, self.domain_pitch_range)
            new_chord_tones = [f.tonal_function[t[0]] for t in chord.tones]
            chords = ChordClassifier.classify_all_roots(
                new_chord_tones, f.range_tonality)
            if chords is not None and len(chords) > 0:
                return chords[0]
            else:
                raise Exception(
                    'Cannot remap/classify chord {0} based on chord.'.format(
                        ', '.join(
                            str(t.diatonic_symbol) for t in new_chord_tones)))
        else:
            if hc in self.__hc_flip_map.keys():
                secondary_function = self.__hc_flip_map[hc].tonal_function
            else:
                secondary_function = self._build_secondary_flip_function(
                    hc).tonal_function

            base_f = self._build_chromatic_reflection(hc)
            root_mapped_tonality = base_f.range_tonality
            mapped_denominator = TonalInterval.calculate_tone_interval(
                root_mapped_tonality.root_tone, secondary_function.
                range_tonality.root_tone).diatonic_distance + 1

            # Alternatively, in the else part, we could have done:
            #   secondary_function = f.tonal_function.create_adapted_function(secondary_tonality, secondary_tonality)
            # but to be consistent within the logic, we go for the reflection_tests constructiobn of
            # the secondary function
            # as embodied in tFlip._build_secondary_flip_function()

            new_chord_tones = [secondary_function[t[0]] for t in chord.tones]
            secondary_tonality = secondary_function.range_tonality
            chords = ChordClassifier.classify_all_roots(
                new_chord_tones, secondary_tonality)

            if chords is not None and len(chords) > 0:
                new_chord = chords[0]
            else:
                raise Exception(
                    'Cannot remap/classify chord {0} based on chord.'.format(
                        ', '.join(
                            str(t.diatonic_symbol) for t in new_chord_tones)))

            # mapped_numerator = TonalInterval.calculate_tone_interval(
            #    new_chord.root_tone,
            #    secondary_function.range_tonality.root_tone).diatonic_distance + 1
            secondary_chord_template = SecondaryChordTemplate(
                new_chord.chord_template, mapped_denominator,
                secondary_tonality.modality.modality_type)
            secondary_chord = SecondaryChord(secondary_chord_template,
                                             root_mapped_tonality,
                                             secondary_function.range_tonality)
            return secondary_chord
Beispiel #4
0
    def test_major_modality(self):
        print('Testing Major Modality: D-Major, cue=G:4')
        domain_tonality = Tonality.create(ModalityType.Major, DiatonicFoundation.get_tone('D'))
        cue_pitch = DiatonicPitch.parse('G:4')

        domain_pitch_range = PitchRange.create('D:3', 'C#:6')
        f = ChromaticPitchReflectionFunction(domain_tonality, cue_pitch, domain_pitch_range, FlipType.CenterTone)

        TestChromaticPitchReflectionFunction.print_function(f)

        # Ensure all domain keys are in the domain_pitch_range
        for pitch in f.domain:
            assert domain_pitch_range.is_pitch_inbounds(pitch), \
                'Pitch {0} is not in range {1}.'.format(pitch, domain_pitch_range)

        assert DiatonicPitch.parse('D:3') in f.domain
        assert DiatonicPitch.parse('C#:6') in f.domain

        # Test for octave coverage
        assert 6 == f['D:3'].octave
        assert 5 == f['C#:4'].octave
        assert 5 == f['D:4'].octave
        assert 4 == f['C#:5'].octave
        assert 4 == f['D:5'].octave
        assert 3 == f['C#:6'].octave
Beispiel #5
0
    def _rebuild_hct(self, orig_hct, as_copy):
        hc_list = orig_hct.hc_list()
        if not as_copy:
            orig_hct.clear()
        new_hct = HarmonicContextTrack() if as_copy else orig_hct
        next_index = 0
        position = Position(0)
        if self.pre_extent is not None:
            for hc in hc_list:
                intersect = hc.extent.intersection(self.pre_extent)
                if intersect is None:
                    break
                duration = Duration(
                    min(intersect.length(), hc.duration.duration))
                new_hc = HarmonicContext(hc.tonality, hc.chord, duration,
                                         hc.position)
                new_hct.append(new_hc)
                position += new_hc.duration
                if hc.extent.upper > self.pre_extent.upper:
                    break
                next_index += 1

        for hc in islice(hc_list, next_index, None):
            intersect = hc.extent.intersection(self.temporal_extent)
            if intersect is None:
                break
            duration = Duration(intersect.length())
            if self.keep_hct:
                new_hc = HarmonicContext(hc.tonality, hc.chord, duration,
                                         position)
            else:
                f = self.__hc_flip_map[hc] if hc in self.__hc_flip_map.keys() else \
                    ChromaticPitchReflectionFunction(hc.tonality, self.cue_pitch, self.domain_pitch_range)
                new_hc = HarmonicContext(f.range_tonality,
                                         self.remap_chord(hc), duration,
                                         position)
            new_hct.append(new_hc)
            position += new_hc.duration
            if hc.extent.upper > self.temporal_extent.upper:
                break
            next_index += 1

        if self.post_extent is not None:
            for hc in islice(hc_list, next_index, None):
                intersect = hc.extent.intersection(self.post_extent)
                if intersect is None:
                    break
                duration = Duration(intersect.length())
                new_hc = HarmonicContext(hc.tonality, hc.chord, duration,
                                         position)
                new_hct.append(new_hc)
                position += new_hc.duration

        return new_hct
Beispiel #6
0
    def _build_secondary_flip_function(self, hc):
        # Strategy - for secondary chords, we simply build a reflection for the secondary scale.
        #  The cue pitch is used if the cue pitch exists in the secondary scale.
        #  otherwise we build a reflection_tests around the neighboring pitches to the cue.
        #  This is about the simplest stragegy to use in this situation, and has credibility by virtue of using
        #  the same cue pitch.  However, it may result in irregular resolutions in chord
        #  sequences, like V/ii, ii
        secondary_tonality = hc.chord.secondary_tonality

        lo_cue_tone, hi_cue_tone = TChromaticReflection._compute_cue_tone(
            self.cue_pitch.diatonic_tone, secondary_tonality)
        octave = self.cue_pitch.octave
        if hi_cue_tone is None:  # case where lo_cue_tone should be enharmonic to cue_pitch.diatonic_tone
            if self.cue_pitch.chromatic_distance < DiatonicPitch(
                    octave, lo_cue_tone).chromatic_distance:
                octave = octave - 1
            elif self.cue_pitch.chromatic_distance > DiatonicPitch(
                    octave, lo_cue_tone).chromatic_distance:
                octave = octave + 1

            lo_cue_pitch = DiatonicPitch(octave, lo_cue_tone)
            f = ChromaticPitchReflectionFunction(secondary_tonality,
                                                 lo_cue_pitch,
                                                 self.domain_pitch_range)
        else:
            if DiatonicPitch(
                    octave, lo_cue_tone
            ).chromatic_distance > self.cue_pitch.chromatic_distance:
                octave = octave - 1
            lo_cue_pitch = DiatonicPitch(octave, lo_cue_tone)
            f = ChromaticPitchReflectionFunction(secondary_tonality,
                                                 lo_cue_pitch,
                                                 self.domain_pitch_range,
                                                 FlipType.LowerNeighborOfPair)

        #
        # Note: the above produces the same tonal function as TonalFunction.create_adapted_function
        #       The former uses a reversal based on the same cue scale index, while the latter
        #       would do that anyway by pickup up on the original note permutation derived from reflection_tests.
        #
        return f
Beispiel #7
0
    def test_melodic_minor_modality(self):
        print('Testing Melodic Minor Modality: C-MelodicMinor, cue=Eb:3')
        domain_tonality = Tonality.create(ModalityType.MelodicMinor, DiatonicFoundation.get_tone('C'))
        cue_pitch = DiatonicPitch.parse('Eb:3')

        domain_pitch_range = PitchRange.create('D:4', 'F:5')
        f = ChromaticPitchReflectionFunction(domain_tonality, cue_pitch, domain_pitch_range, FlipType.CenterTone)

        TestChromaticPitchReflectionFunction.print_function(f)

        assert 2 == f['D:4'].octave
        assert 2 == f['G:4'].octave
        assert 1 == f['A:4'].octave
        assert 1 == f['C:5'].octave
        assert 1 == f['f:5'].octave
Beispiel #8
0
    def test_natural_minor_modality(self):
        print('Testing Natural Minor Modality: C-Major, cue=Eb:3')
        domain_tonality = Tonality.create(ModalityType.NaturalMinor, DiatonicFoundation.get_tone('C'))
        cue_pitch = DiatonicPitch.parse('Eb:3')

        domain_pitch_range = PitchRange.create('D:2', 'F:4')
        f = ChromaticPitchReflectionFunction(domain_tonality, cue_pitch, domain_pitch_range, FlipType.CenterTone)

        TestChromaticPitchReflectionFunction.print_function(f)

        # Test for octave coverage
        assert 4 == f['D:2'].octave
        assert 3 == f['Bb:2'].octave
        assert 3 == f['C:3'].octave
        assert 2 == f['Bb:3'].octave
        assert 2 == f['F:4'].octave