0

.wavファイルのヘッダー情報を読み込もうとしています。

サンプルレートが低い(22050).wavファイルがある場合、すべての情報が完全に読み込まれますが、サンプルレートが高い(8000)と、一部の情報が読み込まれません。

「dataSize」は22050.wavファイルを使用する場合に設定されますが、8000 .wavファイルを使用する場合は設定されず、いくつかの乱数が表示されます。たとえば、実際のサイズが約4k〜4.5kの場合は「1672494080」です。

私が間違っているところへの提案はありますか?

編集:

#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>

using namespace std;
struct riff_hdr
{
   char id[4];
   uint32_t size;
   char type[4];
};

struct chunk_hdr
{
   char id[4];
   uint32_t size;
};

struct wavefmt
{
   uint16_t format_tag;
   uint16_t channels;
   uint32_t sample_rate;
   uint32_t avg_bytes_sec;
   uint16_t block_align;
   uint16_t bits_per_sample;
   uint16_t extra_size;
};


riff_hdr riff;
chunk_hdr chunk;
wavefmt fmt = {0};
uint32_t padded_size;
vector<uint8_t> chunk_data;

bool readHeader(ifstream &file) {

file.read(reinterpret_cast<char*>(&riff), sizeof(riff));
if (memcmp(riff.id, "RIFF", 4) == 0)
{
    cout << "size=" << riff.size << endl;
    cout << "id=" << string(riff.type, 4) << endl;

    if (memcmp(riff.type, "WAVE", 4) == 0)
    {
        // chunks can be in any order!
        // there is no guarantee that "fmt" is the first chunk.
        // there is no guarantee that "fmt" is immediately followed by "data".
        // There can be other chunks present!

        do {

            file.read(reinterpret_cast<char*>(&chunk), sizeof(chunk));
            padded_size = ((chunk.size + 2 - 1) & ~1);

             cout << "id=" << string(chunk.id, 4) << endl;
             cout << "size=" << chunk.size << endl;
             cout << "padded size=" << padded_size << endl;

             if (memcmp(chunk.id, "fmt\0", 4) == 0) 
             {
                 if (chunk.size < sizeof(wavefmt))
                 {
                     // error!
                     file.ignore(padded_size);
                 }else{

                    // THIS block doesn't seem to be executing
                    chunk_data.resize(padded_size);
                    file.read(reinterpret_cast<char*>(&chunk_data[0]), padded_size);

                    fmt = *(reinterpret_cast<wavefmt*>(&chunk_data[0]));

                    cout << "format_tag=" << fmt.format_tag << endl;
                    cout << "channels=" << fmt.channels << endl;
                    cout << "sample_rate=" << fmt.sample_rate << endl;
                    cout << "avg_bytes_sec=" << fmt.avg_bytes_sec << endl;
                    cout << "block_align=" << fmt.block_align << endl;
                    cout << "bits_per_sample=" << fmt.bits_per_sample << endl;
                    cout << "extra_size=" << fmt.extra_size << endl;
                }

                if(fmt.format_tag != 1)
                {
                    uint8_t *extra_data = &chunk_data[sizeof(wavefmt)];
                }
             }else if(memcmp(chunk.id, "data", 4) == 0) {
                file.ignore(padded_size);
            }else{
                file.ignore(padded_size);
            }
        }while ((!file) && (!file.eof()));
    }
}

    return true;
}

int main()
{
ifstream file("example2.wav");


readHeader(file);
return 0;
}

出力:

サイズ=41398

id = WAVE

id = fmt

サイズ=18

パッド入りサイズ=18

チャンクデータサイズ=0

どこが間違っているのですか?

4

1 に答える 1

2

コードに2つの問題があります。

  1. bitsPerSample読み取っていない値の後に2バイトの整数があります。そのチャンク内の余分なデータのサイズを指定します。の値がformat2PCM形式のみを示している場合は、整数の値を無視できます(通常は0になりますが、ガベージになる可能性もあります)が、その存在を考慮する必要があります。非PCM形式の整数は無視できません。値を読み取ってから、その値を読み取る必要があります。ループに入る前に、チャンク全体を読み取っていることを確認する必要がありますwhile。そうしないと、ファイル内の正しい開始位置に移動してさらにチャンクを読み取ることができなくなります。

  2. チャンクが最も近いWORD境界にパディングされることを考慮していませんが、チャンクサイズにはパディングは含まれていません。を呼び出すときはseekg()、値を次のWORD境界に切り上げる必要があります。

更新:投稿した新しいコードに基づいて、代わりに次のようになります。

#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>

using namespace std;

// if your compiler does not have pshpack1.h and poppack.h, then
// use #pragma pack instead. It is important that these structures
// be byte-alignd!

#include <pshpack1.h>

struct s_riff_hdr
{
   char id[4];
   uint32_t size;
   char type[4];
};

struct s_chunk_hdr
{
   char id[4];
   uint32_t size;
};

struct s_wavefmt
{
   uint16_t format_tag;
   uint16_t channels;
   uint32_t sample_rate;
   uint32_t avg_bytes_sec;
   uint16_t block_align;
};

struct s_wavefmtex
{
   s_wavefmt fmt;
   uint16_t bits_per_sample;
   uint16_t extra_size;
};

struct s_pcmwavefmt
{
   s_wavefmt fmt;
   uint16_t bits_per_sample;
};

#include <poppack.h>

bool readWave(ifstream &file)
{
    s_riff_hdr riff_hdr;
    s_chunk_hdr chunk_hdr;
    uint32_t padded_size;
    vector<uint8_t> fmt_data;
    s_wavefmt *fmt = NULL;

    file.read(reinterpret_cast<char*>(&riff_hdr), sizeof(riff_hdr));
    if (!file) return false;

    if (memcmp(riff_hdr.id, "RIFF", 4) != 0) return false;

    cout << "size=" << riff_hdr.size << endl;
    cout << "type=" << string(riff_hdr.type, 4) << endl;

    if (memcmp(riff_hdr.type, "WAVE", 4) != 0) return false;

    // chunks can be in any order!
    // there is no guarantee that "fmt" is the first chunk.
    // there is no guarantee that "fmt" is immediately followed by "data".
    // There can be other chunks present!

    do
    {
        file.read(reinterpret_cast<char*>(&chunk_hdr), sizeof(chunk_hdr));
        if (!file) return false;

        padded_size = ((chunk_hdr.size + 1) & ~1);

        cout << "id=" << string(chunk_hdr.id, 4) << endl;
        cout << "size=" << chunk_hdr.size << endl;
        cout << "padded size=" << padded_size << endl;

        if (memcmp(chunk_hdr.id, "fmt ", 4) == 0) 
        {
            if (chunk_hdr.size < sizeof(s_wavefmt)) return false;

            fmt_data.resize(padded_size);

            file.read(reinterpret_cast<char*>(&fmt_data[0]), padded_size);
            if (!file) return false;

            fmt = reinterpret_cast<s_wavefmt*>(&fmt_data[0]);

            cout << "format_tag=" << fmt->format_tag << endl;
            cout << "channels=" << fmt->channels << endl;
            cout << "sample_rate=" << fmt->sample_rate << endl;
            cout << "avg_bytes_sec=" << fmt->avg_bytes_sec << endl;
            cout << "block_align=" << fmt->block_align << endl;

            if (fmt->format_tag == 1) // PCM
            {
                if (chunk_hdr.size < sizeof(s_pcmwavefmt)) return false;

                s_pcmwavefmt *pcm_fmt = reinterpret_cast<s_pcmwavefmt*>(fmt);

                cout << "bits_per_sample=" << pcm_fmt->bits_per_sample << endl;
            }
            else
            {
                if (chunk_hdr.size < sizeof(s_wavefmtex)) return false;

                s_wavefmtex *fmt_ex = reinterpret_cast<s_wavefmtex*>(fmt);

                cout << "bits_per_sample=" << fmt_ex->bits_per_sample << endl;
                cout << "extra_size=" << fmt_ex->extra_size << endl;

                if (fmt_ex->extra_size != 0)
                {
                    if (chunk_hdr.size < (sizeof(s_wavefmtex) + fmt_ex->extra_size)) return false;

                    uint8_t *extra_data = reinterpret_cast<uint8_t*>(fmt_ex + 1);
                    // use extra_data, up to extra_size bytes, as needed...
                }
            }
        }
        else if (memcmp(chunk_hdr.id, "data", 4) == 0)
        {
            // process chunk data, according to fmt, as needed...

            file.ignore(padded_size);
            if (!file) return false;
        }
        else
        {
            // process other chunks as needed...

            file.ignore(padded_size);
            if (!file) return false;
        }
    }
    while (!file.eof());

    return true;
}

int main()
{
    ifstream file("example2.wav");
    readWave(file);
    return 0;
}
于 2012-12-19T00:19:42.370 に答える