def create_canvas(path, parent): try: sig, fs = audioload(path, sr=None, mono=False) except: return None if len(sig.shape) == 1: sig = np.reshape(sig, [1, len(sig)]) parent.sig_info = { "sig": sig, "fs": fs } def refresh_figure(xlim=None, canvas=None): sig = parent.sig_info["sig"] fs = parent.sig_info["fs"] plt.gcf().clear() gc.collect() fig = plt.gcf() xmin = 0 xmax = sig.shape[1] pics = 1 if canvas and canvas.spectrum: pics += 1 if canvas: canvas.fig = fig canvas.axes = {} if not xlim and canvas: xlim = canvas.xlim_stack[-1] if canvas or xlim: xmin = np.max([int(xlim[0] * fs), xmin]) xmax = np.min([int(xlim[1] * fs), xmax]) t = np.arange(0, sig.shape[1]) / fs for idx in range(sig.shape[0]): ax = plt.subplot(sig.shape[0] * pics, 1, idx * pics + 1) plt.plot(t[xmin:xmax], sig[idx, xmin:xmax]) if canvas: canvas.axes["signal-{}".format(idx)] = ax if xlim: plt.xlim(xlim) offset = 0 if canvas and canvas.spectrum: offset += 1 ax = plt.subplot(sig.shape[0] * pics, 1, idx * pics + 1 + offset) freq_resp = fft(sig[idx, xmin:xmax], 512) freq_resp = freq_resp[:int(len(freq_resp)/2)] freq_resp = np.abs(freq_resp) ff = np.arange(0, len(freq_resp)+1) / (len(freq_resp)+1) * fs/2. ff = ff[:-1] if canvas.spectrum_log: plt.semilogy(ff, freq_resp) else: plt.plot(ff, freq_resp) canvas.axes["spectrum-{}".format(idx)] = ax fig.suptitle("fs: {} Hz, duration: {} secs".format(fs, sig.shape[1] * 1. / fs)) def find_current_axes_name(iax, canvas): for name, ax in ({} if not hasattr(canvas, "axes") else canvas.axes).items(): if ax == iax: return name return None def on_press(event, canvas): canvas.tictoc.toc() canvas.press_xpos = event.xdata def on_move(event, canvas): pass def on_release_on_signal_axes(event, canvas, interval): if interval > 150 and canvas.press_xpos != None and event.xdata != None: xdiff = canvas.press_xpos - event.xdata xlim = canvas.xlim_stack[-1] xlim[0] += xdiff xlim[1] += xdiff canvas.xlim_stack[-1] = xlim refresh_figure(xlim=xlim, canvas=canvas) canvas.draw() return if event.button == MouseButton.LEFT and event.xdata != None: xlim = canvas.xlim_stack[-1] xr = (xlim[1] - xlim[0]) * .7 xmin = np.max([event.xdata - xr / 2, xlim[0]]) xmax = np.min([xmin + xr, xlim[1]]) canvas.xlim_stack.append([xmin, xmax]) refresh_figure(xlim=canvas.xlim_stack[-1], canvas=canvas) canvas.draw() elif event.button == MouseButton.RIGHT: if len(canvas.xlim_stack) < 2: return del canvas.xlim_stack[-1] refresh_figure(xlim=canvas.xlim_stack[-1], canvas=canvas) canvas.draw() def on_release_on_spectrum_axes(event, canvas, interval): if interval > 150: return if event.button in [MouseButton.LEFT, MouseButton.RIGHT] and event.xdata != None: canvas.spectrum_log = not canvas.spectrum_log refresh_figure(canvas=canvas) canvas.draw() on_release_handle = { "signal": on_release_on_signal_axes, "spectrum": on_release_on_spectrum_axes, } def on_release(event, canvas): interval = canvas.tictoc.toc() ax_name = find_current_axes_name(event.inaxes, canvas) if not ax_name: return if not ax_name.split("-")[0] in on_release_handle: return on_release_handle[ax_name.split("-")[0]](event, canvas, interval) plt.gcf().clear() refresh_figure() canvas = FigureCanvasTkAgg(plt.gcf(), master=parent) canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) canvas.draw() canvas.xlim_stack = [plt.gca().get_xlim()] canvas.tictoc = TicToc() canvas.tictoc.tic() canvas.spectrum = False canvas.spectrum_log = False refresh_figure(canvas=canvas) canvas.mpl_connect("button_press_event", lambda event: on_press(event, canvas)) canvas.mpl_connect("button_release_event", lambda event: on_release(event, canvas)) canvas.mpl_connect("motion_notify_event", lambda event: on_move(event, canvas)) def config_changed(name, trigger): setattr(canvas, name, bool(trigger)) refresh_figure(canvas=canvas) canvas.draw() funcs = Checkbar(parent=parent, picks=["spectrum"], command=config_changed) funcs.pack(side=tk.BOTTOM) return canvas