示例#1
0
def test_proper_leaps(obj):
    # breaking this rule is too advanced for you
    unnested_antecedent = Voice.merge_lists(*obj.nested_scale_degrees[:8])
    unnested_consequent = Voice.merge_lists(*obj.nested_scale_degrees[8:])
    proper_antecedent_leaps = Voice.has_proper_leaps(unnested_antecedent)
    proper_consequent_leaps = Voice.has_proper_leaps(unnested_consequent)
    if not (proper_antecedent_leaps and proper_consequent_leaps):
        return False

    ante_cons_transition = Voice.merge_lists(*obj.nested_scale_degrees[5:10])
    if (not Voice.has_proper_leaps(ante_cons_transition)
            and obj.nested_scale_degrees[0] != obj.nested_scale_degrees[8]):
        return False

    return True
示例#2
0
    def validate_base_melody(self):
        """Check current base melody with idioms"""
        melodic_mvmt = "".join(
            str(slope)
            for slope in self.melodic_direction[:self.chord_index + 1])

        if "_" * 3 in melodic_mvmt:
            # Avoid long rests
            return False
        if "_" * 2 in melodic_mvmt:
            all_rest_indices = set()
            start_index = 0
            while True:
                rest_index = melodic_mvmt.find("__", start_index)
                if rest_index == -1:
                    break
                all_rest_indices.add(rest_index)
                start_index = rest_index + 1
            if all_rest_indices - self.good_double_rest_indices:
                # Avoid triple repeats only between phrases")
                return False

        start_index = 0
        while True:
            rest_index = melodic_mvmt.find("_", start_index)

            if rest_index in self.bad_single_rest_indices:
                return False
            if rest_index == -1:
                break
            start_index = rest_index + 1

        relevant_melodic_mvt = melodic_mvmt[1:]

        current_move_distance = self.current_degree_choice - self.previous_degree_choice
        abs_current_move_distance = abs(current_move_distance)
        if abs_current_move_distance > 7:
            # Keep leaps within octave
            return False
        if self.chord_index == 14:
            if abs_current_move_distance > 4:
                # Don't end with a large leap
                return False
            if relevant_melodic_mvt.count('>') > relevant_melodic_mvt.count(
                    '<'):
                # Descending motion should predominate
                return False
        if abs_current_move_distance > 4 and self.chord_index not in self.valid_leap_indices:
            # Large leap can only occur halfway through
            return False
        if len(self.unnested_scale_degrees) >= 3:
            if self.chord_index < 9:
                nested_part_half = self.nested_scale_degrees[:8]
            else:
                nested_part_half = self.nested_scale_degrees[8:]
            unnested_part_half = Voice.merge_lists(*nested_part_half)
            if not Voice.has_proper_leaps(unnested_part_half):
                # "Leap should be followed by contrary stepwise motion (full melody)"
                return False
        if self.chord_index == 11:
            ante_cons_transition = Voice.merge_lists(
                *self.nested_scale_degrees[5:10])
            if (not Voice.has_proper_leaps(ante_cons_transition)
                    and self.nested_scale_degrees[0] !=
                    self.nested_scale_degrees[8]):
                return False

        # score divides into 4 sections, 16 items
        # first 2 sections: antecedent
        # last 2 sections: consequent
        current_section = self.chord_index // 4
        section_start_index = current_section * 4
        section_scale_degrees = (
            self.chosen_scale_degrees[section_start_index:section_start_index +
                                      4])
        end_degree = section_scale_degrees[-1]
        while end_degree is None:
            section_scale_degrees.pop()
            end_degree = section_scale_degrees[-1]

        section_max_degree = max(section_scale_degrees)
        if current_section <= 2:
            if section_scale_degrees.count(section_max_degree) > 2:
                return False
            if section_scale_degrees.count(section_max_degree) == 2:
                for scale_degree0, scale_degree1 in zip(
                        section_scale_degrees, section_scale_degrees[1:]):
                    if (scale_degree0 == section_max_degree
                            and scale_degree0 == scale_degree1):
                        break
                else:
                    return False

        if self.chord_index == 2:
            if self.chosen_figurations[0] != "IPT":
                return False
        if self.chord_index >= 3:
            previous_melody_note = self.chosen_scale_degrees[self.chord_index -
                                                             3]
            for chord_index, melody_group in enumerate(
                    self.nested_scale_degrees[self.chord_index -
                                              3:self.chord_index - 1],
                    self.chord_index - 3):
                for fig_index, current_melody_note in enumerate(melody_group):
                    pitch_diff = current_melody_note - previous_melody_note
                    if (abs(pitch_diff) > 4 and pitch_diff < 0 and
                        (fig_index != 0
                         or chord_index not in self.valid_leap_indices)):
                        return False
                    previous_melody_note = current_melody_note
            if (self.chord_index not in self.quick_turn_indices
                    and melodic_mvmt[self.chord_index - 2:] in {"><>", "<><"}):
                # No late melodic jukes
                return False

        if self.chord_index == 8:
            section1 = self.chosen_scale_degrees[:4]
            section2 = self.chosen_scale_degrees[4:8]
            if max(section1) == max(section2):
                return False
        elif self.chord_index == 15:
            section3 = self.chosen_scale_degrees[8:12]
            section4 = self.chosen_scale_degrees[12:]
            if max(section3) <= max(section4):
                return False
            if abs(self.nested_scale_degrees[-3][-1]) > 1:
                return False
            if (self.chosen_figurations.count("OPT") > 2
                    and self.nested_scale_degrees[0:4] !=
                    self.nested_scale_degrees[8:12]):
                return False

        num_still_figures = self.chosen_figurations.count("CN")
        num_still_figures += self.chosen_figurations.count("DN")
        num_still_figures += self.chosen_figurations.count("DCN")

        if num_still_figures > 2:
            return False
        if self.chosen_figurations.count("OPT") > 4:
            return False
        if self.chosen_figurations.count("ANT") > 1:
            return False

        return True
示例#3
0
	def test_leaps(self):
		self.assertFalse(Voice.has_proper_leaps([7, 6, 2, 1]))
		self.assertFalse(Voice.has_proper_leaps([0, 5, 6, 5]))
		self.assertFalse(Voice.has_proper_leaps([2, 6, 2, 3]))
		self.assertFalse(Voice.has_proper_leaps([4, 0, 5, 1]))

		self.assertFalse(Voice.has_proper_leaps([0, 5, 10, 9]))
		self.assertFalse(Voice.has_proper_leaps([9, 5, 0, 1]))

		self.assertFalse(Voice.has_proper_leaps([6, 7, 2, 2, 1]))
		self.assertFalse(Voice.has_proper_leaps([0, 5, 5, 5, 6]))
		self.assertTrue(Voice.has_proper_leaps([1, 4, 4, 3, 2]))
		self.assertTrue(Voice.has_proper_leaps([10, 6, 6, 7, 6]))

		self.assertTrue(Voice.has_proper_leaps([]))
		self.assertTrue(Voice.has_proper_leaps([1, 2, 3, 4]))
		self.assertTrue(Voice.has_proper_leaps([0, 5, 4, 3]))
		self.assertTrue(Voice.has_proper_leaps([5, 2, 3, 1]))
		self.assertTrue(Voice.has_proper_leaps([8, 6, 4, 2]))
		self.assertTrue(Voice.has_proper_leaps([1, 3, 5, 7]))