久しぶりに音声処理をしたくなりました。目標はMFCCと呼ばれるメルケプストラム係数で特徴量抽出をすることです(2022/06/12: 達成しました)。
このあたりの記事をググってもPython2系だったりと10年前ぐらいの記事が多いため、新しく記事を書くことにしました。
ここでの実行環境は次の通りです。
Python 3.8.1
Ubuntu 20.04.4 LTS
検証するwaveファイル
ここでは、440Hzのsin波を1秒間だけ再生するwave形式の音声ファイル(440Hz.wav)で検証を行うことにします。ファイルパラメータは次の通りです。
・チャネル数:モノラル
・1サンプルあたりのバイト数:2 byte
・サンプリング周波数:44100 Hz
・再生時間:1秒
【簡単】waveファイルの波形データをnumpy配列に変換
音声処理をするPythonのライブラリの選択肢は多いです。今回はsoundfileを使用します。
import soundfile
fname = "440Hz.wav"
data, fs = soundfile.read(fname) #data:波形データ, fs:サンプリング周波数
理解していれば3行で波形データを抽出できるので使い勝手がよいです。しかし、これで満足してしまうと少々危険です。なぜかというとwaveの音声データから-1~+1に正規化された波形データになるところがブラックボックスになっているためです。
もう少し詳しく調べるには、組込みwaveモジュールを取り扱う必要があります。ただし、多少のバイナリも触れる必要がある。
以下からは、解説記事になります。
【waveモジュール】組込みwaveモジュールでwaveの波形データを詳細に調べる
wave形式に詳しくなければ、一度自分で調べたいところ。その場合は、組込みwaveモジュールが有効です。
まずは、ファイルパラメータを確認してみます。
import wave
fname = "440Hz.wav"
wave_file = wave.open(fname, 'r')
nchannels = wave_file.getnchannels() #チャネル数
print("nchannels: {0}".format(nchannels))
sample_width = wave_file.getsampwidth() #1サンプルサイズのバイト数
print("sample_width: {0} byte".format(sample_width))
fs = wave_file.getframerate() #サンプリングレート
print("fs: {0} Hz".format(fs))
nframes = wave_file.getnframes() #音声データのデータ点数
print("nframe: {0}".format(nframes))
実行結果は次のようになる。
nchannels: 1
sample_width: 2 byte
fs: 44100 Hz
nframe: 44100
もしくは、次のコードでまとめてパラメータを表示させることができる。
params = wave_file.getparams()
print(params)
実行結果は次のようになります。
_wave_params(nchannels=1, sampwidth=2, framerate=44100, nframes=44100, comptype='NONE', compname='not compressed')
さて、本題に移ります。
どのように正規化された波形データを取得するかを調べます。
手順としては、
1. 一度waveファイルのバイナリの波形データを取得する。
2. 16bit符号付き整数型に変換する。
3. -2^15 ~ 2^15 - 1 の範囲でサンプルデータが量子化されているため、戻してあげると-1~+1の範囲で正規化される。
※なぜ16bit符号付き整数にするかは、標準の形式があるらしく、少々奥が深いので割愛します。
import wave
import numpy as np
fname = "440Hz.wav"
wave_file = wave.open(fname, 'r')
x = wave_file.readframes(wave_file.getnframes()) #waveをバイナリ化
x = np.frombuffer(x, dtype="int16") / (2**15-1) #16bit符号付き整数型に変換し,-1~1で正規化
print(max(x), min(x))
実行結果は次のようになります。確かに44100サンプルあるデータが-1~+1の範囲に収まっています。
0.999969481490524 -0.999969481490524
このx配列と、soundfileライブラリで取得したdata配列を比較すると、同じ配列になっていることがわかります。ファイルパラメータさえ確認してしまえば、納得しながらsoundfileライブラリで波形データが取得できると思います。