如何在 PyQtGraph 中绘制音频波形

Posted

技术标签:

【中文标题】如何在 PyQtGraph 中绘制音频波形【英文标题】:How to plot audio waveform in PyQtGraph 【发布时间】:2018-12-03 18:33:11 【问题描述】:

我的论文项目需要处理音频波形。而且我真的很难用 PyQtGraph 绘制我的音频波形并且找不到任何解决方案。

我试过用 matplotlib 绘制它,效果很好。

这是通过在 tkinter 窗口上嵌入 matplotlib 进行绘图的代码(不会发布 tkinter 画布嵌入的完整代码,因为我认为这不是我的问题的重点):

 def waveform(self, audio):
    self.waveFile = wave.open(audio, 'rb')  # reading wave file
    format = p.get_format_from_width(self.waveFile.getsampwidth())
    channel = self.waveFile.getnchannels()
    rate = self.waveFile.getframerate()
    self.frame = self.waveFile.getnframes()
    self.stream = p.open(format=format,  # DATA needed for streaming
                         channels=channel,
                         rate=rate,
                         output=True)

    durationF = self.frame / float(rate)
    plt.title('Audio Waveform')
    self.data_int = self.waveFile.readframes(self.frame)
    self.data_plot = np.fromstring(self.data_int, dtype=np.short)
    self.data_plot.shape = -1, 2
    self.data_plot = self.data_plot.T
    self.time = np.arange(0, self.frame) * (1.0 / rate)
    self.fig = Figure(figsize=(30, 6), dpi=30)
    self.fig.set_size_inches(34, 5.3)
    self.fig.subplots_adjust(left=0.05, bottom=0.09, right=1.05, top=1.00, wspace=0, hspace=0)
    self.fig.tight_layout()
    self.xticks = np.arange(0, self.timeDuration, 15)
    self.wavePlot = self.fig.add_subplot(111)
    self.wavePlot.set_xticks(self.xticks)
    if (channel == 1):
        print 'Just mono files only'
        self.wavePlot.plot(self.time, self.data_plot[0])

    elif (channel == 2):
        print 'Just stereo files only'
        self.wavePlot.plot(self.time, self.data_plot[1], c="b")

    self.wavePlot.tick_params(axis='both', which="major", labelsize=20)
    self.wavePlot.tick_params(axis='both', which="minor", labelsize=30)

    self.canvas = FigureCanvasTkAgg(self.fig, self.waveFrame)
    self.canvas.get_tk_widget().grid(row=0, column=0, sticky="nsew")

当我发现 PyQtGraph 时,我转而使用它来进行更具交互性和快速的绘图。 现在,当我在 PyQt/PyQtGraph 中使用几乎完全相同的东西执行此操作时,出现了错误,我无法再绘制它了。

这是我在 PyQT4 中使用 PyQtGraph 进行绘图的代码:

 def waveform(self, audio):
    self.waveFile = wave.open(audio,'rb')
    self.format = p.get_format_from_width(self.waveFile.getsampwidth())
    channel = self.waveFile.getnchannels()
    self.rate = self.waveFile.getframerate()
    self.frame = self.waveFile.getnframes()
    self.stream = p.open(format=self.format,  # DATA needed for streaming
                         channels=channel,
                         rate=self.rate,
                         output=True)

    durationF = self.frame / float(self.rate)

    #Setting up waveform plot
    self.data_int = self.waveFile.readframes(self.frame)
    self.data_plot = np.fromstring(self.data_int, 'Int16')
    self.time = np.arange(0, self.frame) * (1.0 / self.rate)

     self.win = pg.GraphicsWindow(title='Spectrum Analyzer')
    self.win.setWindowTitle('Spectrum Analyzer')
    self.win.setGeometry(5, 115, 1910, 1070)

    wf_xlabels = [(0, '0'), (2048, '2048'), (4096, '4096')]
    wf_xaxis = pg.AxisItem(orientation='bottom')
    wf_xaxis.setTicks([wf_xlabels])

    wf_ylabels = [(0, '0'), (127, '128'), (255, '255')]
    wf_yaxis = pg.AxisItem(orientation='left')
    wf_yaxis.setTicks([wf_ylabels])

    self.waveform = self.win.addPlot(
        title='WAVEFORM', row=1, col=1, axisItems='bottom': wf_xaxis, 
              'left': wf_yaxis,
              )
    self.waveform.plot(pen='c', width=3)
    self.waveform.setYRange(0,255, padding=0)
    self.waveform.setXRange(0,2 * self.chunk, padding = 0.005)
    self.waveform.plot(self.time, self.data_plot)

当我运行上面的代码时,一个错误提示 ---in updateData raise Exception("X 和 Y 数组的形状必须相同——得到 %s 和 %s。" % (self.xData.shape, self.yData.shape)) 例外:X 和 Y 数组的形状必须相同——得到 (1535696L,) 和 (767848L,)。

我尝试了不同的绘图方式,但我还没有想出任何解决方案来绘制它。我想知道为什么 matplotlib 代码可以正常工作而 PyQtGraph 不能? 任何回应都会有很大帮助。

【问题讨论】:

【参考方案1】:

X 和 Y 必须具有相同的长度。在您的错误消息中,一个是另一个的两倍。

在您的 MatPlotLib 代码示例中,一些代码似乎将 self.data_plot 重塑为两行。

self.data_plot.shape = -1, 2
self.data_plot = self.data_plot.T

PyQtGraph 代码中缺少此功能。

【讨论】:

非常感谢您的回复,我编辑并插入了那些行,但我得到了相同的错误,但 dataType 中出现了不同的数组形状错误 ------ raise Exception('array shape must be ( N,) or (N,2); got %s instead' % str(obj.shape)) 例外:数组形状必须是 (N,) 或 (N,2);得到 (2L, 383924L) 代替。不幸的是,PyQtGraph 中的绘图可能在 matplotlib 中有所不同?我对绘图真的很陌生,必须为我的项目发现这一点,但我被困住了。 Matplotlib 和 PyQtGraph 之间可能存在差异,但在这种情况下,差异在于您的示例之间。 data_plot 数组有两行,因为它包含两个通道的数据。在您的 Matplotlib 代码中,您可以通过在 plot 命令中输入 self.data_plot[0] 来选择第一行。在您的 PyQtGraph 图中,您只需使用 self.waveform.plot(self.time, self.data_plot) 传递整个数组。将此更改为 self.waveform.plot(self.time, self.data_plot[0]) 以绘制第一个通道。顺便说一句,在调试过程中,它有助于打印数组的形状,以便您查看它们是否正确 非常感谢!有效!但还有一件事,它终于绘制了,但图表太大了。我将在此处链接图像:imgur.com/a/sbTzkY8 ----如您所见,x 标签(时间)在 0 到 8 秒的音频文件中是准确的,但绘图非常巨大。 很高兴能提供帮助。如果您认为我已充分回答,请通过单击复选标记将问题标记为已接受。我不确定您所说的“图表太大”是什么意思。窗户是不是太大了? X轴范围是否太大?由于这是一个不相关的问题,我建议您发布一个新帖子并更详细地解释它。这也可以确保其他人会看到您的新问题。 已检查。对不起,我是***的新手。如果您可以查看链接,它上面有图表的屏幕截图以及我所说的大,X 范围是我需要的,但 Y 不是。我知道 pyqtgraph 可以放大缩小图形,但初始显示很大。再次感谢,我会发布一个新主题,但我仍然期待您的回复,因为您不时帮助我。谢谢。

以上是关于如何在 PyQtGraph 中绘制音频波形的主要内容,如果未能解决你的问题,请参考以下文章

在iOS中绘制录音音频波形图

在Android中绘制wav音频的波形

如何在 Flash 中创建一个音乐播放器来创建音频文件的波形?

如何在pyqtgraph中绘制十字准线并绘制鼠标位置?

Labview波形图 怎么做到不把绘制出来的图像删除 直接在上面绘制新的图形

绘制音频波形和频谱图重叠