Wizard Notes

Pythonを使った音楽信号分析の技術録、作曲活動に関する雑記

Python:soundfile を使ったオーディオファイル (.wav, .flac, .aiff, .raw, etc.) の読み書き

f:id:Kurene:20210128231121p:plain

Python でオーディオファイルを読み込むライブラリは複数あります。

ぱっと見、どれを使えばよいか迷ってしまいますが、

  • 様々なOSで動いてほしい
  • オーディオファイルをNumPy配列として扱いたい
  • ファイル形式は wav, aiff, flac, raw など(mp3, aacなどは利用しない
  • ブロック(フレーム)ごとに信号を読み込みたい
  • 処理は軽いほうがよい

場合、 soundfile がお勧めです

SoundFile — PySoundFile 0.10.3post1-1-g0394588 documentation

soundfile のエンジンは、libsndfileというCで書かれたライブラリとなっています(ライセンスは LGPL)。

読み書きできるオーディオファイルフォーマットはこちらにまとめられています。

もしも、

  • mp3, aac, m4a 形式のオーディオファイルも扱いたい
  • 読み込み時に信号のサンプリング周波数を変えたい(リサンプリングしたい)

場合は、audioread、特に後者は librosa.load がお勧めです。

www.wizard-notes.com

それでは、soundfile を使ったオーディオファイルの読み込み/書き込み方法をサンプルコードとともに紹介します。


soundfileでのオーディオファイル読み込み

import soundfile as sf
filepath = "xxx.wav" #"xxxx.flac"
data, samplerate = sf.read(filepath)

キーワード引数でalways_2d=Trueとすることで、モノラル信号でも2次元のnumpy配列として取得できます。

取得する信号のnumpy配列のdtype はキーワード引数で指定できます。

なお、dataが2次元の場合、data.shapeは、(信号長, チャンネル数)です。

soundfileでのオーディオファイル書き込み

import soundfile as sf
sr = 44100
filepath = "xxx.wav" #"xxxx.flac"
_format = "WAV"
subtype = 'PCM_24'
sf.write(filepath, data, sr, format=_format, subtype=subtype)

書き込む信号dataのチャンネル数が2つ以上の場合、data.shapeは、(信号長, チャンネル数)であることに注意してください。

format, subtypeの指定方法は、ソースコードに書かれています。以下に、内部で使われている辞書_formats, _subtypesを引用します。これらのKeyとなっている文字列('WAV'や'PCM_16')をformat, subtypeとして与えてください。

# https://github.com/bastibe/python-soundfile/blob/master/soundfile.py#L38
_formats = {
    'WAV':   0x010000,  # Microsoft WAV format (little endian default).
    'AIFF':  0x020000,  # Apple/SGI AIFF format (big endian).
    'AU':    0x030000,  # Sun/NeXT AU format (big endian).
    'RAW':   0x040000,  # RAW PCM data.
    'PAF':   0x050000,  # Ensoniq PARIS file format.
    'SVX':   0x060000,  # Amiga IFF / SVX8 / SV16 format.
    'NIST':  0x070000,  # Sphere NIST format.
    'VOC':   0x080000,  # VOC files.
    'IRCAM': 0x0A0000,  # Berkeley/IRCAM/CARL
    'W64':   0x0B0000,  # Sonic Foundry's 64 bit RIFF/WAV
    'MAT4':  0x0C0000,  # Matlab (tm) V4.2 / GNU Octave 2.0
    'MAT5':  0x0D0000,  # Matlab (tm) V5.0 / GNU Octave 2.1
    'PVF':   0x0E0000,  # Portable Voice Format
    'XI':    0x0F0000,  # Fasttracker 2 Extended Instrument
    'HTK':   0x100000,  # HMM Tool Kit format
    'SDS':   0x110000,  # Midi Sample Dump Standard
    'AVR':   0x120000,  # Audio Visual Research
    'WAVEX': 0x130000,  # MS WAVE with WAVEFORMATEX
    'SD2':   0x160000,  # Sound Designer 2
    'FLAC':  0x170000,  # FLAC lossless file format
    'CAF':   0x180000,  # Core Audio File format
    'WVE':   0x190000,  # Psion WVE format
    'OGG':   0x200000,  # Xiph OGG container
    'MPC2K': 0x210000,  # Akai MPC 2000 sampler
    'RF64':  0x220000,  # RF64 WAV file
}

_subtypes = {
    'PCM_S8':    0x0001,  # Signed 8 bit data
    'PCM_16':    0x0002,  # Signed 16 bit data
    'PCM_24':    0x0003,  # Signed 24 bit data
    'PCM_32':    0x0004,  # Signed 32 bit data
    'PCM_U8':    0x0005,  # Unsigned 8 bit data (WAV and RAW only)
    'FLOAT':     0x0006,  # 32 bit float data
    'DOUBLE':    0x0007,  # 64 bit float data
    'ULAW':      0x0010,  # U-Law encoded.
    'ALAW':      0x0011,  # A-Law encoded.
    'IMA_ADPCM': 0x0012,  # IMA ADPCM.
    'MS_ADPCM':  0x0013,  # Microsoft ADPCM.
    'GSM610':    0x0020,  # GSM 6.10 encoding.
    'VOX_ADPCM': 0x0021,  # OKI / Dialogix ADPCM
    'G721_32':   0x0030,  # 32kbs G721 ADPCM encoding.
    'G723_24':   0x0031,  # 24kbs G723 ADPCM encoding.
    'G723_40':   0x0032,  # 40kbs G723 ADPCM encoding.
    'DWVW_12':   0x0040,  # 12 bit Delta Width Variable Word encoding.
    'DWVW_16':   0x0041,  # 16 bit Delta Width Variable Word encoding.
    'DWVW_24':   0x0042,  # 24 bit Delta Width Variable Word encoding.
    'DWVW_N':    0x0043,  # N bit Delta Width Variable Word encoding.
    'DPCM_8':    0x0050,  # 8 bit differential PCM (XI only)
    'DPCM_16':   0x0051,  # 16 bit differential PCM (XI only)
    'VORBIS':    0x0060,  # Xiph Vorbis encoding.
    'ALAC_16':   0x0070,  # Apple Lossless Audio Codec (16 bit).
    'ALAC_20':   0x0071,  # Apple Lossless Audio Codec (20 bit).
    'ALAC_24':   0x0072,  # Apple Lossless Audio Codec (24 bit).
    'ALAC_32':   0x0073,  # Apple Lossless Audio Codec (32 bit).
}

24-bit, 32-bit float形式wavファイルも簡単に扱えるのがsoundfileの強みだと思います。

soundfileでのオーディオファイル読み込み(ブロック単位)

import soundfile as sf
filepath = "xxx.wav" #"xxxx.flac"
for block in sf.blocks(filepath, blocksize=1024):
    pass  # your_processing(block)

この記法を使うことで、以下のような形でブロックごとのオーディオ信号処理ができます。

引数overlapで重複のある読み込みもできるようです。

例:RMS算出

import numpy as np
import soundfile as sf

rms = [np.sqrt(np.mean(block**2)) for block in
       sf.blocks('myfile.wav', blocksize=1024, overlap=512)]

soundifleでのRawファイルの読み込み

channels, samplerate, subtypeをキーワード引数として与える必要があります。

import soundfile as sf
filepath = 'xxxx.raw'
data, samplerate = sf.read(filepath, channels=1, samplerate=44100,subtype='FLOAT')

まとめ

Python 用のオーディオファイルの読み書きを行うライブラリ soundfileを紹介しました。