示例#1
0
def _best_sane_chord(preceding, current, following,
                     recent_notes, chord_index, limiting, net):
    r"""
    Given a current theoretical chord, find the best plausible form for it.

    * `preceding` is a chronological list of preceding chords in physical form.
    * `current` is the theoretical chord to be instantiated.
    * `following` is a chronological list of following chords.
    * `recent_notes` is a mapping from theoretical notes to physical notes;
       it indicates what the most recent instance of a particular note was.
    * `chord_index` is the chord number of `current`, e.g. 0 if `current` is
       the first chord.
    * `limiting` is the first "limiting" note part of a chord with an index
       strictly greater than `chord_index`.
    * `net` is the trained neural net that makes the final decision.
    """
    min_error = None
    best_config = None
    for sane in sane_chords(current):
        # TODO move "transformation" to sane_chords where it belongs
        transformed_sane = {}
        for sane_entry in sane:
            string_index = STANDARD_STRINGS.index(sane_entry[1])
            transformed_sane[string_index] = sane_entry[0]
        LOG.debug('Transformed: {transformed_sane}'.format(**locals()))
        error = _sane_chord_error(preceding, transformed_sane, following,
                                  recent_notes, chord_index, limiting, net)
        if min_error is None or error < min_error:
            min_error = error
            best_config = transformed_sane
            for elem in best_config:
                if elem > 24:
                    LOG.warning('Outside of fret range!')
    return best_config
 def test_sane_chords_with_capo(self):
     notes = set([('G', 5), ('F#', 4)])
     expected = set([
                   frozenset([(24, ('G', 3)), (21, ('A', 2))]),
                   frozenset([(24, ('G', 3)), (2, ('E', 4))]),
                   frozenset([(20, ('B', 3)), (2, ('E', 4))]),
                   frozenset([(20, ('B', 3)), (21, ('A', 2))]),
                   frozenset([(20, ('B', 3)), (16, ('D', 3))]),
                   frozenset([(15, ('E', 4)), (11, ('G', 3))]),
                   frozenset([(15, ('E', 4)), (16, ('D', 3))])
                   ])
     generated = set(notemappings.sane_chords(notes, capo=2))
     self.assertEqual(generated, expected)
 def test_sane_chords_a3_fifth(self):
     notes = set([('A', 3), ('E', 4)])
     expected = set([
                   frozenset([(17, ('E', 2)), (19, ('A', 2))]),
                   frozenset([(17, ('E', 2)), (0, ('E', 4))]),
                   frozenset([(17, ('E', 2)), (14, ('D', 3))]),
                   frozenset([(12, ('A', 2)), (14, ('D', 3))]),
                   frozenset([(12, ('A', 2)), (0, ('E', 4))]),
                   frozenset([(12, ('A', 2)), (9, ('G', 3))]),
                   frozenset([(7, ('D', 3)), (9, ('G', 3))]),
                   frozenset([(7, ('D', 3)), (5, ('B', 3))]),
                   frozenset([(7, ('D', 3)), (0, ('E', 4))]),
                   frozenset([(2, ('G', 3)), (5, ('B', 3))]),
                   frozenset([(2, ('G', 3)), (0, ('E', 4))])
                   ])
     generated = set(notemappings.sane_chords(notes))
     self.assertEqual(generated, expected)
示例#4
0
def annotate(midi_path, net):
    r"""
    Given a path to a generated midi,
    yield the best configuration for each chord.
    """
    preceding = []
    recent_notes = {}
    for (current, following, current_index, limiting) in midi_contexts(midi_path):
        # sane_chords actually uses note lists instead of canonical chords
        # this is okay for single-note melodies, though

        # TODO adjust called code so that this whole hack is not necessary
        LOG.debug('Following: {f}'.format(f=following))
        following_notelists = []
        for theor_following in following:
            theor_notelist = []
            for key in theor_following.keys():
                theor_notelist.extend([key] * theor_following[key])
            following_notelists.append(theor_notelist)
        LOG.debug('Following notelists: {f}'.format(f=following_notelists))
        phys_following = [next(sane_chords(successor)) for successor in following_notelists]
        LOG.debug('Phys following: {p}'.format(p=phys_following))
        phys_transformed = []
        for frozen in phys_following:
            el = next(iter(frozen))  # only one, anyway
            phys_transformed.append({STANDARD_STRINGS.index(el[1]): el[0]})
        LOG.debug('Phys transformed: {p}'.format(p=phys_transformed))

        best_config = _best_sane_chord(preceding, current, phys_transformed,
                                       recent_notes, current_index,
                                       limiting, net)
        yield best_config
        if len(preceding) >= CHORDS_BEFORE_CURRENT:
            del(preceding[0])
        preceding.append(best_config)
        for string_num in best_config:
            fret = best_config[string_num]
            recent_notes[fret2note(fret, string_num)] = (string_num, fret)
 def test_sane_chords_single_unique_note(self):
     notes = set([('E', 2)])
     # each config is a frozenset, and there is a set of configs
     expected = set([frozenset([(0, ('E', 2))])])
     generated = set(notemappings.sane_chords(notes))
     self.assertEqual(generated, expected)