より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

サウンドのwavフォーマットを理解して再生時間を割り出してみる

仕事柄ファイルフォーマットについて関心をもつようになったので、今回はwavファイルのファイルフォーマットを自分の手でプログラムを書いて分析してみることにしました。

以下のような0秒未満の効果音に対してミリ秒単位での再生時間を算出することをしてみたいと思います。

f:id:rimever:20190519212910p:plain

ヘッダーの解析

ヘッダーには様々な情報が記載されています。

www.youfit.co.jp

フォーマットとしては素直で固定長で、ここからここまではチャンネル数、ここからここまではブロックサイズとなっています。

file_path = "./input/youfit.wav"
wav_data = open(file_path, "rb")
contents = wav_data.read()
wav_data.close()
print(contents)

# ヘッダー情報を出力します。
print('RIFF = ' + repr(contents[0:4]))
print('チャンクサイズ = ' + str(int.from_bytes(contents[4:8], byteorder='little')))
print('フォーマット = ' + repr(contents[8:12]))
print('fmt識別子 = ' + repr(contents[12:16]))
print('fmtチャンクのバイト数 = ' + str(int.from_bytes(contents[16:20], byteorder='little')))
print('音声フォーマット = ' + str(int.from_bytes(contents[20:22], byteorder='little')))
print('チャンネル数 = ' + str(int.from_bytes(contents[22:24], byteorder='little')))
print('サンプリング周波数(Hz) = ' + str(int.from_bytes(contents[24:28], byteorder='little') / 1000))
print('1秒あたりのバイト数平均 = ' + str(int.from_bytes(contents[28:32], byteorder='little')))
print('ブロックサイズ = ' + str(int.from_bytes(contents[32:34], byteorder='little')))
print('ビット/サンプル = ' + str(int.from_bytes(contents[34:36], byteorder='little')))

print('サブチャンク識別子2 = ' + repr(contents[36:40]))
print('サブチャンク識別子2サイズ = ' + str(int.from_bytes(contents[40:44], byteorder='little')))

f:id:rimever:20190519225152p:plain

再生時間

再生時間 = 波形データサイズ / 1秒あたりのバイト数平均

で割り出せそうですね。

f:id:rimever:20190519224547p:plain

音声を波形に

今回のデータは1サンプル16bit(2bytes)となります。2bytesずつ取得していくことになります。

ステレオだと左、右、左、右と順に取得するのややこしいのですがチャンネルが1つのモノラルです。

全て取得して表示すると、よくわからなくなるので一部を取得して折れ線にしてみます。

f:id:rimever:20190519224735p:plain

参考サイト

Python バイナリデータ

[小ネタ]バイナリを文字列として出力するrepr()[python] | KentaKomai Blog

python3ならintとbytesの変換が楽勝になる - BlankTar

Pythonで 数値 -> バイナリ -> 16進文字列 -> バイナリ -> 数値への変換。 · GitHub