はじめに
ここではRIFFファイルとフォーマットの概要と読み込むためのクラスの実装について説明します。
今回の作成するクラスのソースファイルはこちらにあります。 → riffsample_20231210
※WavファイルやSoundfontファイル読込サンプルも同梱されています。
RIFFファイル形式をもとにして作られたファイルの取り扱についても下記にまとめています。
RIFFファイルとは
RIFFファイルとは「Resource Interchange File Format」の略になります。
MicrosoftとIBMが提案したマルチメディア用のファイルフォーマットで、音声や動画などのデータ(=Resource)をアプリケーション間でやり取り(Interchange)するためのファイルフォーマットになります。
アプリケーション固有の情報をファイルに付与しても、他のアプリケーションでの読み込みに影響をなくすように設計されたファイルフォーマットです。
有名なファイルとして音声ファイルの「.wav」や動画ファイルの「.avi」などがある他、DTMでサンプラー等の音色ファイルとして使われるSoundFontファイル(.sf2)もこのRIFFファイルフォーマットとなっています。
RIFFファイルフォーマット概要
RIFFファイルではデータに4Byteの識別子(ID)を付けてデータを管理します。
識別子(ID)はFourCC(4 character codeの略)と呼ばれる形式で、1文字1Byteの4文字(4Byte)であらわす形式になります。
(NULL文字で終端されておらず4Byte固定ですので文字列ではありません。)
識別子(ID)を付けてまとめたデータのかたまりをチャンク(Chunk)と呼びます。識別子(ID)はチャンクIDとも呼ばれます。
チャンクは階層構造にして管理することもできます。
RIFFファイルフォーマットのイメージは下記になります。
チャンクについて
1つ1つのチャンクはすべて下記の構造になっています。
構造 | サイズ | 概要 |
---|---|---|
チャンクID | 4Byte | データにつけられた識別子(ID)。 【例】「WAVE」「fmt 」「smpl」など。(「fmt 」の最後は空白文字がある。) |
データサイズ | 4Byte | データ部のサイズ。単位はByte。 【例】データ部のサイズが100byteなら100になる。 |
データ部 | – | 実際のデータ内容。サイズは上記の「データサイズ」になる。 【例】wavファイルの識別子「data」のチャンクなら音声波形データが保存されている |
チャンクやデータサイズ、データ部のエンディアンは基本的にリトルエンディアンになります。(MIDIのSMFファイルなどはビッグエンディアンのようです。)
特殊なチャンクとしてRIFFチャンクとLISTチャンクがあります。それ以外は一般チャンクとなります。
RIFFチャンクについて
RIFFチャンクは必ずファイルの先頭にあるチャンクで、必ずRIFFファイルのトップ階層になります。
(他のチャンクはすべてRIFFチャンク配下となります。)
RIFFチャンクのチャンクIDは「RIFF」固定で、データ部の先頭4Byteはファイル識別子と呼ばれるFourCC形式のデータが入ります。
ファイル識別子はファイルの種類を示すためのコードになります。(【例】wavファイルの場合「WAVE」、SoundFontファイルの場合「sfbk」等)
構造 | サイズ | 概要 |
---|---|---|
チャンクID | 4Byte | 「RIFF」固定 |
データサイズ | 4Byte | データ部のサイズ。必ず「ファイルサイズ – 8Byte」となる。 (ファイルサイズからチャンクID 4Byteとデータサイズ 4Byteを除いた値。) |
データ部 | – | 実際のデータ内容。 先頭4Byteはファイル識別子(FourCC形式)で、その後はLISTチャンクや一般チャンクが保存されている。 【ファイル識別子 例】wavファイルの場合「WAVE」、SoundFontファイルの場合「sfbk」等 |
LISTチャンクについて
LISTチャンクは一般チャンクをまとめるためのチャンクになります。(一般チャンク配下にはチャンクを入れることができません。)
LISTチャンクのチャンクIDは「LIST」固定で、データ部の先頭4ByteはLIST識別子と呼ばれるFourCC形式のデータが入ります。
LIST識別子はLISTチャンクの種類を示すためのコードになります。
構造 | サイズ | 概要 |
---|---|---|
チャンクID | 4Byte | 「LIST」固定 |
データサイズ | 4Byte | データ部のサイズ。配下の全チャンク合計サイズ + 4Byte(LIST識別子分)になる。 |
データ部 | – | 実際のデータ内容。 先頭4ByteはLIST識別子(FourCC形式)で、その後は一般チャンクが保存されている。 【LIST識別子 例】SoundFontファイルの場合「INFO」「sdta」「pdta」等 |
チャンク構造イメージ
各チャンクの構造をイメージした図が下記になります。
基本的にRIFFチャンクをトップ階層として、その配下にLISTチャンクや一般チャンクがある階層構造になっています。
RIFFファイル形式をもとにして作られたファイルには厳密に階層構造やチャンクの順番等が決められているものもあるようです。
チャンクIDの重複について
チャンクIDについては重複が許されているようで、スタンダードMIDIファイル(.smfファイル)などは同じチャンクIDのチャンクが複数存在することがあります。
RIFFファイル読み込みについて
RIFFファイルの読み込み方法として簡単な方法は、ファイルを開いてから下記を繰り返す形で読み込みます。
厳密には階層構造・チャンク順番等を考慮しなければならないのですが、一般チャンクを探してそのデータを読み込むだけでよい場合が多いためです。
- ファイル内からチャンクIDをもとに必要な一般チャンクを探す
- 探したチャンクのデータサイズ分メモリを確保
- 確保したメモリにチャンクのデータを読み込み
RIFFファイル読み込みクラス
今回作成するRIFFファイル読み込みクラスはCRiffLoaderとしています。
CRiffLoaderクラスの詳細は後述しますが、下記の機能を備えたクラスにしています。
- ファイルを開くためのコンストラクタ
- チャンクIDを指定するとそのチャンクのサイズを返すgetChunkSize()関数
- チャンクIDを指定するとそのチャンクのデータをバッファにコピーするgetChunkData()関数
CRiffLoaderクラスを使えば「RIFFファイル読み込みについて」の手順で読み込めるようにしています。
【使用方法】
具体的にCRiffLoaderクラスは下記のように定義しています。
基本的に上記の「使用方法」以上のことはできませんので、説明については省略させていただきます。
流用する際は下記にご注意ください。
- 可読性を上げるためエラー処理は省いておりますので流用する際は必要なエラー処理を追記ください。
- 再定義している「BYTE」「WORD」「DWORD」「FOURCC」等はwindows.h等と重複しているので必要に応じて書き換えてください
- fopen()関数を利用していますが、Visual Studioではセキュリティ上の警告がでるので、fopen_s()関数などに書き換えてください。
ソースファイルはこちらになります。 → riffsample_20231210
※WavファイルやSoundfontファイル読込サンプルも同梱されています。
【criffloader.h】
最後に
RIFFファイルの概要と読み込みは以上です。
RIFFファイル形式をもとにして作られたファイルの取り扱についても下記にまとめています。必要に応じてご参照ください。
今回の作成するクラスのソースファイルはこちらにあります。 → riffsample_20231210
※WavファイルやSoundfontファイル読込サンプルも同梱されています。
質問はコメント欄や掲示板、Twitterでいただけばとおもいます。
また、「この部分を詳しく」などの要望も掲示板やTwitterでいただければと思います。
■掲示板
■Twitterアカウント:@vstcpp URL:https://twitter.com/vstcpp