Pythonでマイク入力音声をリアルタイム波形グラフ表示:PyaudioとMatplotlib活用

今回は、pythonでマイク音声を入力する方法について記載しようと思います。

筆者は組み込みエンジニアでオーディオ関連の仕事をすることもあるので、Visual Studio C++で、音声入力とフーリエ変換をするプログラム書いたことがあり、ちょっと興味があって今回挑戦してみました。

ライブラリのインストール

まず初めにマイクの入力と波形を出力するために、以下の2つライブラリをインストールします。

①pyaudio ・・・ pythonでAudioデバイスを制御するためのライブラリ

(windowsでのDirectXみたいなものなのかな??ちょっと詳しくは知りません。。。)

②matplotlib ・・・ グラフ等を表示するためのライブラリ

pyaudio のインストール

pyaudioは、windowsPCの場合、インターネット経由のpipコマンドでインストールするのは無理そうでした。

まず、Microsoft C++ Build Toolsを入れるように怒られ、そしてもしインストールしたとしても、「portaudio.h」というものがないって怒られてインストールに失敗しました。

で、ちょっと調べてみたところ、以下のサイトにあるwhlからインストールすれば使えるとのことで

以下からダウンロードしました。

※Unofficialとのことで、使用する際には自己責任でインストールしてください。

Page Not Found - Laboratory for Fluorescence Dynamics
HTTP Error 404 - File or directory not found

以下のようなページが表示されますので、pyaudioを探してください。

以下のような感じでありますので、環境にあったものをインストールしてください。

そして、ダウンロードできたら、コマンドプロンプトへ以下の通りコマンドを入力しインストールしてください。

pip install PyAudio-0.2.11-cp39-cp39-win_amd64.whl
※ PyAudio-0.2.11-cp39-cp39-win_amd64.whlはダウンロードしたファイルを指定してください。

以下のような感じで簡単にインストールできます。

matplotlibのインストール

続いて、 「matplotlib」のインストールです。

コマンドプロンプトを開き、以下の通りコマンドを実行してください。

pip install matplotlib

※こちらは、ネット経由で勝手にインストールしてくれます。

以下のようになります。

これで準備は完了です。

サンプルコード

では実際のプログラムです。

import pyaudio
import matplotlib.pyplot as plot
import numpy

def audiostart():
    audio = pyaudio.PyAudio() 
    stream = audio.open( format = pyaudio.paInt16,
                         rate = 44100,
                         channels = 1, 
                         input_device_index = 1,
                        input = True, 
                        frames_per_buffer = 1024)
    return audio, stream

def audiostop(audio, stream):
    stream.stop_stream()
    stream.close()
    audio.terminate()

def read_plot_data(stream):
    data = stream.read(1024)
    audiodata = numpy.frombuffer(data, dtype='int16')
    
    plot.plot(audiodata)
    plot.draw()
    plot.pause(0.001)
    plot.cla()

if __name__ == '__main__':
    (audio,stream) = audiostart()
    
    while True:
        try:
            read_plot_data(stream)
        except KeyboardInterrupt:
            break

    audiostop(audio,stream)

そして、実際に実行させたときの表示はこのような感じになります。

実行結果

乱れてはいますが、これはマイクに1Khzの 正弦波 を近づけたときの波形です。

一応正弦波になっています。

続いてはプログラムの解説ですが、解説は次ページにて記載します。

プログラム解説

ここから解説していきます。

マイクデバイスのオープンと入力

まず、マイクデバイスの制御をするためにpyaudioをインポートしています。

import pyaudio

つづいて、マイクのオープン処理です。

def audiostart():
    audio = pyaudio.PyAudio()
    stream = audio.open( format = pyaudio.paInt16,
                         rate = 44100,
                         channels = 1, 
                         input_device_index = 1,
                        input = True, 
                        frames_per_buffer = 1024)
    return audio, stream

こちら、まず以下でAudioのインスタンスを生成

audio = pyaudio.PyAudio()

そして、以下でデバイスのオープンをしています。

stream = audio.open( format = pyaudio.paInt16,        … 16 bit
                         rate = 44100,                … 44.1Khz
                         channels = 1,                … チャンネル数 1 
                         input_device_index = 1,      … デバイスインデックス
                        input = True,                 … インプットを有効化
                        frames_per_buffer = 1024)     … 何バイト単位でデータをもらうか

そして、データの取得は以下で行います。

data = stream.read(1024)

最大で何バイト取得するのか指定してread関数を呼び出すだけです。

そして、使い終わったら、最後に後始末です。

def audiostop(audio, stream):
    stream.stop_stream()
    stream.close()
    audio.terminate()

データのグラフ化

続いて、グラフを表示するためには、以下の通りインポートします。

import matplotlib.pyplot as plot

これは、「matplotlib」モジュールの「pyplot」というクラスを、「plot」という名前で使いますよってことです。
そして、実際にプロットしてグラフを表示しているのは以下です。

    plot.plot(audiodata)
    plot.draw()
    plot.pause(0.001)
    plot.cla()

これは以下のような流れを行うことでデータを設定して描画しています。

① plot.plot ・・・ データを設定
② plot.draw ・・・ 設定したデータで描画を指示
③ plot.pause ・・・ 少し止めて描画を待つ
※リアルタイムで描画したいときにはこれを行う必要があります。
④ plot.cla ・・・ データの内容をクリア

これで、マイクから音声を入力し、入力データをグラフ化できました。
Pythonはやっぱり簡単でいいですね。
次は、また勉強して、入力したデータをフーリエ変換し、入力波形の周波数をチェックしてみようと思います。


2021/12/16 追記

音量(デシベル)と周波数の取得方法の記事を書きましたので、興味ある方はこちらも見てみてください。

こちらは録音ではなく、スピーカー出力となりますが、pyaudioでのコールバック処理の方法をまとめていますので、コールバックで処理したいよって方は以下を参考にしてみたください。

Pythonについて勉強したい人は以下がおすすめです。私も持っていてたまに眺めて勉強していますものですのでぜひ購入して学習してみてください。


にいやん

出身 : 関西 居住区 : 関西 職業 : 組み込み機器エンジニア (エンジニア歴13年) 年齢 : 38歳(2022年11月現在) 最近 業務の効率化で噂もありPython言語に興味を持ち勉強しています。 そこで学んだことを記事にして皆さんとシェアさせていただければと思いブログをはじめました!! 興味ある記事があれば皆さん見ていってください!! にほんブログ村

View Comments

  • こんにちは。
    いま、ステレオ音声をLRそれぞれFFTにかけようとしています。
    同様にPyaudioを用いて、channels=2としてステレオ入力にして、ちゃんとステレオで読み込めてはいるようですが、LとRに分けてのFFTができません。
    もし、Pyaudioを用いる用いないにかかわらずLとR別々にFFTを行う方法をご存じでしたらご教示戴けませんでしょうか。

    • コメントありがとうございます。
      ステレオでデータが取得できているのであれば、データは単純に L CH 16Bit + R Ch 16Bitのデータ列になっていますので、LChとRChでデータを分割してFFTすれば各チャンネルの周波数が取れます。
      LRを分けて周波数を取得するサンプルコードを追記しましたので、参考にしてみてください。

  • numpyという記述がソースコード中にありましたが、importに記述しないのですか?

    • コメントありがとうございます。
      テキストファイルから、転記するときにコピー漏れをしていたようです。
      import numpy も必要です。
      全体コードを修正しました。