以下の記事にありますように、Python ではオーディオファイルの読み込むライブラリが複数あります。
しかし,.mp3, .aac, .m4a といった圧縮コーデックを読み込むものは多くありません。
今回紹介する audioread では ffmpeg のようなバックエンドを呼び出すことで.mp3, .aac, .m4a といった圧縮コーデックもPython上で読み込むことができます*1。
合わせて、.mp3, .aac, .m4a などのオーディオファイルをNumPy配列として読み込むサンプルコードもご紹介します
audioread の使い方
インストール
pip install audioread
ライセンス
MIT License
バックエンド
audioread では以下のようなソフトウェアを使うことで様々な拡張子のオーディオファイルを読み込むことができます。
- Gstreamer (PyGObject)
- Core Audio (on Mac OS X, ctypes)
- MAD (pymad bindings)
- FFmpeg or Libav
- The standard library wave, aifc, and sunau modules (for uncompressed audio formats).
利用方法
基本的な利用方法は以下のようになっています。
信号をブロックごとに読み込み、buf
に格納しています。
ここで,buf
はバイト型であることに注意してください。
with audioread.audio_open(filepath) as f: print(f.channels, f.samplerate, f.duration) for buf in f: do_something(buf)
流石にバイト型を直接使うわけにはいかないので、NumPy配列などに変換する処理が必要になります。
サンプルコード(NumPy配列として読み込み)
librosa.load の実装を参考にサンプルコードを作成しました。
処理の流れと解説:
- ```audioread.audio_open(filepath) を実行
- デコードに使うバックエンドのヘルパーを取得します
- 1D-NumPy配列として読み込み
- バイト型のバッファをブロックごとに読み込む
np.frombuffer
でバイト型を16-bit PCM として Numpy配列に変換するscale
を算出し、信号の振幅値の範囲を変換- [-32768, 32767] から [-1.0, 1.0)
- 利用するブロック(フレーム)以外を捨てる
- 1D-NumPy配列をチャネル数で分割
- 最終的に(チャネル数, 信号長)の信号とする
y.reshape((-1, n_channels))
の-1
は、n_channels
で分割する場合に0次元目の要素数がいくつになるか自動で算出する
# -*- coding: utf-8 -*- import numpy as np import audioread def load_audioread(filepath, offset=0, duration=None, n_bytes=2): # (1) with audioread.audio_open(filepath) as f: sr = f.samplerate n_channels = f.channels s_start = int(np.round(sr * offset)) * n_channels if duration is None: s_end = np.inf else: s_end = s_start + (int(np.round(sr * duration)) * n_channels) # (2) Convert bytebuffer to numpy-1d array and rescale [-32768, 32767] to [-1.0, 1.0) scale = 1.0 / float(1 << ((8 * n_bytes) - 1)) frame_list = [scale * np.frombuffer(frame, f"<i{n_bytes}").astype(np.float32) for frame in f] # (3) Select use frames y = [None for _ in range(len(frame_list))] n = 0 start_idx, end_idx = 0, -1 for k, frame in enumerate(frame_list): n_prev = n n = n + len(frame) if n < s_start: start_idx += 1 continue if s_end < n_prev: end_idx = k - start_idx break if s_end < n: frame = frame[: s_end - n_prev] if n_prev <= s_start <= n: frame = frame[(s_start - n_prev) :] y[k] = frame if end_idx != -1: y = y[start_idx:end_idx] else: y = y[start_idx::] y = np.concatenate(y) # (4) channel-split if n_channels > 1: y = y.reshape((-1, n_channels)).T return y, sr
まとめ
Pythonで .mp3, .aac, .m4a の読み込みができる ライブラリ audioread
を紹介しました。
他のライブラリでは対象とされてないことが多い、.mp3, .aac, .m4a 形式のオーディオファイルを扱えるところがメリットです。
ただし、他のオーディオファイルの読み込みを行うライブラリと比べると、バイト型からの変換が必要となります。
バイト型からの変換は、サンプルコードのように自前で用意しても良いのですが、NumPy配列として読み込みたい場合は librosa.load
を使う方が手っ取り早かったりします。((librosa.load
は条件によってはaudioread
を利用するため))
*1:16ビットの信号に限定