Python3で音データの正規化: 正規化した音データを扱うMATLAB-LIKEな関数の作成

はじめに

PythonでSciPyなどを利用してデータを読み込むと,wavファイルの形式によってデータの最大値が異なり扱いづらいことがあります.wavファイル形式の違いによらずデータの振幅値を[-1, 1]の範囲に正規化して,処理を行いたいときの便利関数を作りました.

具体的には,
wavファイルの形式によらず

  • デフォルトで音データを正規化してくれる wavread() 関数
  • 正規化されたデータを自分でもとに戻さなくても,音量を保って音データを書き込める wavwrite() 関数
  • (関数から呼び出される正規化用関数 audio_normalize() 関数)

が入ったライブラリ matwavlib を作成しましたので,内容を簡単に説明します.

  • 音データにFFT,スペクトログラム解析などを適用したい時
  • 読み込んだファイル形式によらず,データを読み込んで処理がしたい・処理をした音データを保存したい時
  • wavファイルの量子化ビット数を変換したい時

に役に立つのではないかと思います(少なくとも私は忘備録として使います).

対称とする読者

  • 音・音声データをPythonで処理する方(データサイエンスなど)
  • SciPyで時系列解析などを行う方
  • wavファイルのフォーマットの違いを意識せずに音データを扱いたい方
  • そのままコピーして使えるwav読み込み・書き込み関数を必要とする方
  • 特定のwav formatに変換する必要のある方

目次

結論

以下のコードをコピー・ダウンロードして利用してください.
環境には,Numpy, SciPyがインストールされている必要があります(Anacondaを利用している場合,標準でインストールされています).

matwavlib.pyのコード(この行をクリックするとコードが展開されます)

gistfa0a56f9e5e59a4f3a80e375b84c4156

読み込み・書き込みに使える関数の説明

y, fs = wavread(wavfile, norm=True)

  • 説明: 音データの読み込み(デフォルトでデータの正規化)
  • パラメータ
    • wavfile(str): 読み込みたいwavファイルのパスを入力
    • norm(bool): 音データを正規化するかどうか(DefalutでTrue)
  • 返り値
    • y (np.ndarray): 音声データ
    • fs (int): サンプリングレート

wavwrite(wavefile, data, fs, ftype=’float32′)

  • 説明: 正規化されたデータの書き込み
  • パラメータ
    • wavefile(str): 保存したい場所・名前のパス
    • data(np.ndarray): 保存したい音データ(正規化されていないデータも問題なく書き込めます).
    • fs(int): サンプリング周波数
    • ftype(str, parameters = [“float32”, “uint8”, “int16”, “int32”]): 保存するファイル形式の選択 (デフォルトで32bit floating-point format)
      • int: integer PCM format
      • float: floating-point format

使用例

wavread, wavwriteの間でyに対して好みの処理を行ってください.

from matwavlib import matwavlib as mw
infilepath = "input.wav"
outfilepath = "output.wav"
y, fs = mw.wavread(infilepath)
mw.wavwrite(outfilepath, y, fs)
print("input Datatype:", y.dtype)


GitHub

なにか変更やご指摘があればこちらで変更していきます.

github.com

解説

以下に細かい内容などを知りたい人向けの解説を書きます.特に形式を気にしない方は上をコピペしたりダウンロードして使ってもらえればと思います.

SciPy の仕様 -> MATLABの仕様へ

以下の表が,音データ(wav)を読み込む際の,SciPyとMATLABの仕様の違いです.

機能SciPyMATLAB
読み込み正規化なし,wav形式によってデータの最大値異なる,読み込み後自分で正規化する必要ありデータ形式によらず最大値を正規化したデータを返す
書き込み正規化した場合,書き込み前に元の音量に戻す処理が必要正規化されたデータも自動で元の音量に戻す

FFTやスペクトログラム.その他特徴抽出など,科学計算関連の関数を適用する場合には,データが正規化されていたほうが扱いやすいため,MATLABのようにデフォルトでは読み込み,書き込み関数が正規化・正規化解除をやってくれると手間が省けます.

wavread(), wavwrite()関数は,上の表のMATLABのように,関数で読み込めば勝手に正規化・正規化解除をしてくれるように作りました(normパラメータなどで正規化したくない場合はその旨を指定できます).

SciPyで読み込んだ場合・書き込んだ場合のデータ形式の違いについては,
ryoiijima.hatenablog.com

にまとめています.

正規化関数の説明 audio_normalize(y)

def audio_normalize(y):
"""
    Audio data normalization between [-1, 1].
    Parameters
    ----------
    y: numpy.ndarray, audio data from SciPy
    Returns
    ----------
    norm_y: numpy.ndarray, normalized audio data the range is [-1, 1]
    """
print("y.dtype:", y.dtype)
if y.dtype == "float32" or y.dtype == "float64":
max_y = 1
elif y.dtype == "uint8":
y = y - 128 # convert unsigned to signed
max_y = 128
elif y.dtype == "int16":
max_y = np.abs(np.iinfo(np.int16).min)
elif y.dtype == "int32":
max_y = np.abs(np.iinfo(np.int32).min)
else:
raise ValueError("%s can't use datatype for audio normalization. \
            Datatype must be [float32, float64, uint8, int16, int32]" % (y.dtype))
max_y = np.abs(np.iinfo(np.int16).min)
norm_y = y / max_y
norm_y = norm_y.astype(np.float32)
return norm_y


wavread(), wavwrite()から,正規化するための関数 audio_normalize() を呼び出すことによって,ファイル形式ごとに正規化する処理をしています.
最大値を取得して,データの各値を最大値で割ることで,[-1, 1]の間のデータ形式にしています.(scipyの音データ np.ndarrayを引数として渡せば使えます.)

同様にして,wavwrite()関数では,指定されたファイル形式に合わせて,値の範囲を[-1, 1]からもとに戻す処理を行っています.例えば,16bit integer PCMでは,[-32768, 32767]の範囲となるように最大値をかける処理を行います.この処理を忘れると,書き出されたファイルの音量が小さい・聞こえなくなってしまいます.

正規化をする際の注意点は,8 bit unsigned integer PCM 形式のファイルの場合,符号なしデータを0-255の範囲で扱っているため,他の形式と同じ用に扱うためには,128を引く・足すことによって半分ずらす必要があります.これらを考えるのが億劫なため,今後に備えてこのような関数を作りました.

参考文献

正規化の方法を参考にさせていただきました.

コメントを残す

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

*