Mercurial > hg > plosone_underreview
comparison scripts/PitchBihist.py @ 37:2cc444441f42 branch-tests
refactor pitchbihist and introduce default melody_sr
author | Maria Panteli |
---|---|
date | Thu, 14 Sep 2017 14:50:00 +0100 |
parents | 3b67cd634b9a |
children | e5e8e8a96948 |
comparison
equal
deleted
inserted
replaced
36:3b67cd634b9a | 37:2cc444441f42 |
---|---|
11 import smoothiecore as s | 11 import smoothiecore as s |
12 | 12 |
13 | 13 |
14 class PitchBihist: | 14 class PitchBihist: |
15 def __init__(self, win2sec=8): | 15 def __init__(self, win2sec=8): |
16 self.y = None | |
17 self.sr = None | |
18 self.chroma = None | |
19 self.chromasr = None | |
20 self.melodiasr = 44100. / 128. | |
21 self.bihist = None | |
22 self.win2sec = win2sec | 16 self.win2sec = win2sec |
17 self.hop2sec = 0.5 | |
18 self.melody_sr = 44100. / 128. | |
23 | 19 |
24 | 20 |
25 def hz_to_cents(self, freq_Hz, ref_Hz=32.703, n_cents=1200): | 21 def hz_to_cents(self, freq_Hz, ref_Hz=32.703, n_cents=1200): |
26 """ convert frequency values from Hz to cents | 22 """ convert frequency values from Hz to cents |
27 reference frequency at C1 | 23 reference frequency at C1 |
40 def get_melody_from_file(self, melodia_file, stop_sec=None): | 36 def get_melody_from_file(self, melodia_file, stop_sec=None): |
41 if not os.path.exists(melodia_file): | 37 if not os.path.exists(melodia_file): |
42 return [] | 38 return [] |
43 data = np.loadtxt(melodia_file, delimiter=',') | 39 data = np.loadtxt(melodia_file, delimiter=',') |
44 times, freqs = (data[:, 0], data[:, 1]) | 40 times, freqs = (data[:, 0], data[:, 1]) |
45 self.chromasr = 1. / (times[1] - times[0]) | 41 #melody_sr = 1. / (times[1] - times[0]) |
46 if stop_sec is not None: | 42 if stop_sec is not None: |
47 stop_idx = np.where(times < stop_sec)[0] | 43 stop_idx = np.where(times < stop_sec)[0] |
48 times, freqs = times[stop_idx], freqs[stop_idx] | 44 times, freqs = times[stop_idx], freqs[stop_idx] |
49 freqs[freqs<=0] = np.nan | 45 freqs[freqs<=0] = np.nan |
50 melody = freqs | 46 melody = freqs |
51 return melody | 47 return melody#, melody_sr |
52 | 48 |
53 | 49 |
54 def get_melody_matrix(self, melody): | 50 def get_melody_matrix(self, melody): |
55 n_bins = 60 | 51 n_bins = 60 |
56 n_frames = len(melody) | 52 n_frames = len(melody) |
62 melody_matrix[int(pitch), time] = 1 | 58 melody_matrix[int(pitch), time] = 1 |
63 return melody_matrix | 59 return melody_matrix |
64 | 60 |
65 | 61 |
66 def bihist_from_melodia(self, filename='sample_melodia.csv', secondframedecomp=True, stop_sec=None): | 62 def bihist_from_melodia(self, filename='sample_melodia.csv', secondframedecomp=True, stop_sec=None): |
63 #melody, melody_sr = self.get_melody_from_file(filename, stop_sec=stop_sec) | |
67 melody = self.get_melody_from_file(filename, stop_sec=stop_sec) | 64 melody = self.get_melody_from_file(filename, stop_sec=stop_sec) |
68 if len(melody) == 0: | 65 if len(melody) == 0: |
69 self.bihist = [] | 66 return [] |
70 return self.bihist | |
71 melody_matrix = self.get_melody_matrix(melody) | 67 melody_matrix = self.get_melody_matrix(melody) |
68 bihist = [] | |
72 if secondframedecomp: | 69 if secondframedecomp: |
73 nbins, norigframes = melody_matrix.shape | 70 nbins, norigframes = melody_matrix.shape |
74 win2 = int(round(self.win2sec*self.chromasr)) | 71 win2 = int(round(self.win2sec * self.melody_sr)) |
75 hop2 = int(round(0.5*self.chromasr)) | 72 hop2 = int(round(self.hop2sec * self.melody_sr)) |
76 if norigframes<=win2: | 73 if norigframes<=win2: |
77 nframes = 1 | 74 nframes = 1 |
78 win2 = norigframes | 75 win2 = norigframes |
79 else: | 76 else: |
80 nframes = int(np.ceil((norigframes-win2)/float(hop2))) | 77 nframes = int(np.ceil((norigframes-win2)/float(hop2))) |
82 for i in range(nframes): # loop over all 8-sec frames | 79 for i in range(nframes): # loop over all 8-sec frames |
83 frame = melody_matrix[:, (i*hop2):(i*hop2+win2)] | 80 frame = melody_matrix[:, (i*hop2):(i*hop2+win2)] |
84 bihist = self.bihistogram(frame) | 81 bihist = self.bihistogram(frame) |
85 bihist = np.reshape(bihist, -1) | 82 bihist = np.reshape(bihist, -1) |
86 bihistframes[:, i] = bihist | 83 bihistframes[:, i] = bihist |
87 self.bihist = bihistframes | 84 bihist = bihistframes |
88 else: | 85 else: |
89 self.bihist = self.bihistogram(melody_matrix) | 86 bihist = self.bihistogram(melody_matrix) |
90 return self.bihist | 87 return bihist |
91 | 88 |
92 | 89 |
93 def bihistogram(self, spec, winsec=0.5, align=True): | 90 def bihistogram(self, spec, spec_sr=None, winsec=0.5, align=True): |
94 win = int(round(winsec*self.chromasr)) | 91 if spec_sr is None: |
92 # assume spec is melody_matrix with default sr | |
93 spec_sr = self.melody_sr | |
94 win = int(round(winsec * spec_sr)) | |
95 ker = np.concatenate([np.zeros((win, 1)), np.ones((win+1, 1))], axis=0) | 95 ker = np.concatenate([np.zeros((win, 1)), np.ones((win+1, 1))], axis=0) |
96 spec = spec.T # transpose to have franes as rows in convolution | 96 spec = spec.T # transpose to have frames as rows in convolution |
97 | 97 |
98 # energy threshold | 98 # energy threshold |
99 thr = 0.3*np.max(spec) | 99 thr = 0.3*np.max(spec) |
100 spec[spec < max(thr, 0)] = 0 | 100 spec[spec < max(thr, 0)] = 0 |
101 | 101 |
118 B = np.roll(B, -ref, axis=0) | 118 B = np.roll(B, -ref, axis=0) |
119 B = np.roll(B, -ref, axis=1) | 119 B = np.roll(B, -ref, axis=1) |
120 return B | 120 return B |
121 | 121 |
122 | 122 |
123 def bihist_from_chroma(self, filename='test.wav', secondframedecomp=True): | |
124 self.chroma, self.chromasr = s.get_smoothie_for_bihist(filename=filename, hopinsec=0.005) | |
125 if secondframedecomp: | |
126 win2 = int(round(8*self.chromasr)) | |
127 hop2 = int(round(0.5*self.chromasr)) | |
128 nbins, norigframes = self.chroma.shape | |
129 if norigframes<win2: | |
130 nframes = 1 | |
131 else: | |
132 nframes = int(1+np.floor((norigframes-win2)/float(hop2))) | |
133 bihistframes = np.empty((nbins*nbins, nframes)) | |
134 for i in range(nframes): # loop over all 8-sec frames | |
135 frame = self.chroma[:, (i*hop2):min((i*hop2+win2),norigframes)] | |
136 bihist = self.bihistogram(frame) | |
137 bihist = np.reshape(bihist, -1) | |
138 bihistframes[:, i] = bihist | |
139 self.bihist = bihistframes | |
140 else: | |
141 self.bihist = np.reshape(self.bihistogram(), -1) | |
142 | |
143 | |
144 def bihist_from_precomp_chroma(self, align=False): | |
145 win2 = int(round(self.win2sec*self.chromasr)) | |
146 hop2 = int(round(0.5*self.chromasr)) | |
147 nbins, norigframes = self.chroma.shape | |
148 if norigframes<win2: | |
149 nframes = 1 | |
150 else: | |
151 nframes = int(1+np.floor((norigframes-win2)/float(hop2))) | |
152 bihistframes = np.empty((nbins*nbins, nframes)) | |
153 for i in range(nframes): # loop over all 8-sec frames | |
154 frame = self.chroma[:, (i*hop2):min((i*hop2+win2),norigframes)] | |
155 bihist = self.bihistogram(frame, align=align) | |
156 bihist = np.reshape(bihist, -1) | |
157 bihistframes[:, i] = bihist | |
158 self.bihist = bihistframes | |
159 | |
160 def get_pitchbihist(self, filename='test.wav'): | |
161 self.bihist_from_chroma(filename=filename) | |
162 return self.bihist | |
163 | |
164 def get_pitchbihist_from_chroma(self, chroma=[], chromasr=[]): | |
165 self.chroma = chroma | |
166 self.chromasr = chromasr | |
167 self.bihist_from_precomp_chroma(align=False) | |
168 return self.bihist | |
169 | |
170 | |
171 if __name__ == '__main__': | 123 if __name__ == '__main__': |
172 pb = PitchBihist() | 124 pb = PitchBihist() |
173 pb.get_pitchbihist() | 125 pb.bihist_from_melodia(filename='vamp_melodia.csv') |