Mercurial > hg > chourdakisreiss2016
comparison experiment-reverb/code/ui.py @ 0:246d5546657c
initial commit, needs cleanup
author | Emmanouil Theofanis Chourdakis <e.t.chourdakis@qmul.ac.uk> |
---|---|
date | Wed, 14 Dec 2016 13:15:48 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:246d5546657c |
---|---|
1 # -*- coding: utf-8 -*- | |
2 """ | |
3 Created on Thu Jun 11 11:03:04 2015 | |
4 | |
5 @author: mmxgn | |
6 """ | |
7 | |
8 | |
9 import matplotlib | |
10 matplotlib.use("TkAgg") | |
11 from matplotlib.figure import Figure | |
12 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg | |
13 | |
14 import pyaudio | |
15 from sys import argv, exit | |
16 from essentia.standard import YamlInput, YamlOutput, AudioLoader, AudioWriter | |
17 from essentia import Pool | |
18 from pca import * | |
19 | |
20 from numpy import * | |
21 from sklearn import cluster | |
22 from sklearn.metrics import pairwise_distances | |
23 from sklearn.cluster import KMeans, MiniBatchKMeans | |
24 from matplotlib.pyplot import * | |
25 #from sklearn.mixture import GMM | |
26 from sklearn.naive_bayes import GaussianNB, MultinomialNB | |
27 from scipy.signal import decimate | |
28 from sklearn import cross_validation | |
29 from Tkinter import * | |
30 import tkMessageBox | |
31 import thread | |
32 from numpy.core._internal import _gcd as gcd | |
33 import time | |
34 import os | |
35 import subprocess | |
36 from scikits.audiolab import Format, Sndfile | |
37 from scipy.signal import fftconvolve | |
38 from glob import glob | |
39 | |
40 def zafar(lx, rx, d1, g1, da, G, gc, m): | |
41 """ Rafii & Pardo Reverberator (2009) controlled by High Level parameters | |
42 Inputs: | |
43 lx : left channel input | |
44 rx : right channel input | |
45 d1 : delay of first comb filter in samples | |
46 g1 : gain of first comb filters | |
47 da : delay of allpass filter in samples | |
48 G : dry/wet mix gain | |
49 gc : lowpass filter gain | |
50 m : difference between left and right channel phases | |
51 | |
52 Outputs: | |
53 ly: left channel output | |
54 ry: right channel output | |
55 """ | |
56 | |
57 def calculate_parameters(d1,g1): | |
58 | |
59 d2 = int(round((1.5)**(-1)*d1)) | |
60 | |
61 while gcd(d2,d1) != 1: | |
62 d2 += 1 | |
63 | |
64 d3 = int(round((1.5)**(-2)*d1)) | |
65 | |
66 while gcd(d3, d2) != 1 or gcd(d3, d1) != 1: | |
67 d3 += 1 | |
68 | |
69 d4 = int(round((1.5)**(-3)*d1)) | |
70 | |
71 while gcd(d4, d3) != 1 or gcd(d4, d2) != 1 or gcd(d4, d1) != 1: | |
72 d4 += 1 | |
73 | |
74 | |
75 d5 = int(round((1.5)**(-4)*d1)) | |
76 | |
77 while gcd(d5, d4) != 1 or gcd(d5, d3) != 1 or gcd(d5, d2) != 1 or gcd(d5, d1) != 1: | |
78 d5 += 1 | |
79 | |
80 d6 = int(round((1.5)**(-5)*d1)) | |
81 while gcd(d6, d5) != 1 or gcd(d6, d4) != 1 or gcd(d6, d3) != 1 or gcd(d6, d2) != 1 or gcd(d6, d1) != 1: | |
82 d6 += 1 | |
83 g2 = g1**(1.5)**(-1)*g1 | |
84 g3 = g1**(1.5)**(-2)*g1 | |
85 g4 = g1**(1.5)**(-3)*g1 | |
86 g5 = g1**(1.5)**(-4)*g1 | |
87 g6 = g1**(1.5)**(-5)*g1 | |
88 | |
89 return (d1, d2, d3, d4, d5, d6, g1, g2, g3, g4, g5, g6) | |
90 def comb_array(x, g1, d1): | |
91 | |
92 (d1,d2,d3,d4,d5,d6,g1,g2,g3,g4,g5,g6) = calculate_parameters(d1,g1) | |
93 | |
94 | |
95 | |
96 c1out = comb(x, g1, d1) | |
97 c2out = comb(x, g2, d2) | |
98 c3out = comb(x, g3, d3) | |
99 c4out = comb(x, g4, d4) | |
100 c5out = comb(x, g5, d5) | |
101 c6out = comb(x, g6, d6) | |
102 | |
103 | |
104 Lc1 = len(c1out) | |
105 Lc2 = len(c2out) | |
106 Lc3 = len(c3out) | |
107 Lc4 = len(c4out) | |
108 Lc5 = len(c5out) | |
109 Lc6 = len(c6out) | |
110 | |
111 Lc = max(Lc1, Lc2, Lc3, Lc4, Lc5, Lc6) | |
112 | |
113 y = zeros((Lc, )) | |
114 | |
115 y[0:Lc1] = c1out | |
116 y[0:Lc2] += c2out | |
117 y[0:Lc3] += c3out | |
118 y[0:Lc4] += c4out | |
119 y[0:Lc5] += c5out | |
120 y[0:Lc6] += c6out | |
121 | |
122 return y | |
123 | |
124 def comb(x, g, d): | |
125 LEN = len(x)+d | |
126 print d | |
127 y = zeros((LEN,)) | |
128 for n in range(0, LEN): | |
129 if n - d < 0: | |
130 y[n] = 0 | |
131 else: | |
132 y[n] = x[n-d] + g*y[n-d] | |
133 | |
134 return y | |
135 | |
136 def allpass(x, g, d): | |
137 LENx = len(x) | |
138 LENy = LENx+d | |
139 y = zeros((LENy,)) | |
140 for n in range(0, LENy): | |
141 if n-d < 0: | |
142 y[n] = -g*x[n] | |
143 elif n >= LENx: | |
144 y[n] = x[n-d] + g*y[n-d] | |
145 else: | |
146 y[n] = x[n-d] - g*x[n] + g*y[n-d] | |
147 | |
148 return y | |
149 | |
150 def lowpass(x, g): | |
151 LEN = len(x) | |
152 y = zeros((LEN,)) | |
153 | |
154 for n in range(0, LEN): | |
155 if n-1 < 0: | |
156 y[n] = (1-g)*x[n] | |
157 else: | |
158 y[n] = (1-g)*x[n] + g*y[n-1] | |
159 | |
160 return y | |
161 | |
162 ga = 1./sqrt(2.) | |
163 | |
164 cin = 0.5*lx + 0.5*rx | |
165 cout = comb_array(cin, g1, d1) | |
166 | |
167 | |
168 ra = allpass(cout, ga, da+m/2) | |
169 la = allpass(cout, ga, da-m/2) | |
170 | |
171 ral = lowpass(ra, gc) | |
172 lal = lowpass(la, gc) | |
173 | |
174 ralg = G*ral | |
175 lalg = G*lal | |
176 | |
177 ry = ralg[0:len(rx)] + (1-G)*rx | |
178 ly = lalg[0:len(lx)] + (1-G)*lx | |
179 | |
180 # ry = cout | |
181 # ly = cout | |
182 | |
183 | |
184 | |
185 return (ry, ly) | |
186 | |
187 class UI: | |
188 | |
189 def __init__(self, master, directory): | |
190 self.master = master | |
191 | |
192 self.directory = directory | |
193 | |
194 | |
195 | |
196 yamlinput = YamlInput(filename="session.yaml") | |
197 | |
198 try: | |
199 self.sessionpool = yamlinput() | |
200 try: | |
201 self.files_to_visit = self.sessionpool['files_to_visit'] | |
202 except: | |
203 self.files_to_visit = [] | |
204 | |
205 try: | |
206 self.visited_files = self.sessionpool['visited_files'] | |
207 except: | |
208 self.visited_files = [] | |
209 | |
210 | |
211 | |
212 except: | |
213 print "[II] Could not open sessionpool file, creating a new one" | |
214 self.sessionpool = Pool() | |
215 self.files_to_visit = glob("%s/*.wav" % directory) | |
216 for i in self.files_to_visit: | |
217 self.sessionpool.add('files_to_visit', i) | |
218 self.visited_files = [] | |
219 | |
220 if len(self.files_to_visit) == 0: | |
221 tkMessageBox.showinfo("","No files to visit") | |
222 master.destroy() | |
223 return | |
224 | |
225 filename = self.files_to_visit[-1] | |
226 self.filename = filename | |
227 # visited_files.append(filename) | |
228 self.label_top = Label(master, text="") | |
229 self.label_top.grid(row=0, column=0, columnspan=6) | |
230 | |
231 self.load_song(filename) | |
232 | |
233 | |
234 # Top Label | |
235 | |
236 self.label_top.config( text="Training song: %s (sampleRate: %.0f, nChannels: %d) - %d songs left" % (filename, self.SR, self.numChannels, len(self.files_to_visit)-1)) | |
237 | |
238 # Sliders | |
239 | |
240 self.scale_d1 = Scale(master, to_=0.01, from_=0.1, resolution=0.01, label="d1", showvalue=True)#, command=self.callback_update_parameters) | |
241 self.scale_d1.bind("<ButtonRelease-1>",self.callback_update_parameters) | |
242 self.scale_d1.grid(row=1,column=0,rowspan=17,sticky=N+S+E+W) | |
243 self.scale_g1 = Scale(master,to_=0.01, from_=0.99, resolution=0.01, label="g1", showvalue=True)#, command=self.callback_update_parameters) | |
244 self.scale_g1.bind("<ButtonRelease-1>",self.callback_update_parameters) | |
245 | |
246 self.scale_g1.grid(row=1,column=1,rowspan=17,sticky=N+S+E+W) | |
247 self.scale_da = Scale(master, to_=0.006, from_=0.012, resolution=0.001, label="da", showvalue=True)#, command=self.callback_update_parameters) | |
248 self.scale_da.bind("<ButtonRelease-1>",self.callback_update_parameters) | |
249 | |
250 self.scale_da.grid(row=1,column=2,rowspan=17,sticky=N+S+E+W) | |
251 self.scale_G = Scale(master,to_=0.01, from_=0.99, resolution=0.01, label="G", showvalue=True)#, command=self.callback_update_parameters) | |
252 self.scale_G.bind("<ButtonRelease-1>",self.callback_update_parameters) | |
253 | |
254 self.scale_G.grid(row=1,column=3,rowspan=17,sticky=N+S+E+W) | |
255 self.scale_gc = Scale(master, to_=0.01, from_=0.99, resolution=0.01, label="gc", showvalue=True)#, command=self.callback_update_parameters) | |
256 self.scale_gc.bind("<ButtonRelease-1>",self.callback_update_parameters) | |
257 | |
258 self.scale_gc.grid(row=1,column=4,rowspan=17,sticky=N+S+E+W) | |
259 | |
260 | |
261 # Labels | |
262 | |
263 self.label_T60 = Label(master, text="Reverberation Time: ") | |
264 self.label_T60.grid(row=2,column=6,sticky=N+S+E+W) | |
265 self.label_D = Label(master, text="Echo Density: ") | |
266 self.label_D.grid(row=3,column=6,sticky=N+S+E+W) | |
267 self.label_C = Label(master, text="Clarity: ") | |
268 self.label_C.grid(row=4,column=6,sticky=N+S+E+W) | |
269 self.label_Tc = Label(master, text="Central Time: ") | |
270 self.label_Tc.grid(row=5,column=6,sticky=N+S+E+W) | |
271 self.label_SC = Label(master, text="Spectral Centroid: ") | |
272 self.label_SC.grid(row=6,column=6,sticky=N+S+E+W) | |
273 | |
274 | |
275 # Buttons | |
276 | |
277 self.button_plot_impulse = Button(master, text="Plot Impulse",command=self.callback_plot_impulse, width=15).grid(row=7,column=6,sticky=N+S+E+W) | |
278 self.button_plot_raw = Button(master, text="Plot Raw", width=15,command=self.callback_plot_raw).grid(row=8,column=6,sticky=N+S+E+W) | |
279 self.button_plot_reverb = Button(master, text="Plot Reverb", width=15, command=self.callback_plot_reverb).grid(row=9, column=6,sticky=N+S+E+W) | |
280 self.button_play_raw = Button(master, text="Play Raw", bg="green", fg="white", width=15, command=self.callback_play_raw).grid(row=10, column=6,sticky=N+S+E+W) | |
281 self.button_play_reverb = Button(master, text="Play Reverb", bg="green", fg="white", width=15, command=self.callback_play_reverb).grid(row=11, column=6,sticky=N+S+E+W) | |
282 self.button_stop = Button(master, text="Stop Playing", bg="red", fg="white", width=15, command=self.callback_stop).grid(row=12, column=6,sticky=N+S+E+W) | |
283 self.button_save = Button(master, text="Save", fg="white", bg="orange", width=15, command=self.callback_save).grid(row=13, column=6,sticky=N+S+E+W) | |
284 self.button_reset = Button(master, text="Undo", width=15, command=self.callback_reset).grid(row=14, column=6,sticky=N+S+E+W) | |
285 self.button_next = Button(master, text="Next >>", width=15, command=self.callback_next).grid(row=15, column=6,sticky=N+S+E+W) | |
286 | |
287 | |
288 | |
289 # Figure | |
290 | |
291 self.figure = Figure( dpi=50) | |
292 self.figure.text(0.5,0.5,'No plot selected', weight = "bold", horizontalalignment='center') | |
293 | |
294 | |
295 # a tk.DrawingArea | |
296 self.canvas = FigureCanvasTkAgg(self.figure, master=root) | |
297 #self.canvas.get_tk_widget().config(height=500, width=640) | |
298 self.canvas.show() | |
299 self.canvas.get_tk_widget().grid(row=0, column=7, rowspan=17, padx=20,sticky=E+W+N+S) | |
300 | |
301 # toolbar = NavigationToolbar2TkAgg( master, master ) | |
302 # toolbar.update() | |
303 self.canvas._tkcanvas.grid(row=0, column=7, rowspan=17) | |
304 # self.scale_d1.pack() | |
305 | |
306 # Toolbar for canvas | |
307 | |
308 self.toolbar_frame = Frame(master) | |
309 self.toolbar_frame.grid(row=17,column=7,sticky=E+W+N+S, padx=19) | |
310 self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.toolbar_frame) | |
311 | |
312 | |
313 | |
314 Grid.columnconfigure(master, 7, weight=1) | |
315 Grid.rowconfigure(master, 1, weight=1) | |
316 | |
317 # Status bar | |
318 | |
319 self.status_bar_text = Label(text="Ready.") | |
320 self.status_bar_text.grid(row=18, column=0, columnspan = 8, sticky=N+S+E, padx=10) | |
321 | |
322 self.lastplot = '' | |
323 self.parameterschanged_render = True | |
324 self.pendingactions = [] | |
325 | |
326 # Initial values | |
327 | |
328 d1t = 0.05 | |
329 self.d1 = d1t*self.SR | |
330 dat = 0.006 | |
331 self.da = dat*self.SR | |
332 g1 = 0.5 | |
333 self.g1 = g1 | |
334 G = 0.5 | |
335 self.G = G | |
336 gc = 0.5 | |
337 self.gc = gc | |
338 | |
339 self.scale_d1.set(d1t) | |
340 self.scale_da.set(dat) | |
341 self.scale_g1.set(g1) | |
342 self.scale_gc.set(gc) | |
343 self.scale_G.set(G) | |
344 | |
345 t = zeros((self.SR*120,)) | |
346 t[0] = 1 | |
347 | |
348 self.impulse = t | |
349 | |
350 # self.callback_plot_impulse() | |
351 | |
352 | |
353 # Pyaudio object | |
354 | |
355 # self.player = pyaudio.PyAudio() | |
356 | |
357 # self.player_idx = 0 | |
358 # | |
359 # self.playerprocess = None | |
360 | |
361 | |
362 # Pool | |
363 | |
364 self.pool = Pool() | |
365 self.pool.set('filename', self.filename) | |
366 self.pool.set('sampleRate', self.SR) | |
367 self.pool.set('nChannels', self.numChannels) | |
368 | |
369 | |
370 # Finally | |
371 self.callback_update_parameters(None) | |
372 | |
373 | |
374 | |
375 | |
376 | |
377 def pyaudio_callback_raw(self, in_data, frame_count, time_info, status): | |
378 if self.player_command == 'Stop': | |
379 return (0, pyaudio.paAbort) | |
380 | |
381 data = self.audio[self.player_idx:self.player_idx+frame_count, :] | |
382 | |
383 data = reshape(data, (data.shape[0]*data.shape[1], 1)) | |
384 | |
385 # print data | |
386 self.player_idx += frame_count | |
387 | |
388 | |
389 return (data, pyaudio.paContinue) | |
390 | |
391 | |
392 def play_reverb(self): | |
393 | |
394 self.calculate_impulse_response() | |
395 ly, ry = self.impulse_response_left_channel, self.impulse_response_right_channel | |
396 | |
397 lx = self.audio[:,0] | |
398 rx = self.audio[:,1] | |
399 | |
400 print "Convolving left channel" | |
401 l_out = fftconvolve(ly, lx) | |
402 | |
403 print "Convolving right channel" | |
404 r_out = fftconvolve(ry, rx) | |
405 | |
406 | |
407 | |
408 lim = min(len(l_out), len(r_out)) | |
409 | |
410 | |
411 | |
412 if self.numChannels == 1: | |
413 audio_out = l_out[0:lim] | |
414 else: | |
415 audio_out = concatenate((matrix(l_out[0:lim]).T, | |
416 matrix(r_out[0:lim]).T | |
417 ), | |
418 axis=1) | |
419 | |
420 reverb_filename = "%s_reverb_%s" % (self.filename.split('.')[0], self.filename.split('.')[1]) | |
421 | |
422 audio_file = Sndfile(reverb_filename, 'w', Format(self.filename.split('.')[1]), self.numChannels, self.SR) | |
423 audio_file.write_frames(audio_out) | |
424 audio_file.close() | |
425 | |
426 self.reverberated_audio = audio_out | |
427 # | |
428 # audiowriter(audio_out) | |
429 | |
430 self.reverb_filename = reverb_filename | |
431 | |
432 self.playerprocess = subprocess.Popen("mplayer %s" % reverb_filename, | |
433 stdout = subprocess.PIPE, | |
434 shell=True, | |
435 preexec_fn=os.setsid) | |
436 | |
437 def play_raw(self): | |
438 self.playerprocess = subprocess.Popen("mplayer %s" % self.filename, | |
439 stdout = subprocess.PIPE, | |
440 shell=True, | |
441 preexec_fn=os.setsid) | |
442 | |
443 | |
444 | |
445 | |
446 | |
447 def remove_action_from_status(self, text): | |
448 | |
449 self.pendingactions.remove(text) | |
450 | |
451 if len(self.pendingactions) == 0: | |
452 self.status_bar_text.config(text='Ready.') | |
453 elif len(self.pendingactions) == 1: | |
454 self.status_bar_text.config(text=self.pendingactions[0]+'.') | |
455 else: | |
456 self.status_bar_text.config(text=reduce(lambda h,t: h+','+t, self.pendingactions)+'.') | |
457 | |
458 | |
459 def add_action_to_status(self, text): | |
460 | |
461 self.pendingactions.append(text) | |
462 | |
463 if len(self.pendingactions) == 0: | |
464 self.status_bar_text.config(text='Ready.') | |
465 elif len(self.pendingactions) == 1: | |
466 self.status_bar_text.config(text=text+'.') | |
467 else: | |
468 self.status_bar_text.config(text=reduce(lambda h,t: h+', '+t, self.pendingactions)+'.') | |
469 | |
470 print self.pendingactions, len(self.pendingactions) | |
471 | |
472 | |
473 def load_song(self, filename): | |
474 # self.label_top.config(text="Training '%s'" % filename) | |
475 # print filename | |
476 #self.audio, self.SR, self.numChannels = AudioLoader(filename=filename)() | |
477 tup = AudioLoader(filename=filename)() | |
478 self.audio = tup[0] | |
479 self.SR = tup[1] | |
480 self.numChannels = tup[2] | |
481 self.label_top.config(text="Training song: %s (sampleRate: %.0f, nChannels: %d) - %d songs left" % (filename, self.SR, self.numChannels, len(self.files_to_visit)-1)) | |
482 self.saved = False | |
483 | |
484 | |
485 | |
486 | |
487 def estimate_T60(self, d1, g1, gc, G, SR): | |
488 ga = 1/sqrt(2) | |
489 return d1/SR/log(g1)*log(10**-3/ga/(1-gc)/G) | |
490 | |
491 def calculate_parameters(self,d1,g1): | |
492 | |
493 d2 = int(round((1.5)**(-1)*d1)) | |
494 | |
495 while gcd(d2,d1) != 1: | |
496 d2 += 1 | |
497 | |
498 d3 = int(round((1.5)**(-2)*d1)) | |
499 | |
500 while gcd(d3, d2) != 1 or gcd(d3, d1) != 1: | |
501 d3 += 1 | |
502 | |
503 d4 = int(round((1.5)**(-3)*d1)) | |
504 | |
505 while gcd(d4, d3) != 1 or gcd(d4, d2) != 1 or gcd(d4, d1) != 1: | |
506 d4 += 1 | |
507 | |
508 | |
509 d5 = int(round((1.5)**(-4)*d1)) | |
510 | |
511 while gcd(d5, d4) != 1 or gcd(d5, d3) != 1 or gcd(d5, d2) != 1 or gcd(d5, d1) != 1: | |
512 d5 += 1 | |
513 | |
514 d6 = int(round((1.5)**(-5)*d1)) | |
515 while gcd(d6, d5) != 1 or gcd(d6, d4) != 1 or gcd(d6, d3) != 1 or gcd(d6, d2) != 1 or gcd(d6, d1) != 1: | |
516 d6 += 1 | |
517 g2 = g1**(1.5)**(-1)*g1 | |
518 g3 = g1**(1.5)**(-2)*g1 | |
519 g4 = g1**(1.5)**(-3)*g1 | |
520 g5 = g1**(1.5)**(-4)*g1 | |
521 g6 = g1**(1.5)**(-5)*g1 | |
522 | |
523 return (d1, d2, d3, d4, d5, d6, g1, g2, g3, g4, g5, g6) | |
524 def estimate_C(self, g1, G, gc): | |
525 g2 = g1**(1.5)**(-1)*g1 | |
526 g3 = g1**(1.5)**(-2)*g1 | |
527 g4 = g1**(1.5)**(-3)*g1 | |
528 g5 = g1**(1.5)**(-4)*g1 | |
529 g6 = g1**(1.5)**(-5)*g1 | |
530 gains = zeros((6,1)) | |
531 gains[0] = g1 | |
532 gains[1] = g2 | |
533 gains[2] = g3 | |
534 gains[3] = g4 | |
535 gains[4] = g5 | |
536 gains[5] = g6 | |
537 | |
538 return -10*log10(G**2*(1-gc)/(1+gc)*sum(1/(1-gains**2))) | |
539 | |
540 def estimate_D(self, d1, g1, da, SR): | |
541 Dm = zeros((6,10)) | |
542 delays = zeros((6,)) | |
543 gains = zeros((6,1)) | |
544 (delays[0],delays[1],delays[2],delays[3],delays[4],delays[5],gains[0],gains[1],gains[2],gains[3],gains[4],gains[5]) = self.calculate_parameters(d1,g1) | |
545 for k in range(1, 7): | |
546 for m in range(1, 11): | |
547 Dm[k-1,m-1] = max(0.1-m*delays[k-1]/SR,0) | |
548 | |
549 return 10/da*self.SR*sum(Dm) | |
550 | |
551 def estimate_Tc(self, d1, g1, da, SR): | |
552 delays = zeros((6,)) | |
553 gains = zeros((6,1)) | |
554 (delays[0],delays[1],delays[2],delays[3],delays[4],delays[5],gains[0],gains[1],gains[2],gains[3],gains[4],gains[5]) = self.calculate_parameters(d1,g1) | |
555 return sum(delays/SR*gains**2/(1-gains**2)**2)/sum(gains**2/(1-gains**2)) + da/SR | |
556 | |
557 | |
558 def callback_update_parameters(self,_): | |
559 SR = self.SR | |
560 d1t = self.scale_d1.get() | |
561 print d1t | |
562 | |
563 d1 = round(d1t*SR) | |
564 g1 = self.scale_g1.get() | |
565 dat = self.scale_da.get() | |
566 da = round(dat*SR) | |
567 G = self.scale_G.get() | |
568 gc = self.scale_gc.get() | |
569 | |
570 | |
571 T60 = self.estimate_T60(d1,g1,gc,G,SR) | |
572 D = self.estimate_D(d1, g1, da, SR)/10 | |
573 C = self.estimate_C(g1, G, gc) | |
574 Tc = self.estimate_Tc(d1,g1,da,SR) | |
575 SC = self.estimate_SC(gc, SR) | |
576 | |
577 self.d1_old = self.d1 | |
578 self.G_old = self.G | |
579 self.gc_old = self.gc | |
580 self.g1_old = self.g1 | |
581 self.da_old = self.da | |
582 | |
583 self.d1 = d1 | |
584 self.G = G | |
585 self.gc = gc | |
586 self.g1 = g1 | |
587 self.da = da | |
588 | |
589 | |
590 | |
591 self.pool.set('parameters.d1', d1t) | |
592 self.pool.set('parameters.G', G) | |
593 self.pool.set('parameters.gc', gc) | |
594 self.pool.set('parameters.g1', g1) | |
595 self.pool.set('parameters.da', dat) | |
596 | |
597 | |
598 | |
599 self.T60 = T60 | |
600 self.D = D | |
601 self.Tc = Tc | |
602 self.SC = SC | |
603 self.C = C | |
604 | |
605 self.pool.set('parameters.T60', T60) | |
606 self.pool.set('parameters.D', D) | |
607 self.pool.set('parameters.C', C) | |
608 self.pool.set('parameters.Tc', Tc) | |
609 self.pool.set('parameters.SC', SC) | |
610 | |
611 self.label_T60.config(text="Reverberation Time: %.3fs" % T60) | |
612 self.label_D.config(text="Echo Density: %.3f at 0.1s" % D) | |
613 self.label_C.config(text="Clarity: %.3f dB" % C) | |
614 self.label_Tc.config(text="Central Time: %.3fs" % Tc) | |
615 self.label_SC.config(text="Spectral Centroid: %.3f Hz" % SC) | |
616 | |
617 self.lastplot = '' | |
618 self.parameterschanged_render = True | |
619 # self.callback_plot_impulse() | |
620 | |
621 | |
622 def estimate_SC(self, gc, SR): | |
623 n = arange(0, SR/2+1) | |
624 return sum(n/(1+gc**2-2*gc*cos(2*pi*n/SR)))/sum(1/(1+gc**2-2*gc*cos(2*pi*n/SR))) | |
625 | |
626 | |
627 | |
628 | |
629 def say_hi(self): | |
630 print "Hi, there" | |
631 | |
632 def callback_plot_impulse(self): | |
633 try: | |
634 thread.start_new_thread(self.plot_impulse, ()) | |
635 except: | |
636 print "[EE] Could not start new thread" | |
637 | |
638 | |
639 | |
640 def calculate_impulse_response(self): | |
641 self.add_action_to_status('Calculating impulse response') | |
642 N = self.numChannels | |
643 SR = self.SR | |
644 T = 1.0/self.SR | |
645 | |
646 delta = self.impulse[0:int(self.T60*self.SR)] | |
647 print "delta:" | |
648 print delta | |
649 | |
650 d1 = int(self.d1) | |
651 g1 = self.g1 | |
652 da = int(self.da) | |
653 G = self.G | |
654 gc = self.gc | |
655 | |
656 mt = 0.002 | |
657 m = int(mt*SR) | |
658 | |
659 (ly, ry) = zafar(delta,delta,d1,g1,da,G,gc,m) | |
660 | |
661 limt = self.T60 | |
662 | |
663 lim = int(limt*SR) | |
664 t = arange(0, lim)*T | |
665 | |
666 padded_y = zeros(shape(t)) | |
667 padded_y[0:len(ly)] = ly | |
668 | |
669 | |
670 padded_y = zeros(shape(t)) | |
671 padded_y[0:len(ry)] = ry | |
672 | |
673 ry = padded_y | |
674 | |
675 self.impulse_response_left_channel = ly | |
676 self.impulse_response_right_channel = ry | |
677 | |
678 | |
679 self.remove_action_from_status('Calculating impulse response') | |
680 | |
681 | |
682 | |
683 def plot_impulse(self): | |
684 if self.lastplot != 'impulse': | |
685 self.add_action_to_status('Plotting impulse response') | |
686 N = self.numChannels | |
687 SR = self.SR | |
688 T = 1.0/self.SR | |
689 | |
690 delta = self.impulse[0:int(self.T60*self.SR)] | |
691 print "delta:" | |
692 print delta | |
693 | |
694 d1 = int(self.d1) | |
695 g1 = self.g1 | |
696 da = int(self.da) | |
697 G = self.G | |
698 gc = self.gc | |
699 | |
700 mt = 0.002 | |
701 m = int(mt*SR) | |
702 | |
703 print "Calculating zafar" | |
704 (ly, ry) = zafar(delta,delta,d1,g1,da,G,gc,m) | |
705 | |
706 print "Stopped calculating zafar"#ly.shape | |
707 limt = self.T60 | |
708 | |
709 lim = int(limt*SR) | |
710 print "lim:", lim | |
711 | |
712 t = arange(0, lim)*T | |
713 # print t | |
714 | |
715 # Pad ly to t | |
716 print "Shape ly" | |
717 print ly | |
718 print len(ly) | |
719 padded_y = zeros(shape(t)) | |
720 padded_y[0:len(ly)] = ly | |
721 | |
722 print "Padded y" | |
723 #print padded_y | |
724 | |
725 # ly = padded_y | |
726 | |
727 # Pad ry to t | |
728 | |
729 padded_y = zeros(shape(t)) | |
730 padded_y[0:len(ry)] = ry | |
731 | |
732 ry = padded_y | |
733 | |
734 | |
735 | |
736 self.figure.clear() | |
737 | |
738 print "Passed A" | |
739 subplt0 = self.figure.add_subplot(2,1,1) | |
740 | |
741 subplt0.plot(t,abs(ly[0:lim])) | |
742 subplt0.set_title('Left Channel') | |
743 subplt0.set_xlabel('time (s)') | |
744 subplt0.set_ylabel('amplitude') | |
745 subplt0.axvspan(0,0.1, alpha=0.1,color='cyan') | |
746 subplt0.axvline(self.Tc, color='red', linestyle='--') | |
747 subplt0.axvline(0.1, color='cyan', linestyle='--') | |
748 subplt0.annotate('Central Time (Tc)', xy=(self.Tc, 0.5), xytext=(self.Tc+0.01, 0.52), arrowprops=dict(facecolor='black',width=1)) | |
749 subplt0.annotate('Echo Density (D) Measurement Point ', xy=(0.1, 0.6), xytext=(.11, 0.62), arrowprops=dict(facecolor='black',width=1)) | |
750 | |
751 # | |
752 | |
753 subplt1 = self.figure.add_subplot(2,1,2,sharex=subplt0) | |
754 subplt1.set_title('Right Channel') | |
755 | |
756 subplt1.plot(t,abs(ry[0:lim])) | |
757 subplt1.set_xlabel('time (s)') | |
758 subplt1.set_ylabel('amplitude') | |
759 subplt1.axvspan(0,0.1, alpha=0.1,color='cyan') | |
760 subplt1.axvline(self.Tc, color='red', linestyle='--') | |
761 subplt1.axvline(0.1, color='cyan', linestyle='--') | |
762 | |
763 | |
764 self.figure.suptitle("Reverberation Impulse Response") | |
765 | |
766 # print "Passed B" | |
767 # | |
768 self.remove_action_from_status('Plotting impulse response') | |
769 self.canvas.draw() | |
770 | |
771 self.lastplot = 'impulse' | |
772 # | |
773 thread.exit_thread() | |
774 | |
775 | |
776 | |
777 def plot_raw(self): | |
778 if self.lastplot != 'raw': | |
779 self.add_action_to_status('Plotting raw') | |
780 N = self.numChannels | |
781 print "Channels: %d" % N | |
782 L = len(self.audio[:,0]) | |
783 | |
784 | |
785 | |
786 | |
787 self.figure.clear() | |
788 | |
789 T = 1.0/self.SR | |
790 t = arange(0, L)*T | |
791 | |
792 oldsubplt = None | |
793 for n in range(0, N): | |
794 if oldsubplt is not None: | |
795 subplt = self.figure.add_subplot(N,1,n+1,sharex=oldsubplt) | |
796 else: | |
797 subplt = self.figure.add_subplot(N,1,n+1) | |
798 subplt.plot(t,self.audio[:,n]) | |
799 subplt.set_title('Channel %d' % n) | |
800 subplt.set_xlabel('time (s)') | |
801 subplt.set_ylabel('amplitude') | |
802 | |
803 oldsubplt = subplt | |
804 | |
805 | |
806 self.figure.suptitle('Raw Signal') | |
807 self.canvas.draw() | |
808 | |
809 self.lastplot = 'raw' | |
810 self.remove_action_from_status('Plotting raw') | |
811 thread.exit_thread() | |
812 def callback_plot_raw(self): | |
813 try: | |
814 thread.start_new_thread(self.plot_raw, ()) | |
815 except: | |
816 print "[EE] Could not start new thread" | |
817 | |
818 | |
819 | |
820 # show() | |
821 | |
822 def plot_reverb(self): | |
823 if self.lastplot != 'reverb': | |
824 self.add_action_to_status('Plotting reverberated signal') | |
825 | |
826 self.calculate_impulse_response() | |
827 ly, ry = self.impulse_response_left_channel, self.impulse_response_right_channel | |
828 | |
829 lx = self.audio[:,0] | |
830 rx = self.audio[:,1] | |
831 | |
832 print "Concolving left channel" | |
833 l_out = fftconvolve(ly, lx) | |
834 | |
835 print "Convolving right channel" | |
836 r_out = fftconvolve(ry, rx) | |
837 | |
838 | |
839 | |
840 lim = min(len(l_out), len(r_out)) | |
841 # N = self.numChannels | |
842 # SR = self.SR | |
843 # T = 1.0/self.SR | |
844 # | |
845 # | |
846 # d1 = int(self.d1) | |
847 # g1 = self.g1 | |
848 # da = int(self.da) | |
849 # G = self.G | |
850 # gc = self.gc | |
851 # | |
852 # mt = 0.002 | |
853 # m = int(mt*SR) | |
854 # | |
855 # lchannel = ravel(self.audio[:,0]) | |
856 # rchannel = ravel(self.audio[:,1]) | |
857 # | |
858 # print "Calculating zafar" | |
859 # | |
860 # if self.parameterschanged_render == True: | |
861 # (ly, ry) = zafar(lchannel,rchannel,d1,g1,da,G,gc,m) | |
862 # | |
863 # self.reverberated_signal_left_channel = ly | |
864 # self.reverberated_signal_right_channel = ry | |
865 # | |
866 # self.parameterschanged_render = 0 | |
867 # else: | |
868 # ly = self.reverberated_signal_left_channel | |
869 # ry = self.reverberated_signal_right_channel | |
870 # | |
871 # print "Stopped calculating zafar"#ly.shape | |
872 # # limt = self.T60 | |
873 # | |
874 # lim = int(limt*SR) | |
875 | |
876 # lim = len(lchannel) | |
877 # print "lim:", lim | |
878 T = 1/self.SR | |
879 t = arange(0, lim)*T | |
880 # print t | |
881 | |
882 # Pad ly to t | |
883 # print "Shape ly" | |
884 ## print ly | |
885 # print len(ly) | |
886 # padded_y = zeros(shape(t)) | |
887 # padded_y[0:len(ly)] = ly | |
888 | |
889 # print "Padded y" | |
890 #print padded_y | |
891 | |
892 # ly = padded_y | |
893 | |
894 # Pad ry to t | |
895 | |
896 # padded_y = zeros(shape(t)) | |
897 # padded_y[0:len(ry)] = ry | |
898 | |
899 # ry = padded_y | |
900 # | |
901 | |
902 | |
903 self.figure.clear() | |
904 | |
905 print "Passed A" | |
906 subplt0 = self.figure.add_subplot(2,1,1) | |
907 | |
908 subplt0.plot(t,l_out[0:lim]) | |
909 subplt0.set_title('Left Channel') | |
910 subplt0.set_xlabel('time (s)') | |
911 subplt0.set_ylabel('amplitude') | |
912 # subplt0.axvspan(0,0.1, alpha=0.1,color='cyan') | |
913 # subplt0.axvline(self.Tc, color='red', linestyle='--') | |
914 # subplt0.axvline(0.1, color='cyan', linestyle='--') | |
915 # subplt0.annotate('Central Time (Tc)', xy=(self.Tc, 0.5), xytext=(self.Tc+0.01, 0.52), arrowprops=dict(facecolor='black',width=1)) | |
916 # subplt0.annotate('Echo Density (D) Measurement Point ', xy=(0.1, 0.6), xytext=(.11, 0.62), arrowprops=dict(facecolor='black',width=1)) | |
917 | |
918 # | |
919 | |
920 subplt1 = self.figure.add_subplot(2,1,2,sharex=subplt0) | |
921 subplt1.set_title('Right Channel') | |
922 | |
923 subplt1.plot(t,r_out[0:lim]) | |
924 subplt1.set_xlabel('time (s)') | |
925 subplt1.set_ylabel('amplitude') | |
926 # subplt1.axvspan(0,0.1, alpha=0.1,color='cyan') | |
927 # subplt1.axvline(self.Tc, color='red', linestyle='--') | |
928 # subplt1.axvline(0.1, color='cyan', linestyle='--') | |
929 | |
930 | |
931 self.figure.suptitle("Reverberated Signal") | |
932 | |
933 # print "Passed B" | |
934 # | |
935 self.remove_action_from_status('Plotting reverberated signal') | |
936 self.canvas.draw() | |
937 | |
938 self.lastplot = 'reverb' | |
939 # | |
940 thread.exit_thread() | |
941 def callback_plot_reverb(self): | |
942 try: | |
943 thread.start_new_thread(self.plot_reverb, ()) | |
944 except: | |
945 print "[EE] Could not start new thread" | |
946 | |
947 | |
948 def callback_play_raw(self): | |
949 print "[II] Called callback_play_raw" | |
950 try: | |
951 self.playerprocess.terminate() | |
952 except: | |
953 pass | |
954 self.play_raw() | |
955 | |
956 def callback_play_reverb(self): | |
957 | |
958 print "[II] Called callback_play_reverb" | |
959 try: | |
960 self.playerprocess.terminate() | |
961 except: | |
962 pass | |
963 | |
964 self.play_reverb() | |
965 | |
966 def callback_stop(self): | |
967 self.playerprocess.terminate() | |
968 | |
969 def callback_save(self): | |
970 outf = "%s_parameters.yaml" % self.filename.split('.')[0] | |
971 out = YamlOutput(filename=outf) | |
972 out(self.pool) | |
973 print "[II] Parameters Saved" | |
974 self.saved = True | |
975 | |
976 def callback_reset(self): | |
977 d1 = self.d1 | |
978 g1 = self.g1 | |
979 da = self.da | |
980 G = self.G | |
981 gc = self.gc | |
982 | |
983 self.d1 = self.d1_old | |
984 self.g1 = self.g1_old | |
985 self.G = self.G_old | |
986 self.gc = self.gc_old | |
987 self.da = self.da_old | |
988 | |
989 self.scale_d1.set(self.d1/self.SR) | |
990 self.scale_g1.set(self.g1) | |
991 self.scale_da.set(self.da/self.SR) | |
992 self.scale_G.set(self.G) | |
993 self.scale_gc.set(self.gc) | |
994 | |
995 | |
996 def callback_next(self): | |
997 if self.saved == False: | |
998 tkMessageBox.showerror("File not saved", "You need to save your changes first") | |
999 return | |
1000 | |
1001 | |
1002 self.visited_files.append(self.filename) | |
1003 self.sessionpool.add('visited_files', self.filename) | |
1004 self.files_to_visit.pop() | |
1005 self.sessionpool.remove('files_to_visit') | |
1006 for i in self.files_to_visit: | |
1007 self.sessionpool.add('files_to_visit', i) | |
1008 outp = YamlOutput(filename="session.yaml")(self.sessionpool) | |
1009 | |
1010 if len(self.files_to_visit) == 0: | |
1011 tkMessageBox.showinfo("Congratulations!", "You finished the training session!") | |
1012 self.master.destroy() | |
1013 return | |
1014 self.filename = self.files_to_visit[-1] | |
1015 self.load_song(self.filename) | |
1016 | |
1017 | |
1018 | |
1019 | |
1020 if __name__ == "__main__": | |
1021 if len(argv) != 2: | |
1022 print "[EE] Wrong number of arguments" | |
1023 print "[II] Correct syntax is:" | |
1024 print "[II] \t%s <trainingdir>" | |
1025 print "[II] where <trainingdir> contains the segments in .wav format and their corresponding .yaml files" | |
1026 | |
1027 exit(-1) | |
1028 | |
1029 print "[II] Using directory: %s" % argv[1] | |
1030 root = Tk() | |
1031 app = UI(root, argv[1]) | |
1032 root.mainloop() | |
1033 | |
1034 # app.player.terminate() | |
1035 # root.destroy() |