示例#1
0
    def test_create(self):
        with self.assertRaises(Exception):
            PitchRange(8, 96)

        with self.assertRaises(Exception):
            PitchRange(9, 97)

        with self.assertRaises(Exception):
            PitchRange('Ab:0', 'C:8')

        with self.assertRaises(Exception):
            PitchRange.create('A:0', 'C#:8')
示例#2
0
    def compute_closest_scale_tones(tonality, pitch):
        """
        Returns either the pitch if in tonality, or lower/upper pitches in scale to pitch.
        :param tonality:
        :param pitch:
        :return: an array with 1 element if exact match, otherwise closest lower and upper bound pitches
                 in given tonality.
        """
        from tonalmodel.pitch_range import PitchRange
        chromatic_index = pitch.chromatic_distance
        pitch_range = PitchRange(
            max(chromatic_index - 12, ChromaticScale.chromatic_start_index()),
            min(chromatic_index + 12, ChromaticScale.chromatic_end_index()))
        pitch_scale = PitchScale(tonality, pitch_range)

        for i in range(0, len(pitch_scale.pitch_scale)):
            p = pitch_scale.pitch_scale[i]
            if p.chromatic_distance < chromatic_index:
                continue
            if p.chromatic_distance == chromatic_index:
                return [p]
            if i == 0:
                raise Exception(
                    'unexpected logic issue in compute_closest_pitch_range {0}, {1]'
                    .format(tonality, pitch))
            return [pitch_scale.pitch_scale[i - 1], p]
        raise Exception(
            'unexpected logic fail in compute_closest_pitch_range {0}, {1]'.
            format(tonality, pitch))
示例#3
0
    def test_for_book_example_2(self):
        print('----- test for book example 2 -----')

        source_instance_expression = '{<A-Major:i> [sA:4 A A A] qA:4 [iA:4 A] <:iv> qA:4 [sA:4 A A A] qA:4}'
        target_instance_expression = '{<G-Major:i> wA:4 <:iv> wA:4}'
        lge = LineGrammarExecutor()

        source_instance_line, source_instance_hct = lge.parse(
            source_instance_expression)

        actors = source_instance_line.get_all_notes()
        for a in actors:
            print("{0}".format(a))

        target_instance_line, target_instance_hct = lge.parse(
            target_instance_expression)
        target_hcs = target_instance_hct.hc_list()
        for hc in target_hcs:
            print("{0}".format(hc))

        pitch_range = PitchRange(
            DiatonicPitch.parse('C:4').chromatic_distance,
            DiatonicPitch.parse('C:6').chromatic_distance)

        p_map = PMap.create(source_instance_expression, pitch_range,
                            [('G-Major:I', Duration(3, 4)),
                             ('G-Major:IV', Duration(3, 4))])

        actors = p_map.actors

        policies = OrderedSet()
        policies.add(
            StepSequenceConstraint(
                [actors[0], actors[1], actors[2], actors[3]], [1, 1, 1]))
        policies.add(ChordalPitchConstraint(actors[0]))
        policies.add(ChordalPitchConstraint(actors[4]))
        policies.add(ChordalPitchConstraint(actors[8]))
        policies.add(
            StepSequenceConstraint(
                [actors[8], actors[9], actors[10], actors[11]], [1, -1, -1]))
        policies.add(EqualPitchConstraint([actors[0], actors[12]]))
        policies.add(EqualPitchConstraint([actors[4], actors[7]]))
        policies.add(
            RelativeDiatonicConstraint(actors[4], actors[5],
                                       Interval(3, IntervalType.Major),
                                       Interval(1, IntervalType.Perfect)))
        policies.add(StepSequenceConstraint([actors[5], actors[6]], [-1]))

        # policies.add(ChordalPitchConstraint(actors[7]))

        solver = PitchConstraintSolver(policies)

        full_results, partial_results = solver.solve(p_map)
        print('Results has {0} results.'.format(len(full_results)))

        for pm in full_results:
            if str(pm[actors[7]].note.diatonic_pitch) == 'D:4' and str(
                    pm[actors[0]].note.diatonic_pitch) == 'G:4':
                print("{0}".format(pm))
    def policy_creator(modality_type, modality_tone, tertian_chord_txt, low_pitch_txt, hi_pitch_txt):
        diatonic_tonality = Tonality.create(modality_type, modality_tone)
        chord = TertianChordTemplate.parse(tertian_chord_txt).create_chord(diatonic_tonality)
        hc = HarmonicContext(diatonic_tonality, chord, Duration(1, 2))

        pitch_range = PitchRange(DiatonicPitch.parse(low_pitch_txt).chromatic_distance,
                                 DiatonicPitch.parse(hi_pitch_txt).chromatic_distance)
        return PolicyContext(hc, pitch_range)
    def apply(self,
              target_hct,
              window_anchor_pitch,
              tag_map=None,
              window_height=None,
              num_solutions=-1,
              tunnel_half_interval=Interval(5, IntervalType.Perfect)):
        """
        Apply method for transformation.
        :param target_hct: Target hct for new target line.
        :param window_anchor_pitch: Pitch specifying the lowest pitch for the target line window.
        :param tag_map: map index of source/target note to specified pitch.
        :param window_height: Height of target pitch window (in semi-tones) - use source line height if None specified.
        :param num_solutions: Maximum number of solutions to return, -1 == unbounded.
        :param tunnel_half_interval: half-interval for pitch range on each target tone.
        :return: MCSResults
        """
        if self.source_hct.duration != target_hct.duration:
            raise Exception(
                'Target hct duration {0} does not match source hct duration {1}.'
                .format(target_hct.duration, self.source_hct.duration))

        window_anchor_pitch = DiatonicPitch.parse(window_anchor_pitch) if isinstance(window_anchor_pitch, str) \
            else window_anchor_pitch

        target_line = self._build_target_line()

        self.__tunnel_half_interval = tunnel_half_interval

        source_notes = self.source_line.get_all_notes()
        target_notes = target_line.get_all_notes()
        source_to_target = {
            source_note: target_note
            for source_note, target_note in zip(source_notes, target_notes)
        }

        constraints = self._build_constraints(source_to_target, tag_map)
        ts_seq, tempo_seq = THarmonicTranscription._build_default_time_sig_tempo(
        )

        height = window_height if window_height else self.height
        pitch_range = PitchRange(
            window_anchor_pitch.chromatic_distance,
            window_anchor_pitch.chromatic_distance + height)

        solver = MelodicConstraintSolver(target_line, tempo_seq, ts_seq,
                                         target_hct, pitch_range, constraints)

        initial_map = {target_notes[k]: v
                       for k, v in tag_map.items()} if tag_map else None
        results = solver.solve(initial_map, num_solutions)
        return results
示例#6
0
    def compute_result(self, arg_contextual_note, target_contextual_note,
                       up_intvl, down_intvl):
        """
        
        :param arg_contextual_note: 
        :param target_contextual_note: 
        :param up_intvl: 
        :param down_intvl: 
        :return: 
        """

        starting_pitch = arg_contextual_note.note.diatonic_pitch
        chromatic_distance_start = starting_pitch.chromatic_distance - down_intvl.chromatic_distance
        chromatic_distance_end = starting_pitch.chromatic_distance + up_intvl.chromatic_distance

        r_start = max(
            chromatic_distance_start,
            target_contextual_note.policy_context.pitch_range.start_index)
        r_end = min(
            chromatic_distance_end,
            target_contextual_note.policy_context.pitch_range.end_index)

        if r_start > r_end:
            return OrderedSet()

        pitch_range = PitchRange(r_start, r_end)
        pitch_scale = PitchScale(
            target_contextual_note.policy_context.harmonic_context.tonality,
            pitch_range)

        result = OrderedSet()
        for pitch in pitch_scale.pitch_scale:
            result.add(
                Note(pitch, self.note_two.base_duration,
                     self.note_two.num_dots))
        # v_result = {Note(pitch, self.note_two.base_duration, self.note_two.num_dots)
        #             for pitch in pitch_scale.pitch_scale}

        return result
示例#7
0
 def written_pitch_range(self):
     return PitchRange(self.written_low.chromatic_distance,
                       self.written_high.chromatic_distance)
示例#8
0
 def sounding_pitch_range(self):
     return PitchRange(self.sounding_low.chromatic_distance,
                       self.sounding_high.chromatic_distance)
    def values(self, p_map, v_note):
        """
        Compute possible values for v_note's target.
        :param p_map: note-->contextual_note
        :param v_note: Note
        :return: Candidate Notes.

        Note: Here is why the intervals are reversed for solving for note_one:
              Suppose x --> [x-a, x + b].  Then for some value y, 
              for t with y-b<=t<=y+a, we have t -->[t-a, t+b], but
              from the inequalities, t-a<=y<t+b - so the reverse map is
              [y-b, y+a] <-- y, which is exactly what happens below.
        """
        if v_note == self.note_two:
            source = self.note_one
            target = self.note_two
            comparative = self.comparative
        elif v_note == self.note_one:
            source = self.note_two
            target = self.note_one
            comparative = 4 - self.comparative
        else:
            raise Exception(
                'v_note specification does not match any v_note in constraints.'
            )

        if p_map[target].note is not None:
            return {p_map[target].note}

        if p_map[source].note is None:
            answer_range = p_map[target].policy_context.pitch_range
            source_pitch = None
        else:
            # Establish a pitch range commensurate with comparative.
            qrange = p_map[target].policy_context.pitch_range
            source_pitch = p_map[source].note.diatonic_pitch

            if comparative > 2:
                answer_range = PitchRange(qrange.start_index,
                                          source_pitch.chromatic_distance)
            elif comparative < 2:
                answer_range = PitchRange(source_pitch.chromatic_distance,
                                          qrange.end_index)
            else:
                answer_range = PitchRange(source_pitch.chromatic_distance,
                                          source_pitch.chromatic_distance)

        pitches = PitchScale.compute_tonal_pitches(
            p_map[target].policy_context.harmonic_context.tonality,
            answer_range)
        if comparative == 4 and len(pitches) > 0 and source_pitch is not None and \
                source_pitch.chromatic_distance == pitches[-1].chromatic_distance:
            pitches.pop(-1)
        if comparative == 0 and len(pitches) > 0 and source_pitch is not None and \
                source_pitch.chromatic_distance == pitches[0].chromatic_distance:
            del pitches[0]

        answer = OrderedSet()
        for pitch in pitches:
            answer.add(Note(pitch, target.base_duration, target.num_dots))
        return answer
示例#10
0
 def create_default(tonality):
     return PitchScale(
         tonality,
         PitchRange(ChromaticScale.chromatic_start_index(),
                    ChromaticScale.chromatic_end_index()))
示例#11
0
    def compute_tonal_pitch_range(tonality, pitch, lower_index, upper_index):
        """
        Find all pitches within range of tonality based on an arbitrary pitch given as starting point.
        In all cases, look at the closest pitches (1 or 2) as origin 0, and the lower/upper as counting indices
        below or up from them.
        :param tonality:
        :param pitch:
        :param lower_index:
        :param upper_index:
        :return:
        """
        import math
        from tonalmodel.pitch_range import PitchRange
        starting_points = PitchScale.compute_closest_scale_tones(
            tonality, pitch)

        # Determine the number of octaves that will cover the given range.
        up_chrom = max(
            0,
            int(
                math.ceil(float(abs(upper_index)) / len(tonality.annotation)) *
                12) * (-1 if upper_index < 0 else 1))
        down_chrom = min(
            0,
            int(
                math.ceil(float(abs(lower_index)) / len(tonality.annotation)) *
                12) * (-1 if lower_index < 0 else 1))

        # Compute all pitches within that range
        low = max(starting_points[0].chromatic_distance + down_chrom,
                  ChromaticScale.chromatic_start_index())
        high = min(
            (starting_points[0].chromatic_distance if len(starting_points) == 1
             else starting_points[1].chromatic_distance) + up_chrom,
            ChromaticScale.chromatic_end_index())

        pitch_range = PitchRange(low, high)
        pitch_scale = PitchScale(tonality, pitch_range).pitch_scale

        # The first starting point is either the enharmonic equivalent to pitch, or the lower scale pitch to the pitch.
        # lower_starting_index is the index in pitch_scale for that pitch.
        lower_starting_index = [
            index for index in range(0, len(pitch_scale))
            if pitch_scale[index].chromatic_distance ==
            starting_points[0].chromatic_distance
        ][0]

        if len(starting_points) == 1:
            full_range = range(
                lower_starting_index + lower_index,
                min(lower_starting_index + upper_index + 1, len(pitch_scale)))
            return [pitch_scale[i] for i in full_range]
        else:
            upper_starting_index = [
                index for index in range(0, len(pitch_scale))
                if pitch_scale[index].chromatic_distance ==
                starting_points[1].chromatic_distance
            ][0]
            lo = lower_index + (lower_starting_index
                                if lower_index <= 0 else upper_starting_index)
            hi = upper_index + (lower_starting_index
                                if upper_index < 0 else upper_starting_index)
            full_range = range(lo, hi + 1)
            return [pitch_scale[i] for i in full_range]