├── __init__.py ├── core ├── __init__.py ├── test.py ├── dtw.py ├── filter.py ├── midi.py └── melody_feature.py ├── utils ├── __init__.py └── file_matcher.py ├── .gitignore ├── data ├── test │ └── mxml2.wma └── train │ ├── soo.wav │ ├── xml.wav │ └── 10-little-indians.wav ├── README.md ├── interface.py └── LICENSE /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | core/*.mp3 2 | core/*.wav 3 | core/*.wma 4 | *.mid 5 | *.txt 6 | *.pyc -------------------------------------------------------------------------------- /data/test/mxml2.wma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyaqu/guess-your-song/HEAD/data/test/mxml2.wma -------------------------------------------------------------------------------- /data/train/soo.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyaqu/guess-your-song/HEAD/data/train/soo.wav -------------------------------------------------------------------------------- /data/train/xml.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyaqu/guess-your-song/HEAD/data/train/xml.wav -------------------------------------------------------------------------------- /data/train/10-little-indians.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyaqu/guess-your-song/HEAD/data/train/10-little-indians.wav -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # guess-your-song 2 | an dtw approach for humming query 3 | 4 | # requirements 5 | * numpy 6 | * pydub (for reading music file) 7 | * ffmpeg (this is required by pydub) 8 | 9 | # how to use 10 | see interface.py 11 | -------------------------------------------------------------------------------- /core/test.py: -------------------------------------------------------------------------------- 1 | from melody_feature import * 2 | 3 | if __name__ == '__main__': 4 | file = 'alphaville-forever_young.mid' 5 | for k,note in note_from_midi_test(file): 6 | print k 7 | name = 'forever_youngy' + str(k)+'.txt' 8 | vector_to_file(note,name) -------------------------------------------------------------------------------- /utils/file_matcher.py: -------------------------------------------------------------------------------- 1 | import os 2 | import fnmatch 3 | 4 | def file_filter(path,filters): 5 | try: 6 | files = os.listdir(path) 7 | for filter in filters: 8 | for f in fnmatch.filter(files, "*.%s" % filter): 9 | p = os.path.join(path, f) 10 | yield (p, filter) 11 | except: 12 | print "Catch an exception caught,but I don't know what to do" 13 | 14 | if __name__ == '__main__': 15 | x = file_filter('c:\\src',['mp3']) 16 | for name,format in x: 17 | print name,format -------------------------------------------------------------------------------- /interface.py: -------------------------------------------------------------------------------- 1 | from utils.file_matcher import file_filter 2 | from core.melody_feature import * 3 | 4 | def db_create(dir,format=['wav']): 5 | db = {} 6 | for file_name, _ in file_filter(dir,format): 7 | pv = file_to_pitch_vector(file_name) 8 | db[file_name] = pv 9 | 10 | return db 11 | 12 | def query(db,pv): 13 | distance = {} 14 | for name,pitch in db.items(): 15 | dis = pitch_vector_distance(pitch,pv) 16 | distance[name] = dis 17 | 18 | ordered = sorted(distance.items(), lambda x, y: cmp(x[1], y[1])) 19 | # name,value pair 20 | if(ordered): 21 | return ordered[0] 22 | 23 | if __name__ == '__main__': 24 | db = db_create('data/train') 25 | test_file = 'data/test/mxml2.wma' 26 | pv = file_to_pitch_vector(test_file) 27 | name,dis = query(db,pv) 28 | 29 | print 'The best match is:' 30 | print ' name:',name,', distance:',dis 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /core/dtw.py: -------------------------------------------------------------------------------- 1 | from numpy import array, zeros, argmin, inf 2 | from numpy.linalg import norm 3 | 4 | 5 | def dtw(x, y, dist=lambda x, y: norm(x - y, ord=1)): 6 | """ Computes the DTW of two sequences. 7 | :param array x: N1*M array 8 | :param array y: N2*M array 9 | :param func dist: distance used as cost measure (default L1 norm) 10 | Returns the minimum distance, the accumulated cost matrix and the wrap path. 11 | """ 12 | x = array(x) 13 | if len(x.shape) == 1: 14 | x = x.reshape(-1, 1) 15 | y = array(y) 16 | if len(y.shape) == 1: 17 | y = y.reshape(-1, 1) 18 | 19 | r, c = len(x), len(y) 20 | 21 | D = zeros((r + 1, c + 1)) 22 | D[0, 1:] = inf 23 | D[1:, 0] = inf 24 | 25 | for i in range(r): 26 | for j in range(c): 27 | D[i+1, j+1] = dist(x[i], y[j]) 28 | 29 | for i in range(r): 30 | for j in range(c): 31 | D[i+1, j+1] += min(D[i, j], D[i, j+1], D[i+1, j]) 32 | 33 | D = D[1:, 1:] 34 | 35 | dist = D[-1, -1] / sum(D.shape) 36 | 37 | return dist, D, _trackeback(D) 38 | 39 | 40 | def _trackeback(D): 41 | i, j = array(D.shape) - 1 42 | p, q = [i], [j] 43 | while (i > 0 and j > 0): 44 | tb = argmin((D[i-1, j-1], D[i-1, j], D[i, j-1])) 45 | 46 | if (tb == 0): 47 | i = i - 1 48 | j = j - 1 49 | elif (tb == 1): 50 | i = i - 1 51 | elif (tb == 2): 52 | j = j - 1 53 | 54 | p.insert(0, i) 55 | q.insert(0, j) 56 | 57 | p.insert(0, 0) 58 | q.insert(0, 0) 59 | return (array(p), array(q)) -------------------------------------------------------------------------------- /core/filter.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | ###################################################################### 4 | # Sampling rate, related to the Nyquist conditions, which affects 5 | # the range frequencies we can detect. 6 | DEFAULT_FS = 44100 7 | 8 | ###################################################################### 9 | # Size of the frame window 10 | DEFAULT_WINDOW_SIZE = 4096 11 | 12 | ###################################################################### 13 | # time of the frame duration,in milliseconds 14 | DEFAULT_FRAME_DURATION = 32 15 | 16 | 17 | def sliding_window(sequence,ws=DEFAULT_WINDOW_SIZE,shift_ratio=1): 18 | """Returns a generator that will iterate through 19 | the defined chunks of input sequence. Input sequence 20 | must be iterable.""" 21 | shift = int(shift_ratio*ws) 22 | # Verify the inputs 23 | try: it = iter(sequence) 24 | except TypeError: 25 | raise Exception("**ERROR** sequence must be iterable.") 26 | if not ((type(ws) == type(0)) and (type(shift) == type(0))): 27 | raise Exception("**ERROR** type(ws) and type(shift) must be int.") 28 | if shift > ws: 29 | raise Exception("**ERROR** shift must not be larger than ws.") 30 | if ws > len(sequence): 31 | raise Exception("**ERROR** ws must not be larger than sequence length.") 32 | 33 | # Pre-compute number of chunks to emit 34 | num_frames = ((len(sequence)-ws)/shift)+1 35 | 36 | # Do the work 37 | for i in range(0,num_frames*shift,shift): 38 | yield sequence[i:i+ws] 39 | 40 | def acf(sequence): 41 | n = len(sequence) 42 | data = np.asarray(sequence) 43 | mean = np.mean(data) 44 | c0 = np.sum((data - mean) ** 2) / float(n) 45 | 46 | def r(h): 47 | acf_lag = ((data[:n - h] - mean) * (data[h:] - mean)).sum() / float(n) / c0 48 | return round(acf_lag, 3) 49 | x = np.arange(n) # Avoiding lag 0 calculation 50 | acf_coeffs = map(r, x) 51 | return np.asarray(acf_coeffs) 52 | 53 | def median_filt(data, k): 54 | """Apply a length-k median filter to a 1D array x. 55 | Boundaries are extended by repeating endpoints. 56 | """ 57 | assert k % 2 == 1, "Median filter length must be odd." 58 | x = np.asarray(data) 59 | assert x.ndim == 1, "Input must be one-dimensional." 60 | k2 = (k - 1) // 2 61 | y = np.zeros ((len (x), k), dtype=x.dtype) 62 | y[:,k2] = x 63 | for i in range (k2): 64 | j = k2 - i 65 | y[j:,i] = x[:-j] 66 | y[:j,i] = x[0] 67 | y[:-j,-(i+1)] = x[j:] 68 | y[-j:,-(i+1)] = x[-1] 69 | return np.median(y, axis=1) 70 | 71 | def del_outlier_pitches(pv,thresh=10): 72 | adjusted = pv - np.median(pv) 73 | loc = (abs(adjusted) > thresh) 74 | pv[loc] = 0 75 | return pv -------------------------------------------------------------------------------- /core/midi.py: -------------------------------------------------------------------------------- 1 | from mido import MidiFile 2 | 3 | class ErrorStr(Exception): 4 | def __init__(self,err_str): 5 | Exception.__init__(self,err_str) 6 | 7 | class NoteSequencer(object): 8 | def __init__(self,file): 9 | try: 10 | self.mid = MidiFile(file) 11 | self.chs = {} 12 | self._load(self.mid) 13 | except Exception,e: 14 | raise ErrorStr,'midi file not exist,try another.' 15 | 16 | def _load(self,mid): 17 | tempo = 120.0 18 | scale_coff = 1.04 19 | last = {} 20 | for i, track in enumerate(mid.tracks): 21 | #print('Track {}: {}'.format(i, track.name)) 22 | # track 0 as descriptor 23 | if(i == 0): 24 | for message in track: 25 | #print message 26 | if(message.type == 'set_tempo'): 27 | tempo = 60000000.0/message.tempo 28 | #how many miliseconds per ticks 29 | scale_coff = (60*1000.0)/(tempo*mid.ticks_per_beat) 30 | 31 | # extract notes 32 | # i have manually change the track name to mainx for the main track 33 | if(track.name == 'mainx' or track.name == 'MAJOR_TRACK'): 34 | cur_time = 0 35 | for message in track: 36 | cur_time += message.time 37 | #print message 38 | if(message.type == 'note_on' and message.velocity != 0): 39 | if(not last.has_key(message.channel)): 40 | last[message.channel] = [] 41 | 42 | ele = dict(note=message.note,start=cur_time,duration=0,open=True) 43 | last[message.channel].append(ele) 44 | 45 | elif((message.type == 'note_on') or message.type == 'note_off'): 46 | #print last[message.channel] 47 | #print '---',int(cur_time*scale_coff),message 48 | ls = [ x for x in last[message.channel] if x['note'] == message.note] 49 | len_ls = len(ls) 50 | if(len_ls > 1 or len_ls <= 0): 51 | #fix me 52 | #what if got a key stucked? raise an error or be more fault-tolerable? 53 | raise ErrorStr,'note on/off not match.' 54 | if(ls[0]['open'] == True): 55 | start = int(ls[0]['start']*scale_coff) 56 | duration = int(message.time*scale_coff) 57 | # append (note,start_time,duration) pair 58 | if(not self.chs.has_key(message.channel)): 59 | self.chs[message.channel] = [] 60 | self.chs[message.channel].append((message.note,start,duration)) 61 | last[message.channel].remove(ls[0]) 62 | else: 63 | raise ErrorStr,'note on/off not match.' 64 | elif(message.type == 'end_of_track'): 65 | pass 66 | 67 | # return (note,start_time,duration) pair sequence 68 | def get_note_seq(self): 69 | for channel,note_seq in self.chs.iteritems(): 70 | yield channel,note_seq 71 | 72 | if __name__ == '__main__': 73 | s = NoteSequencer('eminem-love_the_way_you_lie_feat_rihanna.mid') 74 | for k,v in s.get_note_seq(): 75 | print 'chnnel:',k,v -------------------------------------------------------------------------------- /core/melody_feature.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import pydub 4 | 5 | from filter import * 6 | from dtw import dtw 7 | from midi import NoteSequencer 8 | 9 | def get_raw_from_file(filename): 10 | container = pydub.AudioSegment.from_file(filename) 11 | if container.sample_width == 1: 12 | data = np.fromstring(container._data, np.int8) 13 | else: 14 | data = np.fromstring(container._data, np.int16) 15 | 16 | data = data - data.mean() 17 | channels = [] 18 | for chn in xrange(container.channels): 19 | channels.append(data[chn::container.channels]) 20 | return channels,container.frame_rate 21 | 22 | def freq_to_notes(freqs): 23 | log440 = 8.78135971 24 | notes_array = np.asarray(freqs) 25 | notes = 12 * (np.log2(notes_array) - log440) + 69 26 | return notes 27 | 28 | def note_segment(sequence,thresh=1): 29 | x = np.asarray(sequence) 30 | y = np.array([]) 31 | start = end = 0 32 | for index in range(x.size-1): 33 | if(abs(x[index] - x[index+1]) < thresh): 34 | end = index + 1 35 | if(end == x.size-1): 36 | #print 's',start,index+1,x[start:x.size] 37 | avg = np.median(x[start:x.size]) 38 | x[start:x.size] = avg 39 | if(x.size - start >= 1): 40 | #print 'append' 41 | y = np.append(y,x[start:x.size]) 42 | else: 43 | #print start,index+1, x[start:index+1] 44 | avg = np.median(x[start:index+1]) 45 | x[start:index+1] = avg 46 | if(index+1 - start >= 1): 47 | #print 'b append' 48 | y = np.append(y,x[start:index+1]) 49 | start = index + 1 50 | 51 | index += 1 52 | 53 | return y 54 | 55 | def cal_energy(sequence): 56 | data = np.asarray(sequence) 57 | return data.max() 58 | #return abs(data).sum() 59 | #return 1.0*abs(data).sum()/data.size 60 | 61 | def frame_to_pitch(frame,fs,thresh): 62 | frame_x = np.asarray(frame) 63 | invalid = -1 64 | if cal_energy(frame_x) < thresh: 65 | return invalid 66 | else: 67 | down_limit = 40 68 | up_limit = 1000 69 | n1 = int(round(fs*1.0/up_limit)) 70 | n2 = int(round(fs*1.0/down_limit)) 71 | frame_acf = acf(frame_x) 72 | frame_acf[np.arange(n1)] = invalid 73 | if n2 < frame_acf.size: 74 | frame_acf[np.arange(n2,frame_acf.size)] = invalid 75 | index = frame_acf.argmax() 76 | #max = frame_x[index] 77 | #print n1,n2,max,index 78 | pitch = fs/(index - 1.0) 79 | return pitch 80 | 81 | def extract_pitches(filename,duration=40.0): 82 | channels,fs = get_raw_from_file(filename) 83 | ws = int(round(duration*fs/1000.0)) 84 | data = channels[0] 85 | energy = cal_energy(data) 86 | thresh = 0.3*energy 87 | result = [] 88 | for window in sliding_window(data,ws): 89 | pitch = frame_to_pitch(window,fs,thresh) 90 | result.append(pitch) 91 | return result 92 | 93 | def pitch_vector_distance(pa,pb): 94 | la = ~np.isnan(pa) 95 | lb = ~np.isnan(pb) 96 | x = pa[la] 97 | y = pb[lb] 98 | 99 | dist, cost, path = dtw(x,y) 100 | return dist 101 | 102 | # dump pitch vector to file 103 | def vector_to_file(t,file): 104 | s = ''.join(map(lambda x:str(x)+',',t)) 105 | with open(file,'wb') as f: 106 | f.write(s) 107 | 108 | def file_to_pitch_vector(file): 109 | r = extract_pitches(file) 110 | r1 = freq_to_notes(r) 111 | t = median_filt(r1,7) 112 | 113 | return t 114 | 115 | # note sequence from midi 116 | def note_from_midi_test(file): 117 | thresh = 40 118 | s = NoteSequencer(file) 119 | 120 | for k,v in s.get_note_seq(): 121 | note_seq = [] 122 | for x in v: 123 | n = int(x[2]/thresh) 124 | if(n > 1): 125 | note_seq.extend([x[0]]*n) 126 | else: 127 | note_seq.append(x[0]) 128 | yield k,note_seq 129 | 130 | # note sequence from midi 131 | def note_from_midi(file): 132 | thresh = 40 133 | s = NoteSequencer(file) 134 | 135 | for k,v in s.get_note_seq(): 136 | note_seq = [] 137 | for x in v: 138 | n = int(x[2]/thresh) 139 | if(n > 1): 140 | note_seq.extend([x[0]]*n) 141 | else: 142 | note_seq.append(x[0]) 143 | 144 | note_array = np.array(note_seq) 145 | note_array = note_array - note_array.mean() 146 | #ff = 'aaa' + file + '.txt' 147 | #vector_to_file(note_array,ff) 148 | for note in sliding_window(note_array,ws=10,shift_ratio=0.1): 149 | yield note,file 150 | 151 | #pitch based lsh 152 | def plsh(file): 153 | pv = file_to_pitch_vector(file) 154 | pv = pv - np.median(pv) 155 | for x in sliding_window(pv,ws=10): 156 | note = x 157 | #[::3] 158 | #very helpful to set nan as 0 159 | loc = np.isnan(note) 160 | note[loc] = 0 161 | yield note,file 162 | 163 | # note based lsh 164 | def nlsh(file): 165 | pv = file_to_pitch_vector(file) 166 | pv = pv - np.median(pv) 167 | #filtered = del_outlier_pitches(pv.copy()) 168 | #adjusted = filtered - filtered.mean() 169 | pv = note_segment(pv) 170 | for x in sliding_window(pv,ws=10): 171 | note = x 172 | loc = np.isnan(note) 173 | note[loc] = 0 174 | yield note,file 175 | 176 | if __name__ == '__main__': 177 | from lshash import LSHash 178 | 179 | hash_len = 10 180 | dm = 10 181 | lsh = LSHash(hash_len, dm) 182 | 183 | mid1 = '00001.mid' 184 | mid2 = '00002.mid' 185 | mid3 = '00003.mid' 186 | mid4 = '00004.mid' 187 | mid5 = '00005.mid' 188 | mid6 = '00006.mid' 189 | mid7 = '00007.mid' 190 | mid8 = '00008.mid' 191 | mid9 = '00009.mid' 192 | mid10 = '00010.mid' 193 | mid11 = '00011.mid' 194 | mid12 = '00012.mid' 195 | mid13 = '00013.mid' 196 | mid14 = '00014.mid' 197 | mid15 = '00015.mid' 198 | mid16 = '00016.mid' 199 | mid17 = '00017.mid' 200 | mid18 = '00018.mid' 201 | mid19 = '00019.mid' 202 | mid20 = '00020.mid' 203 | 204 | s1 = 'yldw.mid' 205 | s2 = 'alphaville-forever_young.mid' 206 | s3 = 'counting_stars.mid' 207 | s4 = 'baba-go.mid' 208 | 209 | 210 | for note,name in note_from_midi(s1): 211 | lsh.index(note,extra_data=(name,0.8)) 212 | for note,name in note_from_midi(s2): 213 | lsh.index(note,extra_data=(name,0.8)) 214 | for note,name in note_from_midi(s3): 215 | lsh.index(note,extra_data=(name,0.8)) 216 | for note,name in note_from_midi(s4): 217 | lsh.index(note,extra_data=(name,0.8)) 218 | 219 | for note,name in note_from_midi(mid1): 220 | lsh.index(note,extra_data=(name,0.8)) 221 | for note,name in note_from_midi(mid2): 222 | lsh.index(note,extra_data=(name,0.8)) 223 | for note,name in note_from_midi(mid3): 224 | lsh.index(note,extra_data=(name,0.8)) 225 | for note,name in note_from_midi(mid4): 226 | lsh.index(note,extra_data=(name,0.8)) 227 | for note,name in note_from_midi(mid5): 228 | lsh.index(note,extra_data=(name,0.8)) 229 | for note,name in note_from_midi(mid13): 230 | lsh.index(note,extra_data=(name,0.8)) 231 | 232 | for note,name in note_from_midi(mid7): 233 | lsh.index(note,extra_data=(name,0.8)) 234 | for note,name in note_from_midi(mid8): 235 | lsh.index(note,extra_data=(name,0.8)) 236 | for note,name in note_from_midi(mid9): 237 | lsh.index(note,extra_data=(name,0.8)) 238 | for note,name in note_from_midi(mid10): 239 | lsh.index(note,extra_data=(name,0.8)) 240 | for note,name in note_from_midi(mid11): 241 | lsh.index(note,extra_data=(name,0.8)) 242 | for note,name in note_from_midi(mid12): 243 | lsh.index(note,extra_data=(name,0.8)) 244 | 245 | for note,name in note_from_midi(mid13): 246 | lsh.index(note,extra_data=(name,0.8)) 247 | for note,name in note_from_midi(mid14): 248 | lsh.index(note,extra_data=(name,0.8)) 249 | for note,name in note_from_midi(mid15): 250 | lsh.index(note,extra_data=(name,0.8)) 251 | for note,name in note_from_midi(mid18): 252 | lsh.index(note,extra_data=(name,0.8)) 253 | for note,name in note_from_midi(mid17): 254 | lsh.index(note,extra_data=(name,0.8)) 255 | for note,name in note_from_midi(mid19): 256 | lsh.index(note,extra_data=(name,0.8)) 257 | for note,name in note_from_midi(mid20): 258 | lsh.index(note,extra_data=(name,0.8)) 259 | 260 | kk = [] 261 | i = 0 262 | result = {} 263 | for note,name in nlsh('xml.wav'): 264 | q = note 265 | kk.extend(q) 266 | r = lsh.query(q) 267 | print '--------'+str(i)+'-----------' 268 | i += 1 269 | if(len(r) > 0): 270 | print len(r) 271 | # keep 3 candidate 272 | nn = min(3,len(r)) 273 | # let's vote(based on distance) 274 | for k in range(nn): 275 | w = r[k][1] 276 | name = r[k][0][1][0] 277 | if(not result.has_key(name)): 278 | result[name] = 0.0 279 | else: 280 | w *= 0.93 281 | result[name] += w 282 | print r[k][0][1],r[k][1] 283 | 284 | candidates = sorted(result.items(), lambda x, y: cmp(x[1], y[1])) 285 | print '----------------------------' 286 | print candidates 287 | 288 | 289 | """ 290 | for note,name in plsh(f1): 291 | lsh.index(note,extra_data=(name,0.8)) 292 | for note,name in plsh(f3): 293 | lsh.index(note,extra_data=(name,0.8)) 294 | for note,name in plsh(f4): 295 | lsh.index(note,extra_data=(name,0.8)) 296 | for note,name in plsh(f5): 297 | lsh.index(note,extra_data=(name,0.8)) 298 | 299 | for note,name in plsh(f2): 300 | q = note 301 | r = lsh.query(q) 302 | print '-------------------' 303 | if(len(r) > 0): 304 | print len(r) 305 | print r[0][0] 306 | 307 | """ 308 | """ 309 | p1 = file_to_pitch_vector(f1) 310 | p2 = file_to_pitch_vector(f2) 311 | p3 = file_to_pitch_vector(f3) 312 | p4 = file_to_pitch_vector(f4) 313 | 314 | #vector_to_file(p1,'p1.txt') 315 | #vector_to_file(p2,'p2.txt') 316 | #vector_to_file(p3,'p3.txt') 317 | print pitch_vector_distance(p1,p2) 318 | print pitch_vector_distance(p2,p3) 319 | print pitch_vector_distance(p2,p4) 320 | plt.plot(p1,'red') 321 | plt.plot(p2,'green') 322 | plt.plot(p3,'blue') 323 | plt.plot(p4,'yellow') 324 | plt.show() 325 | """ 326 | 327 | --------------------------------------------------------------------------------