pythonで自分の音声のスペクトログラムを見る

録音→可視化

音声自体の可視化は前回の記事で触れました。
縦軸に周波数、横軸に時間、色彩(や明度)で音の強さを表すスペクトログラムを使って
自分の音声を録音したデータをもとに可視化しようと思います。

Contents

  1. 言葉の意味「音声」
  2. 必要なもの、準備など
  3. 実装
  4. まとめ

1. 音声と似た言葉

「音声」という言葉は奥が深いものです。
例えば「声」「音声」「話し言葉」、これらは別のものを指しています。

そもそも、音(sound)も日本語の辞書の説明だけでは足りないのです。
(以下、その理由。飛ばして頂いて構いません。)
辞書的には「耳で聞こえるもの」とされていることがほとんどで、
「人が入れない空間でマイクロホンによって収録されたデータ」などはこれに含まれません。
音響工学における『超音波』は非常に大きなウェイトをしめている分野のひとつですが、
超音波の定義は「人に聴こえない音」「聴くことを目的としない音」にあたりますが、
当然のように音として扱っています。
『騒音・振動』分野における振動は、例えば集合住宅とかで起こる振動も扱います。
振動そのものも音響の分野のうちとして扱っています。
音響工学的には「観測された振動に関する時系列データ」くらいの認識がいいと考えています。

声(voice):声が指すものは人の口から出た音すべてを指します。吐き気を催したときの「オエッ」も声です。
音声(speech):声に言語的な情報が加わったものです。感嘆詞やフィラー(「えーっと」)とかも含める事が多い印象です。
話し言葉(spoken language):これは音声として話されるような言葉です。あくまで言葉なので音データではありません。

英語とセットで覚えると、声と音声が違うことがよくわかりますね(強引

2. 必要なもの,準備

録音をするので当然マイクロホンが必要になります。PC内蔵のマイクで問題ありません。
もし外部のマイクロホンを接続する場合や、オーディオインターフェースなど用いる場合は、
PC上の設定できちんと録音できているか予め確認するとスムーズにいけます。

それから私の技術・勉強不足のためColab上で実装ができておりません。
Jupyter notebookで動かしてくれると嬉しいです。(windowsならanacondaとかで入れると楽です。)

pyaudioについてですが人(というか環境によって)セットアップがめんどくさいかもしれません。導入方法については他記事におまかせして、本記事では触れません。
pythonの最新バージョンは3.7であるにもかかわらずpyaudio自体がpython3.6までしか使えないため、バージョンを下げる必要があり、面倒な現状となっております。(2019/04/17現在)
(もしスマートに導入できるTipsなどあれば今後紹介するかもしれません。)

3. 実装(プログラム)

読み込む方法同様に録音方法もいくつかありますが、今回はpyaudioパッケージで録音して
waveパッケージで.wavファイルに書き込みます。pyaudioでの録音については本家の例題(ページの下方、Recordタブに記載)に則っておこないます。再生も同様です。
音の可視化については前回同様に、waveファイル読み込みはscipy.io.wavfile、プロットはmatplotlib.pyplotを使います。

import pyaudio, wave
import matplotlib.pyplot as plt
from scipy.io.wavfile import read

# record
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECOND = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                       channels=CHANNELS,
                       rate=RATE,
                       input=True,
                       frames_per_buffer=CHUNK)

print("* recording")

frames=[]
for i in range(0, int(RATE / CHUNK * RECORD_SECOND)):
    data = stream.read(CHUNK)
    frames.append(data)

print("* done recording")

stream.stop_stream()
stream.close()
p.terminate()

wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()

# visualize
fs, speech_data = read(WAVE_OUTPUT_FILENAME)

plt.subplot(2,1,1)
plt.title("waveform")
plt.plot(speech_data)
plt.xlim(0, len(speech_data))
plt.xlabel("sample")
plt.ylabel("amplitude")

plt.subplot(2,1,2)
plt.title("spectrogram")
plt.specgram(speech_data, Fs=fs)
plt.xlabel("time [s]")
plt.ylabel("frequency [Hz]")

plt.tight_layout()
plt.show()

# play
wf = wave.open(WAVE_OUTPUT_FILENAME, 'rb')
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                       channels=wf.getnchannels(),
                       rate=wf.getframerate(),
                       output=True)
data = wf.readframes(CHUNK)
while data != b'':
    stream.write(data)
    data = wf.readframes(CHUNK)
    
stream.stop_stream()
stream.close()

p.terminate()

notebookとして整形してあるものはGithubにて公開しております。
ぜひこちらも合わせてご利用ください。
Githubでnotebookのファイルがロードされない場合は、nbviewerで閲覧することができます。

録音部分:record(5行目から)

録音するための設定がまずつらつらと11行目くらいまで書かれています。
サンプリング周波数(RATE)や録音時間(RECORD_SECOND)、チャンネル数(CHANNELS)、量子化ビット数(FORMAT)、出力ファイル名(WAVE_OUTPUT_FILENAME)はまぁまぁわかりますが、
CHUNK(frame_per_buffer)については音データの情報というよりどうやってデータをとるか?という
コンピュータ側の設定
になります。

マイクからの入力は本来はアナログ値ですが、それをコンピュータ上では1秒間にサンプリング周波数分データをとるようになっています。そうして得られたデータは、一旦バッファとよばれる一時的な記憶領域に格納されます。ここで取り込まれたデータはひとつのファイル的な扱いを受けます。バッファにCHUNKで設定した数だけ(今回は1024個)データが取り込まれたら、一旦dataという変数に格納し、framesというリストに加えていきます。
なのでCHUNKを大きくしすぎるとバッファに格納できるサイズを超えてしまうので実行できません。(おそらく大きくすれば遅延が減るなどメリットがあるかもしれませんが、要検証です。)
とりあえず公式ドキュメント通り1024にしておくのが無難です。

34行目からはwaveファイルへの書き込みをしています。
書き込みの設定を録音時の設定にして、各フレームをバイトクラス(38行目:b”)で書き込んでいます。

可視化部分:visualize(41行目から)

実行するとFig. 1のようなグラフが得られます。(「あ、え、い、う、え、お、あ、お」と発声)

Fig. 1 録音データの可視化(上:時間波形、下:スペクトログラム)

特筆すべき点は特にありませんが、57行目のtight_layout()をすることによってグラフがきれいになります。具体的にはsubplotでグラフを並べたとき、何もしなければx軸ラベルやグラフタイトルが重なって見えなくなる現象が起こります。こういうのをなくしてくれるのがtight_layout()です。

再生部分:play(60行目から)

録音部分で書き出したwaveファイルを読み込んで、出力をしています。
出力のための一時的に記憶するデータもファイルのように扱えるので、
書き込み(write)することでスピーカへの出力ができます。

4. まとめ

すでにある音源だけでなく、自分の声や周囲の音を録音して、その周波数・時間ごとの音の強さをスペクトログラムという形で可視化することをやりました。
録音する方法に関してはいろいろな方法がweb上にあげられています。秒数指定ではなくキーボードのイベントを使って任意の長さでの録音や、音量を監視して大きい音のときだけ記録するなど試してみるのも面白そうです。

余談ですが筆者側ではiMacにRolandのDUO-CAPTUREをつなげて、マイクロホンにはAKGのC3000を用いました。今回の課題に対してはリッチすぎる環境です。

「pythonで自分の音声のスペクトログラムを見る」への1件のフィードバック

  1. ピンバック: インパルス応答を使った室内音響測定入門 | 有閑是宝

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です