Пример #1
0
    def values(self, p_map, v_note):
        if v_note != self.actor_note:
            raise Exception('v_note {0} not in ScalarConstraint actors.'.format(v_note.note))

        policy_context = p_map[self.actor_note].policy_context
        tones = list(policy_context.harmonic_context.tonality.annotation)
        tones = tones[:-1]   # remove final note (same as first)
        if len(self.scalar_roles) != 0:
            tones = [tones[i] for i in self.scalar_roles]
        if p_map[v_note].note is not None:
            tone = p_map[v_note].note.diatonic_pitch.diatonic_tone
            return OrderedSet([self.actor_note]) if tone in tones else None

        pitch_range = 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])

        valid_set = OrderedSet()

        for tone in tones:
            for j in range(start_partition, end_partition + 1):
                pitch = DiatonicPitch(j, 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
Пример #2
0
    def _build_p_map_dict(self, partial_pitch_results=None):
        actors = OrderedSet()
        for p in self.pitch_constraints:
            actors = actors.union(p.actors)

        d = OrderedDict()
        for note in actors:
            hc = self.hct[note.get_absolute_position().position]
            if hc is None:
                raise Exception(
                    'Cannot locate harmonic context for note \'{0}\''.format(
                        note))
            contextual = ContextualNote(PolicyContext(hc, self.pitch_range))
            d[note] = contextual

        if partial_pitch_results is not None:
            for k, v in partial_pitch_results.items():
                if not isinstance(k, Note):
                    raise Exception(
                        'key of partial_pitch_results must be a Note.')
                if not isinstance(v, DiatonicPitch):
                    raise Exception(
                        'value of partial_pitch_results must be a DiatonicPitch.'
                    )
                if k not in d:
                    raise Exception(
                        'Note \'{0}\' of partial result is not a constraint actor.'
                        .format(k))
                d[k].note = Note(v, k.base_duration, k.num_dots)

        return d
Пример #3
0
    def values(self, p_map, v_note):
        if v_note != self.actor_note:
            raise Exception("Illegal v_note {0} for constraint".format(v_note))
        if p_map[v_note].note is not None:
            if p_map[v_note].note.diatonic_pitch.chromatic_distance in (p.chromatic_distance for p in self.pitches):
                return OrderedSet[p_map[v_note].note]
            raise Exception('Fixed Pitch Select Set Constraint Violated has {0} not in pitch set'.format(
                p_map[v_note].note.diatonic_pitch))

        # Return all pitches (self.pitches) except though, for each
        # select a representation closest to the target tonality, if it exists.
        tonality = p_map[self.actor_note].policy_context.harmonic_context.tonality
        result_pitches = []
        for pitch in self.pitches:
            found_pitch = pitch
            for p in pitch.enharmonics():
                if p.diatonic_tone in tonality.annotation:
                    found_pitch = p
                    break
            result_pitches.append(found_pitch)

        result = OrderedSet()
        for p in result_pitches:
            result.add(Note(p, self.actor_note.base_duration, self.actor_note.num_dots))
        return result
Пример #4
0
    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
Пример #5
0
    def values(self, p_map, v_target_note):
        if v_target_note == self.note_two:
            up_down = self.up_down
            v_source_note = self.note_one
        elif v_target_note == self.note_one:
            up_down = not self.up_down
            v_source_note = self.note_two
        else:
            raise Exception(
                'v_note specification does not match any v_note in constraints.'
            )

        if p_map[v_target_note].note is not None:
            return OrderedSet([p_map[v_target_note].note])

        arg_contextual_note = p_map[v_source_note]
        target_contextual_note = p_map[v_target_note]

        if arg_contextual_note.note is None:
            pitches = p_map.all_tonal_pitches(v_target_note)
            result = OrderedSet()
            for p in pitches:
                result.add(
                    Note(p, v_target_note.base_duration,
                         v_target_note.num_dots))
            return result

        return self.compute_result(arg_contextual_note, target_contextual_note,
                                   up_down)
Пример #6
0
    def test_copy(self):
        s = OrderedSet()
        for i in range(1, 10):
            to = TestObject(i)
            s.add(to)

        s1 = s.copy()
        assert id(s1) != id(s)

        objects = [t.ord_value() for t in s1]
        assert objects == [1, 2, 3, 4, 5, 6, 7, 8, 9]
Пример #7
0
    def compute_full_result(p_map, v_note, e_set):
        pitches = p_map.all_tonal_pitches(v_note)
        e_chrm_list = [n.diatonic_pitch.chromatic_distance for n in e_set]
        del_set = OrderedSet()
        for p in pitches:
            if p.chromatic_distance in e_chrm_list:
                del_set.add(p)

        pitches = [p for p in pitches if p not in del_set]

        return OrderedSet([Note(p, v_note.base_duration, v_note.num_dots) for p in pitches])
Пример #8
0
 def _candidate_closure(self, p_map, v_note):
     """
     Find all policies that have v_note as a parameter, and collect their unassigned actors into a set
     without replication.
     :param p_map: PMap
     :param v_note: ContextualNote
     :return: 
     """
     policies = self.v_policy_map[v_note]
     candidates = OrderedSet()
     for p in policies:
         candidates = candidates.union(p_map.unassigned_actors(p))
     return candidates
    def compute_result(self, arg_contextual_note, target_contextual_note,
                       down_steps, up_steps):
        arg_pitch = arg_contextual_note.note.diatonic_pitch

        pitches = PitchScale.compute_tonal_pitch_range(
            target_contextual_note.policy_context.harmonic_context.tonality,
            arg_pitch, down_steps, up_steps)

        result = OrderedSet()
        for pitch in pitches:
            result.add(
                Note(pitch, self.note_two.base_duration,
                     self.note_two.num_dots))

        return result
Пример #10
0
    def values(self, p_map, v_note):
        """
        Compute possible values for v_note's target.
        :param p_map: 
        :param v_note: 
        :return: 
        
        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
            up_intvl = self.up_interval
            down_intvl = self.down_interval
        elif v_note == self.note_one:
            source = self.note_two
            target = self.note_one
            up_intvl = self.down_interval
            down_intvl = self.up_interval
        else:
            raise Exception(
                'v_note specification does not match any v_note in constraints.'
            )

        if p_map[target].note is not None:
            return OrderedSet([p_map[target].note])

        arg_contextual_note = p_map[source]
        target_contextual_note = p_map[target]

        if arg_contextual_note.note is None:
            pitches = p_map.all_tonal_pitches(v_note)
            result = OrderedSet()
            for p in pitches:
                result.add(Note(p, v_note.base_duration, v_note.num_dots))
            return result
            # return {Note(p, v_note.base_duration, v_note.num_dots) for p in pitches}

        return self.compute_result(arg_contextual_note, target_contextual_note,
                                   up_intvl, down_intvl)
Пример #11
0
    def values(self, p_map, v_note):
        assigned = p_map.assigned_actors(self)
        unassigned = p_map.unassigned_actors(self)
        if v_note in unassigned:
            tonality = p_map[v_note].policy_context.harmonic_context.tonality
            pitches = PitchScale.compute_tonal_pitches(tonality,
                                                       self.pitch_range)
            answer = OrderedSet()
            for p in pitches:
                answer.add(Note(p, v_note.base_duration, v_note.num_dots))
            return answer
            # return {Note(p, v_note.base_duration, v_note.num_dots) for p in pitches}

        if v_note in assigned:
            return OrderedSet([p_map[v_note].note])

        raise Exception(
            '{0} is not in actor list for pitch range constraints.'.format(
                v_note.note))
Пример #12
0
    def test_union(self):
        s1 = OrderedSet()
        for i in range(1, 10):
            s1.add(TestObject(i))

        s2 = OrderedSet()
        for i in range(100, 110):
            to = TestObject(i)
            s2.add(to)

        s = s1.union(s2)
        objects = [t.ord_value() for t in s]
        assert objects == [
            1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 101, 102, 103, 104, 105, 106, 107,
            108, 109
        ]
Пример #13
0
    def values(self, pdi, note):
        position = pdi.correct_position(
            note.get_absolute_position())  # position should be adjusted
        ts = pdi.ts_event_sequence.floor_event(position).object
        beat_position = TimeConversion(pdi.tempo_event_sequence, pdi.ts_event_sequence, Position(pdi.line_duration())).\
            position_to_bp(position)
        num_beats = ts.beats_per_measure if beat_position.beat_fraction > 0 else ts.beats_per_measure - 1
        beat_index = (beat_position.beat + 1) % ts.beats_per_measure
        delta_t = ts.beat_duration if beat_position.beat_fraction == 0 else \
            ts.beat_duration * (1 - beat_position.beat_fraction)

        deltas = OrderedSet()
        for i in range(0, num_beats):
            if (self.beat_ids is not None and beat_index in self.beat_ids) or \
               (self.beat_type is not None and self.beat_type == ts.beat_type(beat_index)):
                deltas.add(delta_t)
            delta_t += ts.beat_duration
            beat_index = (beat_index + 1) % ts.beats_per_measure

        return deltas
Пример #14
0
    def test_remove(self):
        s = OrderedSet()
        fone = None
        fmid = None
        flast = None
        for i in range(1, 10):
            item = TestObject(i)
            if i == 1:
                fone = item
            elif i == 6:
                fmid = item
            elif i == 9:
                flast = item
            s.add(item)

        s.remove(fmid)
        s.remove(flast)
        s.remove(fone)
        objects = [t.ord_value() for t in s]
        assert objects == [2, 3, 4, 5, 7, 8]
Пример #15
0
    def values(self, p_map, v_note):
        """
        Return a set of possible pitches that v_note can take that must be in p_map target's chord.
        :param p_map: 
        :param v_note: 
        :return: 
        """
        if v_note != self.actor_note:
            raise Exception(
                'v_note {0} not in ChordalToneConstraint actors.'.format(
                    v_note.note))

        policy_context = p_map[self.actor_note].policy_context
        tones = policy_context.harmonic_context.chord.tones
        if p_map[v_note].note is not None:
            note = p_map[v_note].note
            if note.diatonic_pitch.diatonic_tone in tones:
                return {note}
            raise Exception(
                'Chordal Pitch Policy Violated has {0} should be member of chord {1}'
                .format(p_map[v_note].note.diatonic_pitch,
                        policy_context.harmonic_context.chord))

        pitch_range = 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])

        valid_set = OrderedSet()
        for tone in tones:
            for i in range(start_partition, end_partition + 1):
                pitch = DiatonicPitch(i, tone[0])
                if pitch_range.is_pitch_inbounds(str(pitch)):
                    note = Note(pitch, self.actor_note.base_duration,
                                self.actor_note.num_dots)
                    valid_set.add(note)

        return valid_set
Пример #16
0
    def values(self, p_map, v_note):
        if v_note != self.actor_note:
            raise Exception("Illegal v_note {0} for constraint".format(v_note))
        if p_map[v_note].note is not None:
            if p_map[
                    v_note].note.diatonic_pitch.chromatic_distance == self.pitch.chromatic_distance:
                return OrderedSet([p_map[v_note].note])
            raise Exception(
                'Fixed Pitch Constraint Violated has {0} should be {1}'.format(
                    p_map[v_note].note.diatonic_pitch, self.pitch))

        # select a pitch representation closest to the target tonality, if it exists.
        policy_context = p_map[self.actor_note].policy_context
        pitch = self.pitch
        for p in self.pitch.enharmonics():
            if p.diatonic_tone in policy_context.harmonic_context.tonality.annotation:
                pitch = p
                break

        actual_note = Note(pitch, self.actor_note.base_duration,
                           self.actor_note.num_dots)
        return OrderedSet([actual_note])
Пример #17
0
    def _policy_values(self, p_map, v_note):
        """
        For v_note, find all note values for its target that satisfy all policies in which v_note is involved.
        :param p_map: PMap
        :param v_note: ContextualNote
        :return: A set of notes with same duration as v_note, varying in pitch.
        """
        pitches = None
        for p in self.v_policy_map[v_note]:
            p_values = p.values(p_map, v_note)
            if p_values is None:
                returned_pitches = OrderedSet()  # None means p cannot be satisfied!
            else:
                returned_pitches = OrderedSet()
                for n in p_values:
                    returned_pitches.add(n.diatonic_pitch)
            pitches = returned_pitches if pitches is None else pitches.intersection(returned_pitches)

        retset = OrderedSet()
        for p in pitches:
            retset.add(Note(p, v_note.base_duration, v_note.num_dots))
        return retset
Пример #18
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
Пример #19
0
    def values(self, p_map, v_note):
        """
        Find value candidates for v_note target, given p_map.
        In this constraints, we are more interested in the set of values that v_note target cannot take.
        
        :param p_map: 
        :param v_note: 
        :return: 
        """
        assigned = p_map.assigned_actors(self)
        unassigned = p_map.unassigned_actors(self)
        if len(assigned) == 0:
            pitches = p_map.all_tonal_pitches(v_note)
            return {Note(p, v_note.note.base_duration, v_note.note.num_dots) for p in pitches}
        if v_note in assigned:
            return {p_map[v_note].note}
        if v_note not in unassigned:
            raise Exception('{0} is not in actor list of not equal pitch constraints.'.format(v_note.note))

        e_set = OrderedSet()
        for v in assigned:
            e_set.add(p_map[v].note)

        return NotEqualPitchConstraint.compute_full_result(p_map, v_note, e_set)
Пример #20
0
    def __init__(self, policies):
        """
        Constructor.
        
        :param policies: non-null set of policies
        """
        if policies is None or (not isinstance(policies, set) and not isinstance(policies, list) and
                                not isinstance(policies, OrderedSet)):
            raise Exception('Policies must be non-null and a Set')

        self._policies = OrderedSet(policies)

        self.v_policy_map = dict()
        self._build_v_policy_map()

        self.__instance_limit = 0
        self.__num_instances = 0
        self.__full_results = list()
Пример #21
0
    def compute_note(p_map, assigned_note, unassigned_note):
        """
        For an assigned note and an unassigned note, return for unassigned, a note the same as assigned, but with
        pitch enharmonic to its tonality.
        :param p_map: 
        :param assigned_note: 
        :param unassigned_note: 
        :return: 
        """

        # select a pitch representation closest to the tonality, if it exists.
        policy_context = p_map[unassigned_note].policy_context
        pitch = p_map[assigned_note].note.diatonic_pitch
        for p in pitch.enharmonics():
            for t in PitchScale(policy_context.harmonic_context.tonality,
                                policy_context.pitch_range).tone_scale:
                if p.diatonic_tone == t:
                    pitch = p
                    break

        actual_note = Note(pitch, unassigned_note.base_duration,
                           unassigned_note.num_dots)
        return OrderedSet([actual_note])
Пример #22
0
    def compute_result(self, arg_contextual_note, target_contextual_note,
                       up_down):
        """
        Compute the target note from the arg note basecd on up_down and self.n_steps.
        
        :param arg_contextual_note: Given note
        :param target_contextual_note: Note to find based on constraints.
        :param up_down: 
        :return: 
        """
        if str(arg_contextual_note.policy_context.harmonic_context.tonality) != \
                str(target_contextual_note.policy_context.harmonic_context.tonality):
            raise Exception(
                'Note one and two of tonal step constraints must match on tonality'
            )

        starting_pitch = arg_contextual_note.note.diatonic_pitch

        pitch_scale = PitchScale(
            target_contextual_note.policy_context.harmonic_context.tonality,
            target_contextual_note.policy_context.pitch_range)
        scale = pitch_scale.pitch_scale
        pitch_index = scale.index(
            starting_pitch) if starting_pitch in scale else None
        if pitch_index is None:
            return None

        end_index = pitch_index + (
            self.n_steps * (1 if up_down == PitchStepConstraint.UP else -1))
        if end_index not in range(0, len(scale)):
            return None

        end_pitch = scale[end_index]
        return OrderedSet([
            Note(end_pitch, self.note_two.base_duration,
                 self.note_two.num_dots)
        ])
Пример #23
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))
Пример #24
0
    def _visit(self, p_map, v_note):
        """
        Recursive method used to derive sets of solution to the constraints constraint problem.

        :param p_map: PMap
        :param v_note: ContextualNote, source key of PMap
        :return: A set of pmaps
        """

        if p_map[v_note].note is not None:  # setting means visited
            return {}

        results = OrderedSet()

        # list of tuples (v_note, {solution to v_note's policies})
        result_values = self._build_potential_values(p_map, {v_note})
        if len(result_values) == 0:
            return results

        for value in result_values[0][1]:  # [0] is for v_note; [1] is the set of values.
            p_map[v_note].note = value
            value_results = OrderedSet()  # results for this value for v_note + solutions for ALL peers to v_note

            # Advantage in the following, setting above partially solves each policy v_note is involved in.
            # For this 'value' for v_note, dive depth first through all v_note peers (all policies v_note is in)
            #    which collectively we call a branch.
            # peer_candidates are all unassigned actors in v_note's policies.
            peer_candidates = self._candidate_closure(p_map, v_note)
            if len(peer_candidates) == 0:

                # We reached the end of a branch, save the result.
                if self._full_check_and_validate(p_map):
                    if self.instance_limit != -1 and self.__num_instances >= self.instance_limit:
                        return results
                    self.full_results.append(p_map.replicate())
                    self.__num_instances = self.__num_instances + 1
                else:
                    value_results.add(p_map.replicate())  # We only need a shallow copy

            else:
                for c_note in peer_candidates:
                    if self.instance_limit != -1 and self.__num_instances >= self.instance_limit:
                        results = results.union(value_results)
                        return results

                    if len(value_results) == 0:  # first time through this loop per value, visit with p_map!
                        value_results = self._visit(p_map, c_note)
                        if len(value_results) == 0:  # Indicates failure to assign c_note, move to next value.
                            break  # If one peer fails, they all will, for this 'value'!
                    else:
                        value_results_copy = value_results.copy()
                        # for peer c_note, if all r below fails (len(cand_results) == 0) should we also move on to
                        # next value? Add 'found' flag, set after union, after loop, check if False, to break
                        found = False
                        for r in value_results_copy:
                            if r[c_note].note is None:
                                cand_results = self._visit(r, c_note)
                                if len(cand_results) != 0:
                                    value_results = value_results.union(cand_results)
                                    found = True
                                value_results.remove(r)  # r has no c_note assigned, what was returned did!
                                # If not, r's peers cannot be assigned!
                        if found is False:  # Same as if part, if c_note produces no results, it cannot be assigned.
                            break  # If one peer fails, they all will!
            results = results.union(value_results)

        p_map[v_note].note = None
        return results
Пример #25
0
 def test_ordering(self):
     s1 = OrderedSet()
     for i in range(1, 10):
         s1.add(TestObject(i))
     objects = [t.ord_value() for t in s1]
     assert objects == [1, 2, 3, 4, 5, 6, 7, 8, 9]
Пример #26
0
    def test_constructor(self):
        s = OrderedSet([1, 2, 3, 4, 5])
        items = [item for item in s]

        assert items == [1, 2, 3, 4, 5]
Пример #27
0
    def _compute_values(self, v_note, hc):
        """
        The core pitch computation used in the values() method.
        :param v_note:
        :param hc:
        :return:

        Notes:

        The key for the new constraint is the call to 'eval_as_pitch', which returns one or two pitches nearest to the
        reshape curve.

        Case 1: Exactly one pitch.
        If pitch is scalar, use
        If pitch is non-scalar - if on-beat and pitch is 1/2 step from any chordal tone, do not use, else use

        Case 2: Two notes
        If both are scalar, use the closest to the curve.
        If both are non-scalar, use the nearest to curve, and apply as in case 1   (example, A, Bb in C-)
        If one is scalar and the other not:
           If the scalar is on-beat or is within the scalar bias weight, use it
           Otherwise use the non-scalar
        """

        self.candidate_pitches = list()
        for p in self.pitch_function.eval_as_pitch(self.note_position.position):
            e = FitPitchToFunctionConstraint._get_tonal_equivalent(p, hc)
            self.candidate_pitches.append((e, True) if e is not None else (p, False))

        if len(self.candidate_pitches) == 0:
            return OrderedSet()

        v_note_beat_position = self._get_beat_position(v_note.get_absolute_position())

        # If one solution pitch
        if len(self.candidate_pitches) == 1:
            # if is scalar, use it
            if self.candidate_pitches[0][1]:
                return OrderedSet([Note(self.candidate_pitches[0][0], v_note.base_duration, v_note.num_dots)])
            # non-scalar
            # if on beat and half step off from chord tone, do not use
            if v_note_beat_position is not None and v_note_beat_position == BeatType.Strong:
                if FitPitchToFunctionConstraint._pitch_is_halfstep_off_chord(self.candidate_pitches[0][0], hc):
                    return set()
            # otherwise use
            return OrderedSet([Note(self.candidate_pitches[0][0], v_note.base_duration, v_note.num_dots)])

        # if 2 pitch solution
        if len(self.candidate_pitches) == 2:
            # If both scalar
            if self.candidate_pitches[0][1] and self.candidate_pitches[1][1]:
                interp = self.pitch_function.pitch_range_interpreter
                index = min(enumerate(self.candidate_pitches),
                            key=lambda x: abs(interp.value_for(x[1][0]) - self.function_value))[0]
                # return pitch closest to curve value
                return OrderedSet([Note(self.candidate_pitches[index][0], v_note.base_duration, v_note.num_dots)])
            elif not self.candidate_pitches[0][1] and not self.candidate_pitches[1][1]:
                index = min(enumerate(self.candidate_pitches),
                            key=lambda x: abs(interp.value_for(x[1][0]) - self.function_value))[0]
                pitch = self.candidate_pitches[index]
                # if on beat and half step off from chord tone, do not use
                if v_note_beat_position is not None:
                    if FitPitchToFunctionConstraint._pitch_is_halfstep_off_chord(pitch[0], hc):
                        return OrderedSet()
                # otherwise use
                return OrderedSet([Note(pitch[0], v_note.base_duration, v_note.num_dots)])
            else:
                scalar_pitch = self.candidate_pitches[0][0] if self.candidate_pitches[0][1] \
                    else self.candidate_pitches[1][0]
                nonscalar_pitch = self.candidate_pitches[0][0] if self.candidate_pitches[1][1] \
                    else self.candidate_pitches[1][0]
                scalar_bias = (scalar_pitch.chromatic_distance - self.function_value) /\
                    abs(scalar_pitch.chromatic_distance - nonscalar_pitch.chromatic_distance)
                if v_note_beat_position is not None or scalar_bias <= FitPitchToFunctionConstraint.SCALAR_BIAS_WEIGHT:
                    return OrderedSet([Note(scalar_pitch, v_note.base_duration, v_note.num_dots)])
                else:
                    return OrderedSet([Note(nonscalar_pitch, v_note.base_duration, v_note.num_dots)])
        else:
            raise Exception('Internal error - more than 2 candidate pitches.')
Пример #28
0
    def values(self, p_map, v_note):
        """

        :param p_map:
        :param v_note:
        :return:
        """

        index = self.actors.index(v_note) if v_note in self.actors else None
        if index is None:
            raise Exception('Cannot find v_note in constraints actors')

        if p_map[v_note].note is not None:
            return OrderedSet([p_map[v_note].note])

        # find the first assigned note
        assigned_index = None
        for i in range(0, len(self.actors)):
            if p_map[self.actors[i]].note is not None:
                assigned_index = i
                break

        if assigned_index is None:
            pitches = p_map.all_tonal_pitches(v_note)
            return OrderedSet([Note(p, v_note.base_duration, v_note.num_dots) for p in pitches])

        known_note = p_map[self.actors[assigned_index]].note
        if assigned_index < index:
            for i in range(assigned_index + 1, index + 1):
                unknown_contextual_note = p_map[self.actors[i]]
                unknown_note = unknown_contextual_note.note
                if unknown_note is not None:
                    known_note = unknown_note
                    continue

                lower_index = self.variance_list[i - 1] if self.variance_list[i - 1] < 0 else 0
                upper_index = self.variance_list[i - 1] if self.variance_list[i - 1] > 0 else 0
                pitches = PitchScale.compute_tonal_pitch_range(
                    unknown_contextual_note.policy_context.harmonic_context.tonality,
                    known_note.diatonic_pitch, lower_index, upper_index)
                pitch_index = self.variance_list[i - 1] + (len(pitches) - 1 if self.variance_list[i - 1] < 0 else 0)
                if pitch_index < 0 or pitch_index >= len(pitches):
                    if pitches is None or len(pitches) == 0:
                       return OrderedSet()
                    pitch = pitches[0] if pitch_index < 0 else pitches[len(pitches) - 1]
                else:
                    pitch = pitches[pitch_index]
                known_note = Note(pitch, self.actors[i].base_duration, self.actors[i].num_dots)
            return OrderedSet([known_note])

        for i in range(assigned_index - 1, index - 1, -1):
            unknown_contextual_note = p_map[self.actors[i]]
            unknown_note = unknown_contextual_note.note
            if unknown_note is not None:
                known_note = unknown_note
                continue

            upper_index = -self.variance_list[i] if self.variance_list[i] < 0 else 0
            lower_index = -self.variance_list[i] if self.variance_list[i] > 0 else 0
            pitches = PitchScale.compute_tonal_pitch_range(
                unknown_contextual_note.policy_context.harmonic_context.tonality,
                known_note.diatonic_pitch, lower_index, upper_index)
            pitch_index = -self.variance_list[i] + (len(pitches) - 1 if self.variance_list[i] > 0 else 0)
            if pitch_index < 0:
                pitch_index = 0
            elif pitch_index >= len(pitches):
                pitch_index = len(pitches) - 1
            pitch = pitches[pitch_index]
            known_note = Note(pitch, self.actors[i].base_duration, self.actors[i].num_dots)
        return OrderedSet([known_note])
    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