traveler47’s diary

twitter @gamepgyaruo

初投稿とWaveFileの読み込みをしてみた

ブログはじめました。

不定期更新になると思いますが頑張っていきましょう!
今日は初投稿ということもありテストも兼ねてWaveファイルの読み込みを最近したのでそのメモを残そうと思います。Waveファイルを読み込むにあたってまず必要になる情報はWaveファイルフォーマットになるので調べてみました。

この辺のサイトが参考になると思います。
1.http://www.kk.iij4u.or.jp/~kondo/wave/
RIFFについてはここが簡潔に書かれていそう
2.http://www.umekkii.jp/data/computer/file_format/riff.cgi

どうやらWaveファイルはRIFFというフォーマットの一種(?)らしい。
ではRIFFフォーマットとはなんぞやという話なのですがそれに関しては上のリンクの2.のサイトが解説してくれている。
チャンクとかリストとかいろいろ言っていますが要はそういうことです。
識別子・サイズ・データの3つの情報が集まったものが1チャンクとして扱われます。(フォームタイプというものが存在する場合もあるので一概に3つとは言えないけど)
ここで注意してほしいのがWaveファイルのデータの並びが必ずしも1.のサイトに記述されているとおりではないということで拡張部分とdataチャンクの間にLISTチャンクが存在する可能性もあるということ(というより自分がプログラムを組んでたらそういうのを見たし勿論それ以外のデータの並びもあると思う)
また今回は無圧縮PCMに限った話なので一概にこれでWaveファイルをマスターしたとも言い切れません。

そんなこんなで自分が組んだコードがこちら

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

using ChunkID = char[4];

struct Chunk
{
	std::string mName;
	long        mSize;
	std::vector<unsigned char> mData;

	Chunk() :
		mName(""), mSize(0), mData(0){}
};

class WaveFileLoader
{
public:
    template<typename ValueType>
    void Read(ValueType* pValue, int pSize){ mWaveFileStream.read(reinterpret_cast<char*>(pValue), pSize); }

    void LoadChunk(WaveFile* pWaveFile)
    {
	Chunk lChunk;

	//IDを取得する
	lChunk.mName.resize(sizeof(ChunkID));
	Read(&*lChunk.mName.begin(), sizeof(ChunkID));

	//eofを検出したら終了
	if (mWaveFileStream.eof()) return;

	//このデータ以降のデータサイズを取得する
	Read(&lChunk.mSize, sizeof(lChunk.mSize));

	//IDがLISTであればフォームタイプが次にくるはずなので
	//データ幅を4バイトにしてフォームタイプをデータにつっこむ
	//そうでなければ普通にデータを前のデータサイズ分突っ込む
	if (lChunk.mName == "LIST")
	{
		lChunk.mData.resize(4);
		Read(lChunk.mData.data(), sizeof(lChunk.mData.size()));
	}
	else
	{
		lChunk.mData.resize(lChunk.mSize);
		Read(lChunk.mData.data(), sizeof(char) * lChunk.mData.size());
	}

	//etc...etc...
	pWaveFile->mChunks.push_back(lChunk);

        //データチャンクはアクセスしやすいようにしとく
	if (lChunk.mName == "data")
		pWaveFile->mDataChunk = &(pWaveFile->mChunks.back());

	//eof検出するまで同じようなこと再帰的にやってく
	LoadChunk(pWaveFile);
    }

private:
	std::ifstream mWaveFileStream;
};

いろいろ突っ込みどころの多いコードだとは思いますがそこはお許しください。
ヘッダ部分とかいろいろあるとは思うんですがそこは割愛して重要そうな部分だけ抽出しました。
あとはこのコードが安全である自信が全くありません。何故ならwaveファイル2つくらいしか試してないから(笑)
完全なテスト不足ですが参考までに。

なにか間違っているところ質問などありましたらコメントやツイッターで教えていただければ対応できる範囲でします。