WAVファイルの読み書き

Python
この記事は約27分で読めます。

次のネタのため、ここらでwavファイルの読み書きについてまとめておきます。

WAVファイルの構造

全体の構造

WAVファイルは、RIFFとよばれる型式のファイルの一種です。RIFFとはResource Interchange File Formatの略で、画像や音声を格納する汎用のファイル形式です。

RIFFは、チャンク(=chunk、もとは『大きな塊』を意味する英単語)と呼ばれるデータの単位が並んだ構造をしています。ファイル全体としては以下のようなイメージです。

チャンクには、RIFFチャンク、fmtチャンク、LINKチャンク、JUNKチャンク、dataチャンクなどいろいろな種類があります(上記以外にもあります)。このうちRIFFチャンクがデータ全体を表し、その中にRIFFチャンクのデータとして他のチャンクが一列に並ぶ構造になっています。このように他のチャンクのデータとなっているチャンクのことをサブチャンクと言います。サブチャンクの順番は不定です。

チャンクの基本構造(全チャンク共通)

各チャンクは、基本的に以下のようなフィールドを持っています。

※『位置』はチャンクの先頭を0としてバイト単位で表す(以下全てのチャンクの説明も同じ)

位置バイト数フィールド名意味、値の例
0~34チャンク識別子チャンクの種類を表す文字列
4~74チャンクデータのサイズチャンクデータのバイト数
8~任意長チャンクデータチャンクのデータの本体

各フィールド

チャンク識別子

各チャンク先頭に4バイトの識別子があります。これはチャンクの名前を表す4文字のASCIIコードです。fmtのように名前が4文字に満たない場合は空白文字(0x20)が補われて4バイトになります。

LISTチャンクなら “LIST”=0x4C 49 53 54
fmt チャンクなら “fmt “= 0x66 6D 74 20 (最後に空白文字があることに注意)

など

チャンクデータのサイズ

チャンクデータのバイト数を表します。チャンク全体のサイズからチャンク識別子とチャンクデータのサイズ、合計8バイトを引いた値です。

※RIFFチャンクやLISTチャンクのように、データ本体の前にデータタイプを表すフィールドがあったとしても、チャンクデータのサイズはチャンク全体のサイズから8を引いた値になっています。

次のチャンク(もし次のチャンクがあるとすれば)の開始位置は、このチャンクの開始位置+8+チャンクデータのサイズとなります。ファイル読み込みを実装する場合は、チャンクデータのサイズを読んだ直後にチャンクデータサイズ分だけファイルポインタを進めれば次のチャンクの先頭に移動できます。

チャンクデータ

チャンクデータの内容はチャンクの種類によって異なります。

データの表現

文字列データ

チャンク識別子などの文字列データは、文字順のASCIIコードで格納されます。

数値データ

数値をマルチバイトの列にすると下位のバイトが先になります。
よって、たとえば数値『1』を2バイトで書き込むと、ファイル上は 0x00 01 ではなく 0x01 00 となります。

各チャンクの構造

では、各チャンクの構造をみていきましょう。

RIFFチャンク

位置バイト数項目意味、値の例
0~34チャンク識別子”RIFF”=0x52 49 46 46 に固定
4~74チャンクデータのサイズチャンクデータのバイト数
8~114データフォーマットwavファイルの場合は”WAVE”=0x57 41 56 45 に固定
12~任意長チャンクデータfmt、dataなどのチャンクが並ぶ

各フィールド

チャンク識別子

RIFFチャンクの識別子は、文字列 “RIFF”=0x52 49 46 46 に固定です。

チャンクデータのサイズ

RIFFチャンクはそのデータとして、後で説明するfmtチャンクやdataチャンクなどすべてのチャンクを含んでいます。このように別のチャンクのデータとして含まれているチャンクをサブチャンクと言います。よって、RIFFチャンクのデータサイズは、全サブチャンクサイズの合計=ファイルサイズ-8バイト(RIFFチャンクの『チャンク識別子』フィールド4バイトと『チャンクデータサイズ』フィールド4バイト)を引いたものです。

※『データフォーマット』フィールドはRIFFチャンクのチャンクデータの一部と考えます

データフォーマット

RIFFに含まれるデータの型式を表します。WAVEファイルの場合は文字列 “WAVE”=0x57 41 56 45です。

チャンクデータ

RIFFチャンクのデータはfmtチャンクやdataチャンクなどのサブチャンクです。最初のサブチャンク(wavファイルの場合はfmtチャンク)の開始位置は、ファイル先頭を0バイト目として12バイト目です。

fmt チャンク

wavファイルでは、fmtチャンクは必須です。ほとんどの場合、RIFFチャンクのサブチャンクの中で最初に配置されます。

非圧縮リニアPCMのwavファイルの場合は最後の拡張パラメータの部分が存在しないことが多いので、fmtチャンクのサイズは24bytesです。とはいえ、任意のwavファイルを読み込むプログラムを作成する場合はちゃんとチャンクデータのサイズを確認するように実装するべきです。

位置バイト数項目意味、値
0~34チャンク識別子“fmt “=0x66 6d 74 20に固定
4~74チャンクデータのサイズfmtチャンクのデータのサイズ
(非圧縮リニアPCMでは基本的に16バイト)
8~92音声の型式非圧縮リニアPCMならば 1= 0x01 00
10~112チャンネル数音声データのチャンネル数
12~154サンプリング周波数サンプリング周波数、44.1kHz=44100など
16~1941秒あたりのデータのバイト数の平均非圧縮の場合はブロックサイズ×サンプリング周波数
20~212ブロックサイズ1回のサンプリングで使用するバイト数。
(量子化ビット数÷8)×チャンネル数
22~232量子化ビット数1サンプルあたりのビット数、8や16
24~252拡張パラメータのサイズこの項目自体がない場合もあります
26~不定拡張パラメータこの項目自体がない場合もあります

各フィールド

チャンク識別子

fmtチャンクでは、文字列”fmt “=0x66 6d 74 20に固定です。4文字目が空白文字であることに注意して下さい。

チャンクデータのサイズ

fmtチャンクのデータのサイズです。非圧縮リニアPCMなら(拡張データがないので)16バイト
…と、参考にした本には書いてあったのですが、実は異なるバイト数のファイルも存在するので読み込みプログラムを作る場合には注意が必要です。

音声の型式

音声データの型式を表しています。

非圧縮リニアPCMならば 1= 0x01 00
G.711 A-lawならば 6=0x06 00
G.711 μ-lawならば 7=0x07 00

などとなります。

チャンネル数

音声データのチャンネル数を表します。

モノラルなら1=0x01 00
ステレオなら2=0x02 00

となります。

サンプリング周波数

サンプリング周波数(1秒間に何回サンプリングするか)を表します。

48kHz(業務用素材)ならば 48000=0x80 BB 00 00
44.1kHz(CD音質)ならば 44100=0x44 AC 00 00
8kHz ならば 8000=0x40 1F 00 00

となります。

1秒あたりのデータのバイト数の平均

『平均』となっているのは、データ本体が圧縮形式の場合に時間あたりのデータ量が一定では無いためでしょう。

非圧縮PCMの場合は、

ブロックサイズ×サンプリング周波数

で求められる値と同じで固定です。
たとえばCD音質の場合、サンプリング周波数44.1kHz、ブロックサイズ(後述)4なので

4×44100=176400=0x10 B1 02 00

となります。

ブロックサイズ

1回サンプリングで使用するバイト数です。

(量子化ビット数÷8)×チャンネル数

で求められる値と同じです。
たとえばCD音質の場合は、量子化ビット数16、ステレオ(チャンネル数2)なので

(16÷8)×2=4=0x04 00

となります。

量子化ビット数

1サンプル(1回のサンプリングの1チャンネル分)のデータを表すビット数です。

音楽用の場合は 16ビット=0x10 00

がよく使用されます。

拡張パラメータのサイズ

拡張パラメータのバイト数です。2バイトですが、データ本体が非圧縮リニアPCM型式の場合はこのフィールド自体が存在しないことが多いです。

拡張パラメータ

内容は様々ですが、 データ本体が非圧縮リニアPCM型式の場合はこのフィールド自体が存在しないことが多いです。

dataチャンク

wavファイルでは、dataチャンクは必須です。ただしfmtチャンクの直後に配置されているとは限りません。市販CDからリッピングした場合、JUNQチャンクなどが先に配置され、dataチャンクはその後になることもあるようです。

位置バイト数項目意味、値の例
0~34チャンク識別子”data”=0x50 45 41 4B に固定
4~74チャンクデータのサイズチャンクデータのbyte数
8~任意長チャンクデータ音声データ本体

各フィールド

チャンク識別子

dataチャンクでは、文字列”data”=0x50 45 41 4B で固定です。

チャンクデータのサイズ

dataチャンクのデータのbyte数です。
後述の理由により、量子化ビット数8・モノラルでも必ず偶数になります。

チャンクデータ

音声データの本体です。

モノラルの場合は、

のように、サンプリングされたデータが順に並んでいます。

ステレオの場合は、

のように、左チャンネルのサンプリングデータ、右チャンネルのサンプリングデータ…と交互に並んでいます。

全データのバイト数が奇数の場合、最後に1バイト追加して偶数になるように調整されます。

LISTチャンク

位置バイト数項目意味、値の例
0~34チャンク識別子”LIST”=0x4C 49 53 54 に固定
4~74チャンクデータのサイズチャンクデータのbyte数
8~114リストタイプLISTチャンクのタイプをあらわす4文字の文字列
12~任意長チャンクデータ様々なサブチャンク

各フィールド

チャンク識別子

LISTチャンクでは、文字列”LIST”=0x4C 49 53 54 で固定です。

チャンクデータのサイズ

LISTチャンクのデータのbyte数です。

リストタイプ

LISTチャンクのタイプを表す文字列です。”INFO”=0x49 4E 46 4F などがあります。

チャンクデータ

チャンクデータには、サブチャンクが並びます。

LISTチャンクとサブチャンクの関係は、RIFFチャンクとfmtチャンクやLISTチャンクの関係と同様です。サブチャンクはそれぞれチャンク共通の構造の通り、冒頭4バイトがチャンク識別子、次の4バイトがチャンクデータサイズになっていて、サイズを見ながら順に辿れるようになっています。

LIST_INFOのサブチャンク

ここでは、LISTチャンクのタイプがINFOだった場合について、使用されるサブチャンクをまとめています。非常に種類が多いようなのですが、手元のCDで使われていたのは以下のものでした。

チャンク識別子名称意味
IARTArtist演奏者
ICMTCommentコメント
ICOPCopyright著作権
ICRDDate Created作成された日付
IENGEngineerエンジニア
IGNRGenre楽曲のジャンル
INAMTitle楽曲のタイトル
IPRDProduct制作
ISFTSoftwareソフトウェア
TRCKTruck NumberCDなどメディア内でのトラック番号

_PMX/XMPチャンク

_PMXまたはXMPチャンクとは、XMP(=Extensible Metadata Platform)という、マルチメディアファイルにメタデータを埋め込むXML型式の文書を格納しています。

位置バイト数項目意味、値の例
0~34チャンク識別子”_PMX”=0x5F 50 4D 58 に固定
4~74チャンクデータのサイズチャンクデータのbyte数
8~任意長チャンクデータXMP(XML)のテキストデータ

各フィールド

チャンク識別子

_PMXチャンクでは、文字列”_PMX”=0x5F 50 4D 58で固定です。

チャンクのデータサイズ

_PMXチャンクのデータのbyte数です。

チャンクデータ

XMP(XML型式)のテキストデータが格納されています。

XMPデータは、

ルート要素は必ず x:xmpmeta 要素
x:xmpmeta 要素の中に1つだけ rdf:RDF 要素
rdf:RDF要素の中に複数の rdf:Description 要素があり、その中にメタデータを記述する

となっているXML文書です。wavファイルに埋め込む場合は、さらに全体を

<?xpacket begin=”バイトオーダーマーク id=”W5M0MpCehiHzreSzNTczkc9d”?>
~<?xpacket end=”w”>

で囲みます。バイトオーダーマークは UTF-8なら0xEF BB BF、UTF-16なら0xFE FFなどです。

全体では以下のような感じです(架空のデータです)。
各行行頭の空白や改行も含めて格納されています。

<?xpacket begin="バイトオーダーマーク(UTF-8なら0xEF BB BF)" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core ">
 <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""
     xmp:CreateDate="2021"
     xmpDM:genre="クラシック"
     xmpDM:album="交響曲第1番"
     xmpDM:artist="WAV交響楽団"
     (以下データが続く)
   </rdf:Description>
 </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>

実際のデータ例

ではここで、実際のwavファイルの中を見てみましょう。

例1 最小構成のwavファイル

PythonでFFT』の実験で使用した正弦波ファイルです。

位置バイナリデータ意味
(最初はRIFFチャンク)
00000000~0000000352 49 46 46チャンク識別子 ”RIFF”
00000004~00000007AC 58 01 00総データサイズは0x158AC=88,236 bytes
(ファイルサイズ88,244 bytes - 8 bytes)
00000008~0000000B57 41 56 45データフォーマット “WAVE”
(ここからfmtチャンク)
0000000C~0000000F66 6D 74 20チャンク識別子 “fmt “
00000010~0000001310 00 00 00fmtチャンクのデータサイズは 0x00000010=8 bytes
よって次のチャンクは
0x00000014+0x00000010 = 0x00000024から
00000014~0000001501 00音声の型式は 0x0001 = 1(非圧縮リニアPCM)
00000016~0000001701 00チャンネル数は 0x0001 = 1(モノラル)
00000018~0000001B44 AC 00 00サンプリング周波数は 0x0000AC44 = 44100 = 44.1 kHz
0000001C~0000001F88 58 01 001秒あたりのデータは 0x00015888 = 88,200 bytes
(=ブロックサイズ2 bytes×サンプリング周波数44100)
00000020~0000002102 00ブロックサイズは 0x0002 = 2 bytes
00000022~0000002310 00量子化ビット数は 0x0010 = 16 bits
(ここからdataチャンク)
00000024~0000002764 61 74 61チャンク識別子 “data”
00000028~0000002B88 58 01 00dataチャンクのデータサイズは 0x00015888 = 88,200 bytes
よって次のチャンクは(あるとすれば)
0x0000002C+0x00015888 = 0x0158B4 から
この例ではファイルサイズが88244 bytes = 0x0158B4 なので、
これでファイル終端となります。

例2 市販音楽CDのデータ

市販の音楽CDから1トラックをwavファイルとして取り込んでみました。

最小構成のwavファイルではdataチャンクは36バイト目から・音声データ本体は44バイト目からなのですが、一般的なwavファイルではそうとは限らないことが判ります。音声データを読み込むには、RIFFチャンクのサブチャンクを順にたどってdataチャンクを探さなければなりません。

位置バイナリデータ意味
(最初はRIFFチャンク)
00000000~0000000352 49 46 46チャンク識別子 ”RIFF”
00000004~000000070E 99 80 02総データサイズは0x0280990E=41,982,222 bytes
(ファイルサイズ41,982,230 bytes - 8 bytes)
00000008~0000000B57 41 56 45データフォーマット “WAVE”
(ここからfmtチャンク)
0000000C~0000000F66 6D 74 20チャンク識別子 “fmt “
00000010~0000001310 00 00 00fmtチャンクのデータサイズは 0x00000010=8 bytes
よって次のチャンクは
0x00000014+0x00000010 = 0x00000024から
00000014~0000001501 00音声の型式は 0x0001 = 1(非圧縮リニアPCM)
00000016~0000001702 00チャンネル数は 0x0002 = 2(ステレオ)
00000018~0000001B44 AC 00 00サンプリング周波数は 0x0000AC44 = 44100 = 44.1 kHz
0000001C~0000001F10 B1 02 001秒あたりのデータは 0x0002B110 = 176,400 bytes
(=ブロックサイズ4 bytes×サンプリング周波数44100)
00000020~0000002104 00ブロックサイズは 0x0004 = 4 bytes
00000022~0000002310 00量子化ビット数は 0x0010 = 16 bits
(ここからJUNQチャンク)
00000024~000000274A 55 4E 51チャンク識別子 “JUNQ”
00000028~0000002B26 02 00 00dataチャンクのデータサイズは 0x00000226 = 550 bytes
よって次のチャンクは
0x0000002C+0x00000226 = 0x00000252 から
0000002C~00000251JUNQチャンクのデータ
後のLISTチャンクと重複しますが、
曲名やアーティスト名などが格納されています。
(ここからJUNKチャンク)
00000252~000002554A 55 4E 4B チャンク識別子 “JUNK”
00000256~000002599E 0D 00 00JUNKチャンクのデータサイズは 0x00000D9E = 3,486 bytes
よって次のチャンクは、
0x0000025A + 0x00000D9E = 0x00000FF8 から
0000025A~00000FF7JUNKチャンクのデータ
dataチャンクのデータ本体がキリの良い場所から始まるように
するためのダミーのチャンクで、00で埋められています。
(ここからdataチャンク)
00000FF8~00000FFB64 61 74 61チャンク識別子 “data”
00000FFC~00000FFF20 78 80 02dataチャンクのデータサイズは 0x02807820 = 41,973,792bytes
よって次のチャンクは、
0x00001000 + 0x02807820 = 0x02808820 から
00001000~0280881Fdataチャンクのデータ(音声データ本体)
※このトラックは冒頭1秒ほどが無音のため 00 が並んでいます
(ここから_PMXチャンク)
02808820~028088235F 50 40 58チャンク識別子 “_PMX”
02808824~0280882718 0E 00 00_PMXチャンクのデータサイズは 0x00000E18 = 3,608bytes
よって次のチャンクは、
0x02808828 + 0x00000E18 = 0x02809640 から
02808828~0280963F_PMXチャンクのデータ
XML型式のデータが格納されています。
製作に使用したシステム情報などのようです。
(ここからDISPチャンク)
02809640~0280964344 49 53 50チャンク識別子 “DISP”
02809644~0280964704 00 00 00DISPチャンクのデータサイズは 0x00000004 = 4bytes
よって次のチャンクは、
0x02809648 + 0x00000004 = 0x0280964C から
02809648~0280964BDISPチャンクのデータ
(ここからLISTチャンク)
0280964C~0280964F4C 49 53 54チャンク識別子 “LIST”
02809650~02809653C2 02 00 00LISTチャンクのデータサイズは 0x000002C2 = 706bytes
よって次のチャンクは(あるとすれば)
0x02809654 + 0x000002C2 = 0x02809916 からですが、
0x02809916 = 41,982,230 でファイル終端となります。
02809654~02809915LISTチャンクのデータ
LISTチャンクはさらにいくつかのタイプに分かれています。
ここではINFOというタイプです。
LIST_INFOは内部サブチャンクを含み、
音声データに関する情報を格納しています。
LISTチャンク
 └ INFO
   ├ ICRDサブチャンク:データ作成年月日
   ├ IARTサブチャンク:アーティスト情報
   ├ INAMサブチャンク:曲名
    など

サンプルプログラム

以上の情報をもとに、以前の簡易版よりも対応範囲の広いwavファイル読み込みのモジュールを作ってみました。numpy に依存しています。

※適宜改良するかもしれません

import sys
import numpy

# wav ファイルを読み込む
def readfile(filename):
    # 元音声の読み込み(16ビットモノラル、サンプリング周波数44.1kHz限定)
    f = open(filename, "rb")

    # 先頭は RIFF chunk
    if f.read(4).decode() != "RIFF": 
        return False               #  0~ 3 "RIFF" でなければwavファイルではないので終了
    filesize = int.from_bytes(f.read(4), sys.byteorder)+8       #  4~ 7 ファイルサイズ-8
    if f.read(4).decode() != "WAVE":
        return False               #  8~11 "WAVE" でなければwavファイルではないので終了
    # ここから fmt chunk
    if f.read(4).decode() != "fmt ": 
        return False               # 12~15 "fmt " でなければwavファイルではないので終了

    fmtchunksize = int.from_bytes(f.read(4), sys.byteorder)     # 16~19 fmtチャンクのサイズ、デフォルト 0x10
    formattype = int.from_bytes(f.read(2), sys.byteorder)       # 20~21 フォーマット形式、非圧縮PCMなら0x01
    ch = int.from_bytes(f.read(2), sys.byteorder)               # 22~23 チャンネル数
    samplingfreq = int.from_bytes(f.read(4), sys.byteorder)     # 24~27 サンプリング周波数
    bytepersec = int.from_bytes(f.read(4), sys.byteorder)       # 28~31 1秒あたりのデータのバイト数
    blocksize = int.from_bytes(f.read(2), sys.byteorder)        # 32~33 ブロックサイズ(1サンプリングあたりのバイト数)
    quantizationbits = int.from_bytes(f.read(2), sys.byteorder) # 34~35 1サンプルあたりのビット数

    datachunkpos = 20 + fmtchunksize                            # 36~に拡張データが入る場合がある
    f.seek(datachunkpos)                                        # fmt chunk に拡張データがあっても読み飛ばす

    # data chunk の先頭を探す
    while f.read(4).decode() != "data":                         # 次のchunk識別子が"data"ではない場合、
        skip = int.from_bytes(f.read(4), sys.byteorder)         # その次の4バイトがchunkサイズを表すので、
        f.read(skip)                                            # その分読んでしまう

    datasize = int.from_bytes(f.read(4), sys.byteorder)         #  4~ 7 波形データのバイト数

    # ここから波形データ本体
    if quantizationbits == 8:
        data = numpy.fromfile(f, dtype="uint8")                 # 量子化8ビットなら符号なし8ビット整数
    elif quantizationbits == 16:
        data = numpy.fromfile(f, dtype="int16")                 # 量子化16ビットなら符号付き16ビット整数
    data = data[0:int(datasize/(quantizationbits/8))]           # ファイルの最後まで読むとゴミが入ってるのでdatasize分までで切る

    if ch==2:
        ldata = data[0:len(data):2]                             # ch=2 なら左右に分離
        rdata = data[1:len(data):2]
    else:
        ldata = data
        rdata = data
    
    return {"ch":ch, "samplingfreq":samplingfreq, "quantizationbits":quantizationbits,
            "formattype":formattype, "bytepersec":bytepersec, "blocksize":blocksize, 
            "ldata":ldata, "rdata":rdata}


# wav ファイルを出力する
# data はnumpy.arrayで、
# モノラルなら [[data1,data2,…]] 
# ステレオなら [[ldata1,ldata2,…], [rdata1,rdata2,…]] 
# の型式で与える
def writefile(data, filename, ch=1, samplingfreq=44100, quantizationbits=16):
    # データのチェックと下準備
    if ch == 1:
        if len(data) != 1:
            return False
        else:
            fdata = data[0]
    elif ch == 2:
        if len(data) != 2:
            return False
        elif len(data[0]) != len(data[1]):
            return False
        else:
            fdata = numpy.empty(len(data[0])*2, dtype=data[0].dtype)
            fdata[0:len(fdata):2] = data[0]
            fdata[1:len(fdata):2] = data[1]
    else:
        return False                                        # ch が1,2以外だったらエラー

    if quantizationbits == 8:
        if data.dtype != "uint8":
            return False
    elif quantizationbits == 16:
        if data.dtype != "int16":
            return False
    else:
        return False                                        # quantizationbitsが8,16以外だったらエラー

    blocksize   = int(ch*quantizationbits/8)                # ブロックサイズ(1サンプルあたりのバイト数)
    bytespersec = int(samplingfreq*blocksize)               # 1秒あたりのバイト数
    headersize  = 44                                        # ヘッダサイズ(wavの最小構成では44バイト)
    datasize    = int(len(fdata)*quantizationbits/8)        # 音声データのバイト数
    filesize    = datasize+headersize                       # ファイルサイズ

    f = open(filename, "wb")
    f.write("RIFF".encode())                                # 0- 3 "RIFF"に固定
    f.write((filesize - 8).to_bytes(4, sys.byteorder))      # 4- 7 ファイルサイズ-8
    f.write("WAVE".encode())                                # 8-11 "WAVE"に固定
    f.write("fmt ".encode())                                #12-15 "fmt "に固定
    f.write(0x10.to_bytes(4,sys.byteorder))                 #16-19 fmtチャンクのバイト数、デフォルト0x10
    f.write(0x01.to_bytes(2,sys.byteorder))                 #20-21 音声フォーマット形式、0x01は非圧縮PCM
    f.write(ch.to_bytes(2,sys.byteorder))                   #22-23 チャンネル数 0x01はモノラル
    f.write(samplingfreq.to_bytes(4,sys.byteorder))         #24-27 サンプリングレート44.1kHz
    f.write(bytespersec.to_bytes(4,sys.byteorder))          #28-31 1秒あたりのデータのバイト数
    f.write(blocksize.to_bytes(2,sys.byteorder))            #32-33 ブロックサイズ(1サンプリングあたりのバイト数)
    f.write(quantizationbits.to_bytes(2,sys.byteorder))     #34-35 1サンプルあたりのビット数
    f.write("data".encode())                                #36-39 "data"に固定
    f.write(datasize.to_bytes(4,sys.byteorder))             #40-43 データサイズ

    fdata.tofile(f)                                         #44-   データ本体
    f.close()

コメント

タイトルとURLをコピーしました