コード例 #1
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
コード例 #2
0
    def _build_primary_map(self):
        domain_scale = self.domain_tonality.annotation[:-1]

        tonal_map = dict()
        if self.reflect_type == FlipType.CenterTone:
            for tone in domain_scale:
                interval = Interval.calculate_tone_interval(tone, self.cue_tone)
                end_tone = interval.get_end_tone(self.cue_tone)
                tonal_map[tone] = end_tone
        else:
            if self.reflect_type == FlipType.LowerNeighborOfPair:
                lower_index = domain_scale.index(self.cue_tone)
                upper_index = (lower_index + 1) % len(domain_scale)
            else:
                upper_index = domain_scale.index(self.cue_tone)
                lower_index = (upper_index - 1) % len(domain_scale)
            tonal_map[domain_scale[upper_index]] = domain_scale[lower_index]
            tonal_map[domain_scale[lower_index]] = domain_scale[upper_index]

            last_lower = domain_scale[lower_index]
            last_upper = domain_scale[upper_index]
            for i in list(reversed(range(0, lower_index))):
                new_lower = domain_scale[i]
                interval = Interval.calculate_tone_interval(new_lower, last_lower)
                new_upper = interval.get_end_tone(last_upper)
                tonal_map[new_lower] = new_upper
                last_lower = new_lower
                last_upper = new_upper

            last_lower = domain_scale[lower_index]
            last_upper = domain_scale[upper_index]
            for i in list(range((upper_index + 1), len(domain_scale))):
                new_upper = domain_scale[i]
                interval = Interval.calculate_tone_interval(last_upper, new_upper)
                new_lower = interval.negation().get_end_tone(last_lower)
                tonal_map[new_upper] = new_lower
                last_lower = new_lower
                last_upper = new_upper

        range_tones = list(reversed([tonal_map[tone] for tone in domain_scale]))
        first_tone = range_tones[-1]
        range_tones = [first_tone] + range_tones[:-1]

        # Determine the tonality of the range
        range_tonality = Tonality.find_tonality(range_tones)

        return tonal_map, range_tonality
コード例 #3
0
ファイル: melodic_search.py プロジェクト: dpazel/music_rep
 def compute_chord_degree(hc):
     if hc.chord.chord_template.diatonic_basis is None:
         return hc.chord.chord_template.scale_degree
     else:
         interval = Interval.calculate_tone_interval(
             hc.tonality.diatonic_tone,
             hc.chord.chord_template.diatonic_basis)
         return interval.diatonic_distance + 1
コード例 #4
0
    def _build_shift_function(self, hc):
        if hc in self.hc_pitch_function_map.keys():  # reuse
            return self.hc_pitch_function_map[hc]

        if not isinstance(hc.chord, SecondaryChord):
            f = CrossTonalityShiftPitchFunction(
                hc.tonality, self.domain_pitch_range, self.root_shift_interval,
                self.range_modality_type, self.modal_index
                if self.modal_index is not None else hc.tonality.modal_index)
            range_tonality = f.range_tonality
        else:
            if self.root_shift_interval:
                range_tonality = Tonality.create(
                    self.range_modality_type if self.range_modality_type
                    is not None else hc.tonality.modality_type,
                    self.root_shift_interval.get_end_tone(
                        hc.tonality.diatonic_tone), self.modal_index if
                    self.modal_index is not None else hc.tonality.modal_index)
            else:
                range_tonality = hc.tonality

            # Range tone is the tone from the denominator, e.g. the ii in V/ii.
            range_tone = range_tonality.annotation[
                hc.chord.chord_template.secondary_scale_degree - 1]

            root_tone_interval = TonalInterval.calculate_tone_interval(hc.chord.secondary_tonality.root_tone,
                                                                       range_tone) \
                if not TonalInterval.is_negative(self.root_shift_interval) else  \
                -TonalInterval.calculate_tone_interval(range_tone, hc.chord.secondary_tonality.root_tone)

            f = CrossTonalityShiftPitchFunction(
                hc.chord.secondary_tonality, self.domain_pitch_range,
                root_tone_interval, hc.chord.secondary_tonality.modality_type,
                hc.chord.secondary_tonality.modal_index)
        self.hc_pitch_function_map[hc] = (f, range_tonality)
        return f, range_tonality
コード例 #5
0
    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
コード例 #6
0
ファイル: melodic_search.py プロジェクト: dpazel/music_rep
    def notes_compare(pattern_annotation, note, hc, search_options):
        pattern_note = pattern_annotation.note
        if pattern_note.duration != note.duration:
            return False
        if pattern_note.diatonic_pitch is None and note.diatonic_pitch is None:
            return True
        if (pattern_note.diatonic_pitch is None and note.diatonic_pitch is not None) or \
                (pattern_note.diatonic_pitch is not None and note.diatonic_pitch is None):
            return False
        target_pitch_scalar_degree = MelodicSearch.compute_scale_degree(
            note.diatonic_pitch, hc)
        target_chord_interval = MelodicSearch.compute_chord_interval(hc, note)

        if search_options.note_match_chordal:
            if pattern_annotation.is_chordal:
                if target_chord_interval is None:
                    return False
                if search_options.note_match_chordal_precision:
                    return pattern_annotation.chord_interval.diatonic_distance == \
                           target_chord_interval.diatonic_distance
                return True

        if pattern_annotation.is_scalar:
            if target_pitch_scalar_degree is not None:
                if search_options.note_match_scalar_precision:
                    return pattern_annotation.scale_degree == target_pitch_scalar_degree
                return True
            return False

        # Pattern note is non-scalar
        if target_pitch_scalar_degree is not None:  # Target is scalar
            return search_options.note_match_non_scalar_to_scalar
        # Target pitch is non-scalar
        if not search_options.note_match_non_scalar_precision:
            return True

        target_note_interval = \
            Interval.calculate_tone_interval(hc.tonality.root_tone, note.diatonic_pitch.diatonic_tone)
        if target_note_interval.diatonic_distance != pattern_annotation.root_based_interval.diatonic_distance:
            return False
        return True
コード例 #7
0
ファイル: diatonic_modality.py プロジェクト: dpazel/music_rep
    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
コード例 #8
0
    def _build_extension_map(self):
        ltrs = 'CDEFGAB'
        extension = dict()

        domain_scale = self.domain_tonality.annotation[:-1]
        domain_start_index = ltrs.index(domain_scale[0].diatonic_letter)
        domain_index_list = list(ltrs[domain_start_index:] + ltrs[:domain_start_index])

        # One time calculations based on lower upper
        if self.reflect_type != FlipType.CenterTone:
            if self.reflect_type == FlipType.LowerNeighborOfPair:
                lower_domain_index = domain_scale.index(self.cue_tone)
                upper_domain_index = (lower_domain_index + 1) % len(domain_scale)
            else:
                upper_domain_index = domain_scale.index(self.cue_tone)
                lower_domain_index = (upper_domain_index - 1) % len(domain_scale)
            lower_tone = domain_scale[lower_domain_index]
            upper_tone = domain_scale[upper_domain_index]
            lower_ltr_index = domain_index_list.index(lower_tone.diatonic_letter)
            lower_augmentation = lower_tone.augmentation_offset
            upper_ltr_index = domain_index_list.index(upper_tone.diatonic_letter)
            upper_augmentation = upper_tone.augmentation_offset
        else:
            lower_tone = None
            upper_tone = None
            lower_ltr_index = None
            lower_augmentation = None
            upper_ltr_index = None
            upper_augmentation = None

        for ltr in 'CDEFGAB':
            for aug in ['bb', 'b', '', '#', "##"]:
                tone = DiatonicFoundation.get_tone(ltr + aug)
                if tone not in self.tonal_map.keys():
                    if self.reflect_type == FlipType.CenterTone:
                        interval = Interval.calculate_tone_interval(tone, self.cue_tone)
                        if interval:  # Some intervals are illegal, eg Cbb --> C, for now ignore
                            end_tone = interval.get_end_tone(self.cue_tone)
                            extension[tone] = end_tone
                    else:

                        tone_ltr_index = domain_index_list.index(tone.diatonic_letter)
                        tone_augmentation = tone.augmentation_offset
                        if tone_ltr_index >= 0 and (tone_ltr_index < lower_ltr_index or
                                                    (tone_ltr_index == lower_ltr_index and
                                                     tone_augmentation <= lower_augmentation)):
                            interval = Interval.calculate_tone_interval(tone, lower_tone)
                            if interval:
                                upper = interval.get_end_tone(upper_tone)
                                extension[tone] = upper
                        elif tone_ltr_index < len(domain_index_list) and (tone_ltr_index > upper_ltr_index or
                                                                          (tone_ltr_index == upper_ltr_index and
                                                                           tone_augmentation >= upper_augmentation)):
                            interval = Interval.calculate_tone_interval(tone, upper_tone)
                            if interval:
                                new_lower = interval.get_end_tone(lower_tone)
                                extension[tone] = new_lower
                        else:   # Between the two limits
                            upper_interval = Interval.calculate_tone_interval(tone, upper_tone)
                            lower_interval = Interval.calculate_tone_interval(lower_tone, tone)
                            if upper_interval is None and lower_interval is None:
                                continue
                            elif upper_interval is None:
                                extension[tone] = upper_tone
                            elif lower_interval is None:
                                extension[tone] = lower_tone
                            else:
                                if abs(lower_interval.chromatic_distance) <= abs(upper_interval.chromatic_distance):
                                    extension[tone] = lower_interval.negation().get_end_tone(upper_tone)
                                else:
                                    extension[tone] = upper_interval.negation().get_end_tone(lower_tone)

        return extension