#pragma comment(lib, "OpenAL32.lib")
#pragma comment(lib, "alut.lib")
#include <stdio.h>
#include <AL/alut.h>
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;
class WaveFile{
public:
~WaveFile(){
fp.close();
}
bool Open(const char *path);
int Read(void *out, size_t size);
bool IsEnd()const{return (0==LoadedSize)||(DataSize==LoadedSize);}
ALuint CreateBuffer(ALuint size, ALuint buffer);
private:
unsigned short ChannelQuantity;
unsigned short BlockSize;
unsigned short BitPerSample;
unsigned int Bps;
unsigned int SamplingRate;
ifstream fp;
ifstream::pos_type DataHead;
size_t DataSize;
size_t LoadedSize;
};
bool WaveFile::Open(const char *path){
fp.open(path,ios::binary);
// "RIFF" の読み込み
unsigned int riff;
fp.read((char*)&riff,4);
// データサイズを取得
// データサイズ = ファイルサイズ - 8 byte
fp.read((char*)&DataSize,4);
// WAVEの読み込み
unsigned int wave;
fp.read((char*)&wave,4);
// PCM 情報とデータの先頭の取得
for( int i = 0; i < 2; ++i ){
unsigned int res, size;
fp.read((char*)&res,4);
fp.read((char*)&size,4);
if( 0x20746d66u == res ){//fmt
// PCM 情報の取得
unsigned short res16;
fp.read((char*)&res16,2);
if( 1 != res16 ){// 非対応フォーマット
return false;
}
// モノラル(1), ステレオ(2)
fp.read((char*)&ChannelQuantity,2);
if( 2 < ChannelQuantity ){
return false;
}
// サンプリングレート
fp.read((char*)&SamplingRate,4);
// 1秒あたりのバイト数(byte/sec)
fp.read((char*)&Bps,4);
// ブロックサイズ(byte/sample)
fp.read((char*)&BlockSize,2);
// サンプルあたりのビット数(bit/sample)
fp.read((char*)&BitPerSample,2);
}
else if( 0x61746164u == res ){//data
// データの開始位置を保存
DataHead = fp.tellg();
DataSize = size;
// データを読み飛ばす
fp.seekg(size,ios::cur);
}
}
// データの開始位置までシーク
fp.seekg( DataHead );
LoadedSize = 0;
return true;
}
int WaveFile::Read(void *out, size_t size){
if( !out ){
return 0;
}
// データサイズの調整
if( LoadedSize + size > DataSize ){
size = DataSize - LoadedSize;
}
// データを読み出し書き込む
fp.read((char*)out,size);
LoadedSize += size;
if( LoadedSize == DataSize ){
LoadedSize = 0;
fp.seekg(DataHead);
}
return size;
}
ALuint WaveFile::CreateBuffer( ALuint size, ALuint buffer){
if( !buffer ){// 新規にバッファを作成
alGenBuffers( 1, &buffer );
}
vector<char> wavData(size);
int read = Read(&wavData[0],size);
ALenum format;
if( 1 == ChannelQuantity ){// モノラル
format = (8==BitPerSample)?AL_FORMAT_MONO8:AL_FORMAT_MONO16;
}else{// ステレオ
format = (8==BitPerSample)?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16;
}
// OpenAL のバッファにデータの書き込み
alBufferData( buffer, format, &wavData[0], read, SamplingRate);
return buffer;
}
void main (int argc, char **argv){
// alut の初期化
alutInit (&argc, argv);
// Wave ファイルの読み込み
WaveFile wav;
wav.Open("sample.wav");
// ソースの作成
ALuint source;
alGenSources (1, &source);
// バッファを作成しキューイング
ALuint bufferSize = 1*1024*1024;
ALuint buffers[2];
buffers[0] = wav.CreateBuffer( bufferSize, 0 );
buffers[1] = wav.CreateBuffer( bufferSize, 0 );
alSourceQueueBuffers( source, 2, buffers );
// 再生
alSourcePlay (source);
alutSleep (1);
// 再生し終わったらバッファを埋めて再びキューイング
while(1){
// 処理を終えたキューの数を取得
int processed;
alGetSourcei( source, AL_BUFFERS_PROCESSED, &processed );
while( processed-- ){
// 処理を終えたキューをデキュー
ALuint buffer;
alSourceUnqueueBuffers( source, 1, &buffer );
// バッファを埋める
buffer = wav.CreateBuffer( bufferSize, buffer );
// エンキュー
alSourceQueueBuffers( source, 1, &buffer );
}
}
// リソースを開放
alSourceStop(source);
alDeleteSources( 1, &source );
alDeleteBuffers( 2, buffers );
alutExit ();
return;
}
|