示例#1
0
 def test_abc_2part_mono():
     d_corpus = DCorpus(corpus_path=BERINGER2_SCALE_CORPUS, as_xml=False)
     lo, hi = d_corpus.pitch_range()
     assert lo < hi, "Bad dcorpus pitch range"
     score_count = d_corpus.score_count()
     assert score_count == 38, "Bad score count"
     d_score = d_corpus.d_score_by_title("scales_g_minor_melodic")
     assert d_score is not None, "Bad score_by_title retrieval"
     lo, hi = d_score.pitch_range()
     assert lo < hi, "Bad DScore pitch range"
     part_count = d_score.part_count()
     assert part_count == 2, "Bad part count"
     d_part = d_score.combined_d_part()
     part_lo, part_hi = d_part.pitch_range()
     assert part_lo < part_hi, "Bad DPart pitch range"
     assert part_lo == lo, "Bad low pitch found"
     assert part_hi == hi, "Bad high pitch found"
     assert d_part is not None, "Bad DPart retrieval"
     assert d_part.is_monophonic() is False, "Polyphony not detected"
     d_upper = d_score.upper_d_part()
     assert d_upper, "Bad upper DPart"
     assert d_upper.is_monophonic() is True, "Monophonic upper part not detected"
     d_lower = d_score.lower_d_part()
     assert d_lower, "Bad lower DPart"
     # lower_stream = d_lower.stream()
     # lower_stream.show('text')
     assert d_lower.is_monophonic() is True, "Monophonic lower part not detected"
示例#2
0
 def test_append_dir():
     d_corpus = DCorpus()
     d_corpus.append_dir(corpus_dir=TestConstant.BERINGER2_ANNOTATED_ARPEGGIO_DIR)
     # d_corpus.append_dir(corpus_dir=TestConstant.BERINGER2_ANNOTATED_SCALE_DIR)
     d_corpus.append_dir(corpus_dir=TestConstant.BERINGER2_ANNOTATED_BROKEN_CHORD_DIR)
     score_count = d_corpus.score_count()
     assert score_count > 48, "Bad score count"
     for i in range(score_count):
         d_score = d_corpus.d_score_by_index(i)
         assert d_score.title() is not None, "Missing title at {0}".format(i)
         assert d_score.is_fully_annotated(indices=[0]), "Missing annotation in {}".format(d_score.title())
示例#3
0
    def test_abc2xml_2part_chords():
        p01_path = TestConstant.WTC_CORPUS_DIR + '/prelude01.abc'
        p09_path = TestConstant.WTC_CORPUS_DIR + '/prelude09.abc'
        d_corpus = DCorpus(corpus_path=p01_path, as_xml=True)
        score_count = d_corpus.score_count()
        assert score_count == 1, "Bad score count"
        d_corpus.append(corpus_path=p09_path, as_xml=True)
        assert d_corpus.score_count() == 2, "Bad append"
        titles = d_corpus.titles()
        assert len(titles) == 2, "Bad title count"
        d_score = d_corpus.d_score_by_index(0)
        assert d_score.title() == 'Prelude 1 (BWV 846)', "Bad title retrieval"
        part_count = d_score.part_count()
        assert part_count == 2, "Bad part count"
        d_part = d_score.combined_d_part()
        assert d_part is not None, "Bad DPart retrieval"
        assert d_part.is_monophonic() is False, "Polyphony not detected"
        d_upper = d_score.upper_d_part()
        assert d_upper, "Bad upper DPart"
        assert d_upper.is_monophonic() is False, "Polyphonic upper part not detected"
        d_lower = d_score.lower_d_part()
        assert d_lower, "Bad lower DPart"
        assert d_lower.is_monophonic() is False, "Polyphonic lower part in Prelude 1 not detected"
        assert d_lower.is_orderly() is False, "Lower part in Prelude 1 is not orderly"
        orderly_stream = d_lower.orderly_note_stream()
        # orderly_stream.show('text')
        orderly_d_part = DPart(music21_stream=orderly_stream)
        assert orderly_d_part.is_orderly() is True, "orderly_note_stream() or is_orderly() is broken"

        # Need to check what happens to tied notes
        d_score = d_corpus.d_score_by_index(1)
        d_upper = d_score.upper_d_part()
        disorderly_stream = d_upper.stream()
        disorderly_d_part = DPart(music21_stream=disorderly_stream)
        assert disorderly_d_part.is_orderly() is False, "orderly_note_stream() or is_orderly() is broken"
        disorderly_stream.show('text')
        orderly_stream = d_upper.orderly_note_stream()
        orderly_d_part = DPart(music21_stream=orderly_stream)
        assert orderly_d_part.is_orderly() is True, "orderly_note_stream() or is_orderly() is broken"
示例#4
0
class DEvalSimple(ABC):
    def __init__(self):
        self._dactyler = None
        self._d_corpus = DCorpus()
        self._gold = dict()
        self._gold['upper'] = list()
        self._gold['lower'] = list()

    @staticmethod
    def _max_distance_for_method(method):
        if method == "natural":
            # d_max = Constant.MAX_NATURAL_EDIT_DISTANCE
            # FIXME: desegregated max turns DCPG murky and useless.
            d_max = 4
        elif method == "hamming":
            d_max = 1
        else:
            raise Exception("Not ready to measure {} gain".format(method))
        return d_max

    @staticmethod
    def _proximal_gain(test_abcdf,
                       gold_handed_strikers,
                       gold_vote_counts,
                       staff,
                       method="hamming"):
        testee = DAnnotation.abcdf_to_handed_strike_digits(test_abcdf,
                                                           staff=staff)
        d_max = DEvalSimple._max_distance_for_method(method)
        nugget_index = 0
        total_gain = 0
        for nugget in gold_handed_strikers:
            nugget_gain = 0
            for i in range(len(testee)):
                distance = DAnnotation.strike_distance_cost(
                    gold_handed_digit=nugget[i],
                    test_handed_digit=testee[i],
                    method=method)
                nugget_gain += (d_max - distance)
            nugget_gain *= gold_vote_counts[nugget_index]
            nugget_index += 1
            total_gain += nugget_gain
        return total_gain

    @abstractmethod
    def load_data(self):
        return

    def gold_asts(self, score_index, staff="upper", last_digit=None):
        score_gold = self._score_gold(score_index=score_index,
                                      staff=staff,
                                      last_digit=last_digit)
        asts = list()
        for abcdf in score_gold:
            ast = DAnnotation.abcdf_to_ast(abcdf)
            asts.append(ast)
        return asts

    def gold_list_of_handed_strike_lists(self,
                                         score_index,
                                         staff="upper",
                                         last_digit=None):
        gold_asts = self.gold_asts(score_index,
                                   staff=staff,
                                   last_digit=last_digit)
        list_of_strike_lists = list()
        for gold_ast in gold_asts:
            nuggets = DAnnotation.ast_to_handed_strike_digits(gold_ast,
                                                              staff=staff)
            list_of_strike_lists.append(nuggets)
        return list_of_strike_lists

    def gold_clusters(self, score_index, staff="upper", last_digit=None):
        score_gold = self._score_gold(score_index=score_index,
                                      staff=staff,
                                      last_digit=last_digit)

    @staticmethod
    def krippendorfs_alpha(upper_rh_advice, exercise_upper_gold):
        fingerings = list(upper_rh_advice)
        fingerings.pop(0)
        finger_ints = list(map(int, fingerings))
        exercise_upper_gold.append(finger_ints)
        krip = alpha(reliability_data=exercise_upper_gold,
                     level_of_measurement='interval')
        exercise_upper_gold.pop()
        return krip

    def assert_good_gold(self, staff="upper"):
        score_count = self._d_corpus.score_count()
        gold_score_count = len(self._gold[staff])
        if score_count != gold_score_count:
            raise Exception(
                "Gold count ({0}) does not match score count ({1}).".format(
                    gold_score_count, score_count))

    @staticmethod
    def suggestion_data_by_cost(suggestions, costs, details, cutoff_rank=None):
        """
        Return a dictionary of suggestion data keyed by total costs.
        :param suggestions: A list of abcDF suggestion strings, ordered by increasing cost.
        :param costs: A corresponding list of the particular suggestion costs.
        :param details: A corresponding list of cost details for each suggestion
        :param cutoff_rank: The final rank (as indicated by sorting by cost) to include in
        returned results.
        :return: data_by_cost: A dictionary of lists of dictionaries.
        """
        data_by_cost = dict()
        sugg_count = 0
        last_cost_to_include = None
        for i in range(len(suggestions)):
            sugg_count += 1
            sugg = suggestions[i]
            cost = costs[i]
            detail = details[i]

            if last_cost_to_include is not None and cost > last_cost_to_include:
                break

            if cutoff_rank and cutoff_rank >= sugg_count:
                last_cost_to_include = cost

            if cost not in data_by_cost:
                data_by_cost[cost] = list()
            data = {'suggestion': sugg, 'details': detail}
            data_by_cost[cost].append(data)
        return data_by_cost

    def score_advice(self,
                     score_index,
                     staff="upper",
                     cycle=None,
                     last_digit=None,
                     k=10):
        # FIXME: I don't see what this method buys us. generate_advice() should do the right
        # default thing, no?
        if cycle:
            suggestions, costs, details = \
                self._dactyler.generate_advice(staff=staff, score_index=score_index, cycle=cycle, k=k)
        elif last_digit:
            suggestions, costs, details = \
                self._dactyler.generate_advice(staff=staff, score_index=score_index, last_digit=last_digit, k=k)
        else:
            suggestions, costs, details = \
                self._dactyler.generate_advice(staff=staff, score_index=score_index, k=k)
        return suggestions, costs, details

    def _recall_them_all(self,
                         score_index,
                         staff="upper",
                         cycle=None,
                         last_digit=None):
        k = 25
        last_count = None
        while True:
            suggestions, costs, details = self.score_advice(
                score_index=score_index,
                staff=staff,
                last_digit=last_digit,
                cycle=cycle,
                k=k)
            suggestion_count = len(suggestions)
            if suggestion_count == last_count:
                break
            last_count = suggestion_count
            if self._all_gold_found(score_index=score_index,
                                    staff=staff,
                                    last_digit=last_digit,
                                    suggestions=suggestions):
                break
            k *= 2
        suggestion_count = len(suggestions)
        if suggestion_count <= 0:
            raise Exception("Bad suggestion count")
        suggestions = self._trim_suggestions(suggestions=suggestions,
                                             score_index=score_index,
                                             last_digit=last_digit,
                                             staff=staff)
        costs = costs[0:len(suggestions)]
        details = details[0:len(suggestions)]
        return suggestions, costs, details

    @staticmethod
    def estimated_prob_user_happy(suggestion, score_gold):
        prob = 1
        return prob