Pythonで.wavファイルを読み込む

標準のwaveライブラリを用いて.wavファイルを読み込む方法


wavファイル読み込み&情報表示

試しにWindowsに付属するwavファイルを読み込んで情報を表示してみます

import wave

# テスト用にWindowsのシステムwavファイルを使用
wav_file = 'C:\Windows\Media\Windows Background.wav'

wav = wave.open(wav_file)                         # wavファイルをオープン
print(f'Channel   : {wav.getnchannels()}')        # チャネル数 (1:モノラル, 2:ステレオ)
print(f'Data Size : {wav.getsampwidth()} Bytes')  # データサンプルサイズ
print(f'Frame Rate: {wav.getframerate()} Hz')     # フレームレート [Hz]
print(f'Frame Num : {wav.getnframes()}')          # フレーム数
print(f'Time      : {wav.getnframes()/wav.getframerate():.3} Sec')  # 時間
# 実行結果
Channel   : 2
Data Size : 2 Bytes
Frame Rate: 22050 Hz
Frame Num : 53395
Time      : 2.42 Sec

チャネル数やサンプルサイズはこの後データを処理していくのに必要となります


データ読み込み

次にデータを読み込んでいきます。readframes()で読み込んだデータはbyteオブジェクトとして返されるため、整数型に変換する必要があります

以下の例ではbytes2int()関数で変換を実施しています。サンプルサイズが1, 2, 4バイトの場合はstruct.unapck()で直接変換可能ですが、3バイトの場合は符号に気を付けて1バイト追加しながら変換する必要があります

import struct

def bytes2int(data_bytes, b_size):
    """バイト列から指定のデータサイズ毎に整数に変換"""
    fmt = {1: 'b', 2: 'h', 4: 'l'}
    if b_size in fmt:
        return struct.unpack(f'{int(len(data_bytes)/2)}{fmt[b_size]}', data_bytes)
    elif b_size == 3:
        # 3Byteに符号に合わせて1Byte追加しながらunpack
        data_int = [struct.unpack('<i',
                                  data_bytes[k:k+3] +
                                  (b'\x00' if data_bytes[k+2] < 0x80 else b'\xff'))
                    for k in range(0, len(data_bytes), 3)]
        return data_int
    else:
        assert False, f'Unsupported sample size {b_size}'

wav_data_int = bytes2int(wav_data, wav.getsampwidth())

左右チャネルの取り出し

各チャネルは交互に並んで格納されています。ステレオ(2チャンネル)場合は以下のようにそれぞれのチャネルを取り出します

# ステレオの場合は左右交互に並んだデータをそれぞれ抽出
wav_data_ch = {'left': wav_data_int[0::2],
               'right': wav_data_int[1::2]}

読み込んだデータをプロットして確かめてみます

import matplotlib.pyplot as plt

# プロットしてみる
for k, v in wav_data_ch.items():
    plt.plot(range(len(v)), v, label=k)
plt.legend()
plt.show()

なんとなく正しそうです


書き出し

書き出しも簡単です。wave.open(file, 'wb')でファイルを開き、チャネル数やフレームレートなどを設定してバイト列を書き込むだけです。例として上記で読み込んだファイルの右チャネルのみをサンプルレートを2倍にしたwavファイルを作成してみます

# 書き出してみる
wo = wave.open('test.wav', 'wb')
wo.setnchannels(1)
wo.setsampwidth(2)
wo.setframerate(wav.getframerate() * 2) # 高音にしてみる
wo.setnframes(len(wav_data_ch['right']))
wo.writeframes(struct.pack(f'{len(wav_data_ch["right"])}h',
                           *wav_data_ch["right"]))
wo.close()

おすすめ