PortAudioでWAVEファイルを再生してみる(WAVEファイル読み込み編)

# 3編に分かれてます
この記事は前後編に分かれてます。
PortAudioで～って書いてありますがこの前編ではPortAudioの話はほぼ出てきません、
そっちが知りたい方は後編の方参照してください。
あとライブラリのビルドについて書いた準備編もあるのでそちらも参考に。

- [準備編：VS2012でPortAudioの環境構築](http://qiita.com/nicolai_twi/items/86c26fb192f1613ec96a)
- 前編：PortAudioでWAVEファイルを再生してみる(WAVEファイル読み込み編)　←いまここ
- [後編：PortAudioでWAVEファイルを再生してみる(鳴らす編)](http://qiita.com/nicolai_twi/items/35cfbd868f42afedd88d)


#今回からコード書くよ
 __[前回の記事（準備編）](http://qiita.com/nicolai_twi/private/86c26fb192f1613ec96a)に引き続きPortAudioの記事です。__ 
今回も自分用備忘録めいた記事なので、他の人が読むことはあまり考慮してませんすみません。
（公開設定ではありますけど）

前回はライブラリのビルド～サンプル実行時の注意点を書きましたが、
今回はPortAudioを使ってWAVEファイルを再生してみます。 __今回はストリーミングは考慮してません。__ 

相も変わらず実行環境はVS2012,Windows8,64bitです。
PortAudioのライブラリは前回ビルドしたやつ(portaudio_x86.dllとlib)を使用します。

# WAVEファイルは自分で取り扱おう
さて、「再生してみる」とか書きましたが、
その実PortAudioはドライバへ働きかけ、波形をアウトプットする最低限のAPIしかサポートしてません。
なので、 __WAVEファイルを読み込むクラスは自前で用意する必要があります。__ 

OGGとかMP3でやる場合も基本は同じですんで注意してください。
 _なんでわざわざそんなめっちゃ手間なことやってんの？って言われると完全な自己満足です、暇なので_ 

で、今回の参考サイト様なんですけど以下の2つになります。

- http://www.kk.iij4u.or.jp/~kondo/wave/
- http://d.hatena.ne.jp/colorcle/20100203/1265209117

上のサイトはWAVEファイルのデータ構造が載ってるサイトです。
下はWAVEファイル読み込みをクラス化してみましたみたいな記事です。

 __…なんですが、私の理解不足もあってなんか波形の出力がうまくできなかったので、__ 
 __似たようなフォーマットで新しくクラス作ってしまいました／(^o^)＼__ 
 （下のサイトの人見てたらほんとすみません…）

とりあえずWAVEファイルのフォーマット格納する構造体から載せます。

```cpp:wave.h
//WAVEファイル読み込み
//---------------------------------------------------------------------------
#define _CRT_SECURE_NO_WARNINGS
#include <vector>
#include <stdio.h>
#include <string>

//フォーマット格納用
//---------------------------------------------------------------------------
struct WAVE_FORMAT
{
    unsigned short format_id;	//フォーマットID
    unsigned short channel;	//チャンネル数 monaural=1 , stereo=2
    unsigned long  sampling_rate;//１秒間のサンプル数，サンプリングレート(Hz),だいたいは44.1kHz
    unsigned long  bytes_per_sec;//１秒間のデータサイズ 	44.1kHz 16bit ステレオ ならば44100×2×2 = 176400
    unsigned short block_size;	//１ブロックのサイズ．8bit:nomaural=1byte , 16bit:stereo=4byte
    unsigned short bits_per_sample;//１サンプルのビット数 8bit or 16bit
};
//---------------------------------------------------------------------------
```

この構造体には、上の参考サイトで言うところの「データ1」の部分が格納されます。
まぁ、だいたいは __44100Hz,16bit,stereo,リニアPCMフォーマット__ なんじゃないかって気がします。

で、次に波形データと、上の構造体を持ってるクラスを載せます。
とりあえずヘッダのみ。

```cpp:wave.h
//---------------------------------------------------------------------------
class WAVE
{
private:
	WAVE(const WAVE&);                  //コピーコンストラクタ
	WAVE& operator=(const WAVE&);       //代入演算子定義

    WAVE_FORMAT fmt;                    //フォーマット情報
    std::vector<unsigned char> data_8bit;	//音データ(8bitの場合)
    std::vector<short> data_16bit;			//音データ(16bitの場合)

    int RIFFFileSize;					//RIFFヘッダから読んだファイルサイズ
	int PCMDataSize;					//実際のデータサイズ
	int BufPos;							//バッファポジション
	bool LoopFlag;						//ループフラグ
    
public:
	WAVE(bool _LoopFlag = false);
	WAVE(std::string _name,bool _LoopFlag = false);
	~WAVE(){}
	bool LoadFile(std::string _name);
	template <class T> T WAVE::Read(){
		//PCMデータを読んで波形を返す
		if(LoopFlag && Get_End()){
			//ループフラグが立ってる場合、巻き戻し
			BufPos = 0;
		}
		if(fmt.bits_per_sample == 8){
			//8bit
			return data_8bit[BufPos++];
		}else if(fmt.bits_per_sample == 16){
			//16bit
			return data_16bit[BufPos++];
		}
		return 0;
	}

	bool Get_End();
    
    WAVE_FORMAT    Get_Format(){ return fmt; }
    unsigned long  Get_DataSize(){ return PCMDataSize; }
    double Get_Sec(){ return PCMDataSize/(double)fmt.sampling_rate; }
	void Set_LoopFlag(bool _LoopFlag){ LoopFlag = _LoopFlag; }
	bool Get_LoopFlag(){return LoopFlag;}
};
//---------------------------------------------------------------------------
```

Read関数だけヘッダ内に書いてあるのは、
 __メンバ関数テンプレートはヘッダ内に書かないとコンパイルエラーになるため__ です。

波形部分の読み出しですが、16bitの場合shortとしてvectorに読んで、
8bitの場合unsigned charとして読んで格納みたいな実装です。
どうでもいいですが個人的にC++のファイルストリームが嫌いなのでchar*型も嫌いなんですよ…。
普通はとりあえずunsigned char*で保持して、波形として読むときにキャストするみたいな感じだと思いますが、
あんまり好きくないので分けてしまいました。
一応説明すると8bitの場合1byteごとのデータなんでunsigned charで保存、
16bitの場合2byteデータなんでshortで保存してあります。
んでステレオの場合L,R,L,R,...と波形が保存されてるんで、
16bitデータの場合1ブロック4byteです。

 `int RIFFFileSize;` は、上の参考サイトで言うところのファイルサイズ(byte単位)で、
 `int PCMDataSize;` は、上の参考サイトで言うところの __「データの長さ 3」__ に相当します。
 `int BufPos;` は単なるカウンタです。
実際重要な関数部分は

```cpp
	bool LoadFile(std::string _name);
	template <class T> T Read();
	bool Get_End();
```

これだけです。あとはGetter/Setterなので。


Read以外の実装は以下のようになります。

```cpp:wave.cpp
#include "wave.h"

//---------------------------------------------------------------------------
WAVE::WAVE(bool _LoopFlag = false){
	BufPos = 0;
	LoopFlag = _LoopFlag;
}
//---------------------------------------------------------------------------
WAVE::WAVE(std::string _name,bool _LoopFlag = false){
	BufPos = 0;
	LoopFlag = _LoopFlag;
	LoadFile(_name);
}
//---------------------------------------------------------------------------
bool WAVE::LoadFile(std::string _name){
	FILE *fp;
	fopen_s(&fp,_name.c_str(), "rb");

	std::string readbuf;	//適当
	readbuf.resize(4);
	int readbuf2;	//適当なバッファ

	//RIFFを読む
	fread( (char*)readbuf.c_str(), 4,1,fp);	//4byte読む　"RIFF"がかえる
	if(readbuf != "RIFF")return false;

	fread( &RIFFFileSize, 4,1,fp);	//4byte読む　これ以降のファイルサイズ (ファイルサイズ - 8)が返る
	//WAVEチャンク
	fread( (char*)readbuf.c_str(), 4,1,fp);	//4byte読む　"WAVE"がかえる
	if(readbuf != "WAVE")return false;

	//フォーマット定義
	fread( (char*)readbuf.c_str(), 4,1,fp);	//4byte読む　"fmt "がかえる
	if(readbuf != "fmt ")return false;

	//fmtチャンクのバイト数
	fread( &readbuf2, 4,1,fp);	//4byte読む　リニアPCMならば16が返る

	//データ1
	fread( &fmt.format_id, 2,1,fp);	//2byte読む　リニアPCMならば1が返る
	fread( &fmt.channel, 2,1,fp);	//2byte読む　モノラルならば1が、ステレオならば2が返る
	fread( &fmt.sampling_rate, 4,1,fp);	//4byte読む　44.1kHzならば44100が返る
	fread( &fmt.bytes_per_sec, 4,1,fp);	//4byte読む　44.1kHz 16bit ステレオならば44100×2×2 = 176400
	fread( &fmt.block_size, 2,1,fp);	//2byte読む　16bit ステレオならば2×2 = 4
	fread( &fmt.bits_per_sample, 2,1,fp);	//2byte読む　16bitならば16

	//拡張部分は存在しないものとして扱う
	if(fmt.format_id != 1)return false;

	//dataチャンク
	fread( (char*)readbuf.c_str(), 4,1,fp);	//4byte読む　"data"がかえる
	if(readbuf != "data")return false;
	fread( &PCMDataSize, 4,1,fp);	//4byte読む　実効データのバイト数がかえる

	//以下、上のデータサイズ分だけブロックサイズ単位でデータ読み出し
	if(fmt.bits_per_sample == 8){
		//8ビット
		data_8bit.resize(PCMDataSize+1);	//reserveだと範囲外エラー
		fread( &data_8bit[0],1,(size_t)2*PCMDataSize/fmt.block_size,fp);	//vectorに1byteずつ詰めていく
	}else if(fmt.bits_per_sample == 16){
		//16ビット
		data_16bit.resize(PCMDataSize/2+2);	//reserveだと範囲外エラー
		fread( &data_16bit[0],2,(size_t)2*PCMDataSize/fmt.block_size,fp);	//vectorに2byteずつ詰めていく
	}

	fclose( fp );
	return true;	//正常終了
}
//---------------------------------------------------------------------------
bool WAVE::Get_End(){ 
	if(fmt.bits_per_sample == 8){
		return BufPos >= (int)data_8bit.size();
	}else if(fmt.bits_per_sample == 16){
		return BufPos >= (int)data_16bit.size();
	}
	return true;
}
//---------------------------------------------------------------------------
```

 `LoadFile()` がなんか長々と書いてありますが、
やってることはfread()で読んで適宜メンバに格納してるだけです。
書き捨てじみて書いたので例外なにそれおいしいのって感じですね…
まあ元々最低限の機能しかないので置いときましょう。

 `Get_End()` は演奏終了を知らせるだけの関数です。


さて、WAVEファイルを読み込む必要最低限のクラスができたので、
[後編ではこのクラスを利用して実際に音を鳴らしてみます。](http://qiita.com/nicolai_twi/items/35cfbd868f42afedd88d)