def test_get_distance_dp(): a = midinote.MidiNote(0, 0, 1) b = midinote.MidiNote(1, 0, 1) A = a, a, a B = b, b, a, b, a distance_dp = get_distance_dp(A, B) correct_dp = [[(0, None), (1.125, 2), (2.25, 2), (3.375, 2), (4.5, 2), (5.625, 2)], [(1.125, 1), (1, 0), (2.125, 0), (2.25, 0), (3.375, 2), (4.5, 0)], [(2.25, 1), (2.125, 0), (2, 0), (2.125, 0), (3.25, 0), (3.375, 0)], [(3.375, 1), (3.25, 0), (3.125, 0), (2, 0), (3.125, 0), (3.25, 0)]] assert distance_dp == correct_dp
def parse(filename): with open(filename) as f: lines = f.readlines() notes = [] for line in lines: note, start = map(float, line.split()) notes.append(midinote.MidiNote(note, start, 1)) return notes
def test_get_optimal_alignment(): a = midinote.MidiNote(0, 0, 1) b = midinote.MidiNote(1, 0, 1) A = a, a, a B = b, b, a, b, a dp, b_bounds, b_slice, optimal = get_optimal_alignment(A, B) correct_dp = [ # outermost index is length substring of b (k) [ [(0, None), (1.125, 2), (2.25, 2), (3.375, 2), (4.5, 2), (5.625, 2)], # then enumerate prefixes of a (i) [(1.125, 1), (1, 0), (2.125, 0), (2.25, 0), (3.375, 2), (4.5, 0)], # then enumerate prefixes of b[k:] (j) [(2.25, 1), (2.125, 0), (2, 0), (2.125, 0), (3.25, 0), (3.375, 0)], [(3.375, 1), (3.25, 0), (3.125, 0), (2, 0), (3.125, 0), (3.25, 0)] ], # must pick a score from i == 3 row, ie, use all of a # so for this k=0 block, optimal is 2 [[(0, None), (1.125, 2), (2.25, 2), (3.375, 2), (4.5, 2)], [(1.125, 1), (1, 0), (1.125, 0), (2.25, 2), (3.375, 0)], [(2.25, 1), (2.125, 0), (1, 0), (2.125, 0), (2.25, 0)], [(3.375, 1), (3.25, 0), (2.125, 0), (2, 0), (2.125, 0)]], # and we do only exactly as well by using b[1:] [[(0, None), (1.125, 2), (2.25, 2), (3.375, 2)], [(1.125, 1), (0, 0), (1.125, 2), (2.25, 0)], [(2.25, 1), (1.125, 0), (1, 0), (1.125, 0)], [(3.375, 1), (2.25, 0), (2.125, 0), (1, 0)]], # but using b[2:] produces optimal result [[(0, None), (1.125, 2), (2.25, 2)], [(1.125, 1), (1, 0), (1.125, 0)], [(2.25, 1), (2.125, 0), (1, 0)], [(3.375, 1), (3.25, 0), (2.125, 0)]], # but going shorter is worse! [[(0, None), (1.125, 2)], [(1.125, 1), (0, 0)], [(2.25, 1), (1.125, 0)], [(3.375, 1), (2.25, 0)]], [[(0, None)], [(1.125, 1)], [(2.25, 1)], [(3.375, 1)]] ] assert b_bounds == (2, 5) assert b_slice == (a, b, a) assert optimal == 1 c = midinote.MidiNote(4, 0, 1) C = c, c, a, c, a dp, c_bounds, c_slice, optimal = get_optimal_alignment(A, C) assert c_bounds == (2, 3) assert optimal == 2.25
def test_get_note_uses(): a = midinote.MidiNote(0, 0, 1) b = midinote.MidiNote(4, 0, 1) A = [a, a, a] B = [b, b, a, b, a] pairings = get_note_uses(A, B) assert pairings == [None, None, 2] I = range(12) scale = [midinote.MidiNote(i, i, 1) for i in I] played = [ midinote.MidiNote(i, i - .05 + .1 * random.random(), .95 + .1 * random.random()) for i in I ] mistaken_note = midinote.MidiNote(100, 4.3, 300) played.append(mistaken_note) played.insert(0, midinote.MidiNote(100, -54, 300)) pairings = get_note_uses(played, scale) # notice that mistaken note shows up in the time ordered position in correct_pairings as None correct_pairings = [None, 0, 1, 2, 3, 4, None, 5, 6, 7, 8, 9, 10, 11] assert pairings == correct_pairings played_with_indices = list(enumerate(played)) scale_with_indices = list(enumerate(scale)) random.shuffle(played_with_indices) random.shuffle(scale_with_indices) pairings = get_note_uses([p for i, p in played_with_indices], [s for i, s in scale_with_indices]) assert get_note_uses(played, scale) == correct_pairings
def align(filename, tempo): # returns with time measured in quarter notes at $tempo, starting from zero with open(filename) as f: lines = f.readlines() notes = [] for line in lines: note, start = line.split() notes.append(midinote.MidiNote(int(note), float(start), 1)) print lines[:5] print lines[-5:] #notes = [midinote.MidiNote(note, start, 1) for line in lines for (note, start, _) in line.split()] # fix up durations some day? fix_offset(notes) set_tempo(notes, tempo) round_starts(notes) # plumb so as not to use defaults return notes