音を眺める(グラフ化)

Python

時間変化の可視化

音声信号は時間軸と振幅軸の2次元グラフとして描画することができます。
音声信号はグラフ化して目で見て確認することで、耳で聴いているだけでは気づかないような音声に加えられた効果(サウンドエフェクト)がより具体的にイメージできるようになったり、信号解析には欠かせない特徴を発見できるようになったりします。

Pythonで読み込んだ音声データをそのままグラフ化するコードは以下のようになります。

# wavファイルの読み込み
from scipy.io import wavfile
import numpy as np
import matplotlib.pyplot as plt

# wavファイルのパス
INPUT_FILENAME = "input.wav"
fs, data = wavfile.read(INPUT_FILENAME)

# グラフを描画する。
time = np.linspace(0., data.shape[0]/fs, data.shape[0]) # X軸の値(時間)
fig, ax = plt.subplots(figsize=(10, 3))
ax.plot(time, data[:], label="Speech Sound")
ax.legend()
ax.set_xlabel("Time [s]")
ax.set_ylabel("Amplitude")
plt.show()

音声信号の全体をそのままグラフ化すると、波形の概形(エンベロープ)を確認することができます。
エンベロープが確認できるようになると、サウンドエフェクトの影響具合を目視確認できるようになったり、音声データ内の無音区間が露わになり解析に不要なデータ量を削減できるようになったりします。
しかし、音声データは1秒間に数千~数万サンプリングという膨大なデータ量を扱うため、特に単調な音源データを扱うとその実態が捉えづらくなります。

上段のように単純な正弦波はそのままグラフ化するとグラフが潰れてしまい、波形の特性が読み取れません。必要に応じて下段のグラフのように波形を拡大して、波形の細かい構造まで確認してみましょう。

周波数成分の可視化

音声信号は周波数軸と振幅軸の2次元グラフとして描画することができます。音声信号は様々な周波数の合成波となっていることが多く、特に人の声であれば20Hz~1000Hz程度の音声が複雑に組み合わさっています。
周波数成分を読み取ることができれば音声を聞かずとも、その音声がどのような特徴を持っているか把握することができます。もし仮に、一般に不快音とされるような2000Hz~4000Hzの周波数帯を含む音声が録音されてしまったとしても、周波数成分の可視化をしていれば事前に回避することができますね。

周波数成分を算出するためにはフーリエ変換を行う必要がありますが、Pythonを使用すればたった数行で実装することができます。
(※実際は音声データ全体を一括でフーリエ変換にかけることは稀ですが、今回はフーリエ変換のプログラムを理解することを優先します。)

# wavファイルの読み込み
from scipy.io import wavfile
import numpy as np
import matplotlib.pyplot as plt

# wavファイルのパス
INPUT_FILENAME = "input.wav"
# WAVファイルの読み込み
fs, data = wavfile.read(INPUT_FILENAME)

# フーリエ変換
spectrum = np.fft.fft(data)

# 周波数軸の作成
freq = np.fft.fftfreq(len(data), 1.0 / fs)

# グラフを描画する。
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(freq[: len(freq)//2], np.abs(spectrum)[: len(spectrum)//2], label="Speech Sound")
ax.legend(loc='upper right')
ax.set_xlabel("Frequency[Hz]")
ax.set_ylabel("Amplitude")

plt.show()

上図は人の声をフーリエ変換してグラフ化したものです。
前述の通り、20Hz~1000Hzの間に主なピークが存在します。このピークの値やピークの出現周波数は発言の内容や発話者の声質によって変化します。

スペクトログラムの変化(時間×周波数×振幅)

音声データを時間軸方向に短い間隔に切り分け、それぞれをフーリエ変換することで3次元データを作成します。こうして作成された3次元データをスペクトログラムと呼び、時間変化と周波数変化を同時に可視化することができます。

# wavファイルの読み込み
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile

# wavファイルのパス
INPUT_FILENAME = "input.wav"

# WAVファイルの読み込み
fs, data = wavfile.read(INPUT_FILENAME)

# スペクトログラムの計算
f, t, Sxx = signal.spectrogram(data, fs)

# グラフを描画する。
fig, ax = plt.subplots(figsize=(10, 4))
ax.pcolormesh(t, f, 10 * np.log10(Sxx))
ax.set_xlabel('Time [sec]')
ax.set_ylabel('Frequency [Hz]')

plt.show()

縦軸は周波数、横軸は時間、色は振幅を表します。音声信号が記録されている区間は暖色(上図では黄色)、無音区間は寒色(上図では青または緑)で描画されています。人の声が録音されている区間には独特の縞模様が確認できます。

前述の通り、人の声を記録した音声信号にはその発話内容や発話者の特性が含まれています。そのため、可視化したときに耳で聴かなくとも「誰が」「何と」話していたのか推察するヒントが隠されています。

コメント