リアルタイムに変化する音声のスペクトル包絡を表示するPythonスクリプト

要pyqtgraph、numpy、pyaudio、pysas。
母音(あいうえお)で動作確認すると、スペクトル包絡の形状がリアルタイムに変化する様子が見られるので面白い。

#!/usr/local/bin/python3
# -*- coding:utf-8 -*-

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

# 音声関係のライブラリ
import pyaudio
from pysas import World


sample_rate = 16000
frame_length = 1024
frame_shift = 80


class PlotWindow:
    def __init__(self):

        # プロット初期設定
        self.win = pg.GraphicsWindow()
        self.win.setWindowTitle(u"スペクトル包絡")
        self.plt = self.win.addPlot()
        self.ymin = -100
        self.ymax = 0
        self.plt.setYRange(self.ymin, self.ymax)  # y軸の上限、下限の設定

        # Thanks to yukara 氏
        self.plt.setXRange(0, frame_length / 2, padding=0)
        specAxis = self.plt.getAxis("bottom")
        specAxis.setLabel("Frequency [Hz]")
        specAxis.setScale(sample_rate / 2. / (frame_length / 2 + 1))
        hz_interval = 500
        newXAxis = (
            np.arange(int(sample_rate / 2 / hz_interval)) + 1) * hz_interval
        oriXAxis = newXAxis / (sample_rate / 2. / (frame_length / 2 + 1))
        specAxis.setTicks([zip(oriXAxis, newXAxis)])

        self.curve = self.plt.plot()  # プロットデータを入れる場所
        self.epsiron = 0.0001

        # マイク設定
        self.CHUNK = frame_length  # 1度に読み取る音声のデータ幅
        self.RATE = sample_rate  # サンプリング周波数
        self.audio = pyaudio.PyAudio()
        self.stream = self.audio.open(format=pyaudio.paInt16,
                                      channels=1,
                                      rate=self.RATE,
                                      input=True,
                                      output=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()

        world = World(sample_rate)
        _, spec_env = world.spectral_envelope(self.data.astype(np.float64))
        spec = np.mean(spec_env, axis=0)
        spec = 20 * np.log10(spec + self.epsiron)
        self.curve.setData(spec)  # プロットデータを格納

    def AudioInput(self):
        ret = self.stream.read(self.CHUNK)  # 音声の読み取り(バイナリ)
        ret = np.frombuffer(ret, dtype="int16") / 32768
        return ret


if __name__ == "__main__":
    plotwin = PlotWindow()

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

音声を取得する部分は以下の記事を参考にしました。ありがとうございました。
takeshid.hatenadiary.jp