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