ストリーミング再生(.wav)(OpenAL)

OpenAL で .wav をストリーミング再生します。

#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;
}

 

 

 

 

最終更新:2012年12月18日 15:46