繁体   English   中英

Matplotlib-从WAV文件绘制波形

[英]Matplotlib - plotting waveform from a wav file

我正在开发一个旨在将用户指定的数据隐藏在wav文件中的程序(隐秘程序,但仅用于教育用途,没有什么非常复杂的功能)。 除了进行隐写操作外,我还需要可视化原始和输出的wav文件的内容,但是我不知道如何以可行的方式进行操作。

起初,我以为我只会使用tkintercanvas小部件,但是它几乎不可用,因为输入的wav文件可能非常大,并且绘制如此大量的数据是不可行的,更不用说我需要处理缩放,滚动等

我发现matplotlib可以解决我的问题。 我加载了一个10 MB的wav文件(16位,立体声),分离了两个通道的样本并将其转换为带符号的16位整数。 然后,我尝试绘制第一个通道的数据,但似乎matplotlib无法处理如此大量的绘制点-最初,我可以看到波形图(但仍然需要一段时间),但是当我调整窗口大小时(这将导致重绘绘图),发生以下异常:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python33\lib\tkinter\__i`enter code here`nit__.py", line 1475, in __call__
    return self.func(*args)
  File "C:\Python33\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 276, in resize
    self.show()
  File "C:\Python33\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 348, in  draw
    FigureCanvasAgg.draw(self)
  File "C:\Python33\lib\site-packages\matplotlib\backends\backend_agg.py", line 451, in draw
    self.figure.draw(self.renderer)
  File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python33\lib\site-packages\matplotlib\figure.py", line 1035, in draw
    func(*args)
  File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python33\lib\site-packages\matplotlib\axes.py", line 2088, in draw
    a.draw(renderer)
  File "C:\Python33\lib\site-packages\matplotlib\artist.py", line 56, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 563, in draw
    drawFunc(renderer, gc, tpath, affine.frozen())
  File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 939, in _draw_lines
    self._lineFunc(renderer, gc, path, trans)
  File "C:\Python33\lib\site-packages\matplotlib\lines.py", line 979, in _draw_solid
    renderer.draw_path(gc, path, trans)
  File "C:\Python33\lib\site-packages\matplotlib\backends\backend_agg.py", line 145, in   draw_path
    self._renderer.draw_path(gc, path, transform, rgbFace)
  OverflowError: Allocated too many blocks

当我尝试加载更大的WAV文件(50 MB)时,即使没有绘制波形,也会发生相同的错误。 因此,我需要采用其他方法,但不太了解该怎么做。 当我首先加载样本时,我可能会绘制输入样本子集的平均值,这对于matplotlib应该是可以承受的。 但是我不知道如何缩放/滚动图,这意味着要根据实际的缩放级别和实际的视图位置(“窗口”)重新计算平均值,这可能会导致性能很差-明智的。

而且这只是一个示例图,因此我无法想象绘制出四倍于此数量的数据(2通道,原始数据和输出数据)而不会遇到性能问题甚至提到的故障/异常。 在较小的文件(几百kB)上,它可以很好地工作(但仍然有些慢)。

请问您对此有何建议?

编辑:我发现我对struct.pack()中的16位样本的输入数据有错误的解释(我使用字符串<H而不是<h ),并且以某种方式我对10 MB没有任何问题WAV,似乎有一定的提速,但是绘制波形仍然比合适的要慢得多。 50 MB WAV似乎绘制得很好,但是当我调整窗口大小(并因此调整matplotlib画布)时,发生上述异常,并且当我尝试缩放到某个区域或调整窗口大小时不再进行重绘以前的尺寸。

这是我用来了解matplotlib的代码(它基于简单的matplotlib演示 ):

EDIT2:我更改了代码,以使其以相同的方式正常工作,但现在希望它更简单。)

import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
from tkinter import tix
from tkinter.tix import *
from random import randrange

matplotlib.use('TkAgg')

samples = [randrange(-32768, 32768) for i in range(int(1e7))]
fig = Figure(figsize=(20,8), dpi=50)
subplot1 = fig.add_subplot(111)
subplot1.plot(samples, "r")

root = tix.Tk()

canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)

root.mainloop()

关于如何解决此问题以及如何以合理的性能和内存消耗来处理WAV数据的任何建议(此示例在异常发生之前使用了800 MB以上的内存,这意味着我的解决方法根本不好) 。

您可以进一步简化它以在交互式提示中运行,但是我离题了

import matplotlib
from matplotlib import pyplot as plt
from random import randrange


samples = [randrange(-32768, 32768) for i in range(int(1e7))]
fig, ax = plt.subplots(1, 1)
ax.plot(samples, "r-")

问题是您正在尝试绘制一个比Agg库可以处理的线段更多的线段(我不确定该限制是多少,并且在将路径传递给Agg之前应该进行一些路径简化)可能不是点数限制)。

从某种程度上讲,这不是一个大问题,您的屏幕只有大约1k像素,如果绘制所有点,则每个像素会有1e4个点,这很愚蠢,因此您需要降低采样率。

您可以通过多种方式做到这一点(和方法是正确的,将取决于你为什么要绘制这样),包括:一味降采样( x = x[::1000]平均部( x = np.mean(x[::n * (len(x)//n)].reshape(-1, n), axis=1) )或做一些奇怪的事情(进行fft并将其过滤以仅保持低频)。

如果需要放大并查看缩放区域中的所有点,则可能需要做一些更奇特的操作,以便在缩放时将数据替换为非向下采样版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM