たけし備忘録

自分の好奇心の赴くままに勉強メモ LL系が大好き Python bash Julia C

pyqtgraph+PyAudioによるリアルタイムで音声プロット

通常pythonでのプロットと言ったらmatplotlibですがプロッティングがとても遅い欠点があります。その分使いやすくてキレイなんですけどね。
リアルタイムでプロットしようとしたらメモリは喰うし遅いしで最悪(工夫次第ではそうでもないらしいですがその工夫がめんどくさい)ですので、高速なプロッティングが出来るとされるpyqtgraphを使ってリアルタイムで音声をプロッティングしました。

pyqtgraphは
PyQt(Qtだけかも?)
・numpy
に依存してますのでそれだけ入れてしまえばオッケーです。

また今回は音声のプロットですので音声関係のライブラリを入れておく必要があります。
今回用いたのはPyAudioです。

# -*- coding:utf-8 -*-

#プロット関係のライブラリ
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import sys

#音声関係のライブラリ
import pyaudio
import struct


class PlotWindow:
    def __init__(self):
        #プロット初期設定
        self.win=pg.GraphicsWindow()
        self.win.setWindowTitle(u"リアルタイムプロット")
        self.plt=self.win.addPlot() #プロットのビジュアル関係
        self.plt.setYRange(-1,1)    #y軸の上限、下限の設定
        self.curve=self.plt.plot()  #プロットデータを入れる場所

        #マイクインプット設定
        self.CHUNK=1024             #1度に読み取る音声のデータ幅
        self.RATE=44100             #サンプリング周波数
        self.audio=pyaudio.PyAudio()
        self.stream=self.audio.open(format=pyaudio.paInt16,
                                    channels=1,
                                    rate=self.RATE,
                                    input=True,
                                    frames_per_buffer=self.CHUNK)

        #アップデート時間設定
        self.timer=QtCore.QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(10)    #10msごとにupdateを呼び出し

        #音声データの格納場所(プロットデータ)
        self.data=np.zeros(self.CHUNK)

    def update(self):
        self.data=self.AudioInput()
        self.curve.setData(self.data)   #プロットデータを格納

    def AudioInput(self):
        ret=self.stream.read(self.CHUNK)    #音声の読み取り(バイナリ)
        #バイナリ → 数値(int16)に変換
        #32768.0=2^16で割ってるのは正規化(絶対値を1以下にすること)
        ret=np.frombuffer(ret, dtype="int16")/32768.0
        return ret

if __name__=="__main__":
    plotwin=PlotWindow()
    if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

これを実行すると以下の様な画像になります。
(ごめんなさい、本当は動画を上げたかったのですが動画の上げ方がわからずこのような形になってしまいました。上げ方が分かったら追記で動画を載せます。)

f:id:takeshiD:20151126145102p:plain


データの入出力あたりはPlotWindowクラスのupdateメソッドとAudioInputメソッドでコントロールしてますので
このあたりをテキトーにいじくってあげたり、FFTしてあげたりすればスペクトルアナライザーにもなります。
self.timer.start(10)を50にしてあげたりすればプロットスピードが落ちたりします。

pyqtgraphのリファレンスがちょっと充実度にかけるのでご参考になれば幸いです。

また、PyAudioを利用されたことのある方にお叱りを受けるかもしれませんが、今回streamなどを明示的に終了させてません。
ちゃんと動いて止まっておかしいことはなかったので大丈夫っちゃ大丈夫かな程度のテキトーなコードです。
ちゃんと明示的に止めるのであれば、PlotWindowクラスのpg.GraphicsWIndowがQtからの継承ですので、ウィンドウを閉じる時におそらくcloseEventを発するはずですので、オーバーライドしてstreamを止めればいいのでは。
ですので上記のコードはかなりテキトーです。



[次の記事]
pyqtgraph+PyAudioによるリアルタイムで音声プロット その2 - たけし備忘録