PythonのPyAudioで音声録音する簡単な方法

  • このエントリーをはてなブックマークに追加

Pythonを使ってPCのマイク入力から音声を入力するプログラムはPyAudioを使って簡単に書くことができます。ここでは実際の音をデジタルデータへ変換する際の注意点を踏まえてサンプルコードを示します。

こんにちは。wat(@watlablog)です。
信号処理プログラマを目指すとしたら簡単に録音くらい朝飯前になりたいですね。ここではPyAudioを使って音声信号を取得します

Pythonプログラミングの基本文法や問題解決には体系的な学習プログラムが効果的です。手っ取り早く基礎を覚えるために僕は「PyQ(パイキュー)」に登録してみました。気になる方は「PyQでPython学習!実際に登録してみた感想と気になる料金」という記事を参照下さい!

PyAudioインストールの注意点

筆者の環境はPython3.7を使っていますが、2019年6月現在はインストール時にエラーが発生するようです。詳細はPython3.7でPyAudioがインストールできない時の解決法の記事を確認して頂ければと思います。

録音に使用する機材

これからPythonプログラムを使って録音のプログラムを書きますが、不幸な事に僕のPCに初期から付いていた内蔵マイクが壊れてしまっていたので、このページではUSBマイクを使って例を紹介します。

USBマイクであっても、プログラム自体は何も変化することはありません!それでは、早速コードを書いていきましょう!

Python/PyAudioで録音するコード

今回は「習うより慣れろ!」ということで、コードを書きながら内容を説明していきたいと思います。

インポートするパッケージ

今回使うライブラリパッケージは、音声録音をするためのpyaudio, 配列処理のnumpy, グラフ表示のmatplotlibです。

設定する値

計測のための設定は以下のコードです。

計測時間は全体で何秒録音するか、サンプリングレートは1秒間に収集するデータの個数です。

データは1つずつ収集するのではなく、フレーム単位で収集します。そのためそのフレームのサイズを指定します(この値は2のべき乗(512, 1024, 2048...等))。

マイクのチャンネル指標とは、PCの何番目のチャンネルが録音用のデバイスかを指定するものです。この番号はオーディオインデックスの番号と呼び、「Python/PyAudioでマイクのチャンネルを確認する方法!」で記載した方法で調べることができます。

録音の関数

それではここでメインの録音関数を説明します。

以下のコードが録音関数です。

ストリームとは、ストリーミング動画等に代表されるように「流れ」を意味する単語ですが、PCのサウンドデバイスが準備開始する、というイメージで構わないと思います。

「format=pyaudio.paInt16」は16bitの量子化ビット数でデータを収集するという意味で、後程後述します。

このサンプルコードでは1チャンネルのモノラル録音をしています。

「int(((time / dt) / fs))」の部分は、計測時間timeを指定しましたが、結局はフレーム単位で録音をするため、フレームの整数倍でデータを収集するためのループ回数計算が必要なため、そのループ回数を計算しています。

dataはリスト型で、さらに「b'\xfd\xff\xfa…'」といったデータで作られていますが、リストの中身の、さらにb''の中身の文字列を連結させるために「b''''.join(data)」と.join関数を使います。

「np.frombuffer」部分では、データをNumpy配列に変換し、数値として扱えるように変換するものですが、これがちょっとわかりにくいかも知れませんので、図解を作りました。

但し、今回僕がこのコードを作るために勉強して理解した内容であるため、もしかしたら間違いがあるかも知れません。ご利用には細心の注意をお願いします。

以下の図はPyaudioで録音したデータ構造のイメージを示しています。

量子化データ構造

コンピュータはアナログな連続した値を扱えないので、図中に描いたようなマス目に録音したデータを格納していくことをやっています。

横軸はデータサンプル数で、フレームサイズ単位でループ数に応じて増えていくマスです。

一方縦軸はデータの物理値の量を示す軸ですが、コンピュータは音を測定するからといって音圧[Pa]を直接計測することができません。

本ページでは16bitの量子化ビット数で録音していると先に書きましたが、このビット数によって縦軸のマスの個数が決まると認識しています。

量子化についてもっと詳しく

コンピュータは連続した値を扱えず、ビット数に応じたマスにデータを格納して行きます。

今回は縦軸が16bitなので、表現できる値の数は\(2^{16}\)です。

\(2^{16}\)は65536個のマスを用意できることを意味しますが、音圧のデータは正の値もあれば負の値もあり、さらには0も表現する必要があります。

正負両方の値を表現するためには割る2をしなければいけません。\(2^{16}\)の半分は65536/2=32768となりますが、0をとる必要があるので、32768-1=32767が最大値と最小値になります。

そのため上図は0を中心として±32767の範囲にデータが入ることになります。

ここまでが、「/ float((np.power(2, 16) / 2) - 1) 」としている理由になります。

関数の実行とグラフプロット

ここまでできたら、あとは関数を実行し、グラフにプロットするだけです。

以下のコードのwfmが波形(Waveform)を格納する変数で、先ほど作った関数を実行する部分です。

グラフの横軸tを計算するために、関数内のforループ回数iも取得しています。

実行結果

以下の図が実行結果になります。

これはマイクをテーブルに7回叩きつけた時の音です。綺麗な音圧の減衰自由振動が観測できていますね。

実行結果

まとめ

本ページではPyAudioを使って音声を取得するコードを紹介しました。

ただサンプルコードを紹介するだけでは(僕自身が)理解に苦しんだので、量子化ビット数やデータ構造等の勉強結果も図にしてみました。

以外と録音には専門用語が沢山あって慣れない操作が多かったけど、なんとかデータを自分のPCで収集することができたぞ!

Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

全コード

そのまま貼り付ければ実行して結果が得られるように、全コードを以下に載せておきます。デバイスのindexは個々のPCで番号が違うかも知れませんので、お気をつけ下さい。

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。

コメント

コメントを残す

*