リニアPCMのWAVファイルを読み込む

wavファイルを読み込む簡単なC++のクラスを書いた。バイナリファイルを構造体定義とfreadで一気に読み込む方法は始めて知った。なんて楽なんだ。

参考urlのデータ読み出し手順の例を読んでいる限り、タグの現れる順番は予め決まっているわけではないようだ。factとかいうタグ情報もあるみたいだけどもう眠いので明日以降読む。

参考:http://www.kk.iij4u.or.jp/~kondo/wave/

実行結果

winsowsXPのsystem32フォルダにあるLoopyMusic.wavとBuzzingBee.wavを読みこませた。

$ a LoopyMusic.wav | expand --tabs=12
size        940794
rate        44100
bits        16
ch          1
data bytes  940750
duration    10.67sec
$ a BuzzingBee.wav | expand --tabs=12
size        146650
rate        22050
bits        16
ch          1
data bytes  146606
duration    3.32sec

ソース

/*
 * wavファイルの読み込み
 * 参考:http://www.kk.iij4u.or.jp/~kondo/wave/
 */
#include<cstdlib>
#include<iostream>
#include<string>
#include<stdexcept>
using namespace std;

typedef struct {
    uint32_t id;       // "fmt "
    uint32_t bytes;    // fmtチャンクのバイト数
    uint16_t formatID; // フォーマットID
    uint16_t channels; // チャンネル数
    uint32_t rate;     // サンプリングレート
    uint32_t velocity; // データ速度
    uint16_t blocksize;// ブロックサイズ
    uint16_t bits;     // 量子化ビット数

    //uint16_t extension; // 拡張部分のサイズ (リニアPCMならば存在しない)
    // 拡張部分 (extension bytes)
} fmtChunk;
typedef struct {
    uint32_t id;       // "data"
    uint32_t bytes;    // 波形データのバイト数
} dataChunk;

typedef struct {
    uint32_t riffID; // "riff"
    uint32_t size_8; // ファイルサイズ-8
    uint32_t wavID;  // "WAVE"
    fmtChunk fmtchunk;
    dataChunk datachunk;
} wavFileHeader;

class WAVReader {
    wavFileHeader header;
    string filePath;
    uint8_t *raw; // 波形データ

    bool load(){
        FILE *fp = fopen(filePath.c_str(), "r");
        if (!fp){
            perror("WAV::load");
            exit(1);
        }
        fread((void*)&header, sizeof(header), 1, fp);
        size_t rawbytes = header.datachunk.bytes;
        raw = new uint8_t[rawbytes];
        // 波形データの読み込み
        //fread((void*)raw, sizeof(rawbytes), 1, fp); // 修正2009/09/26
        fread((void*)raw, rawbytes, 1, fp);
        fclose(fp);
    }
public:
    WAVReader(const char* path){
        filePath = path;
        load();
    }
    WAVReader(const string& path){
        filePath = path;
        load();
    }
    ~WAVReader(){
        delete[] raw;
    }
    size_t size(){ return header.size_8 + 8; };
    unsigned int bitrate(){ return header.fmtchunk.rate; };
    unsigned int bits(){ return header.fmtchunk.bits; }
    unsigned int channels(){ return header.fmtchunk.channels; };
    unsigned int dataBytes(){ return header.datachunk.bytes; };
};

int main(int argc, char** argv)
{
    if (argc < 2){
        fprintf(stderr, "usage: %s wavfilepath\n", argv[0]);
        return 0;
    }
    WAVReader wav(argv[1]);
    
   
    const char* desc[] = {"size", "rate", "bits", "ch", "data bytes", ""};
    unsigned int val[] = {wav.size(), wav.bitrate(), wav.bits(), wav.channels(), wav.dataBytes()};
    for (int i = 0; desc[i][0] != '\0'; i++)
        printf("%s\t%u\n", desc[i], val[i]);
    
     // 再生時間
    float duration = ((float)wav.dataBytes() / (wav.bits() / 8) / wav.channels()) / wav.bitrate();
    printf("duration\t%.2fsec\n", duration);
    
    return 0;
}