簡體   English   中英

使用C ++讀取WAV文件時出錯

[英]error in reading a wav file with C++

我有一個.wav文件,我想用C ++閱讀。 我已經對RIFF文件頭進行了一些研究,並編寫了代碼來加載它。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

using namespace std;
#define BUFFER_LEN 4096

int main(int argc,char * argv[])
{
    // Buffers etc..
    char ChunkID[4], Format[4], Subchunk1ID[4],Subchunk2ID[4];
    int ChunkSize,Subchunk1Size, SampleRate, ByteRate,Subchunk2Size;
    short AudioFormat, NumChannels, BlockAlign, BitsPerSample;

    // Read the wave file
    FILE *fhandle=fopen(argv[1],"rb");
    fread(ChunkID,1,4,fhandle);
    fread(&ChunkSize,4,1,fhandle);
    fread(Format,1,4,fhandle);
    fread(Subchunk1ID,1,4,fhandle);
    fread(&Subchunk1Size,4,1,fhandle);
    fread(&AudioFormat,2,1,fhandle);
    fread(&NumChannels,2,1,fhandle);
    fread(&SampleRate,4,1,fhandle);
    fread(&ByteRate,4,1,fhandle);
    fread(&BlockAlign,2,1,fhandle);
    fread(&BitsPerSample,2,1,fhandle);
    fread(&Subchunk2ID,1,4,fhandle);
    fread(&Subchunk2Size,4,1,fhandle);
    fclose(fhandle);

    // print RIFF info
    printf("\%c",ChunkID[0]);
    printf("\%c",ChunkID[1]);
    printf("\%c",ChunkID[2]);
    printf("\%c",ChunkID[3]);
    cout << endl;

    // print chunk size
    printf("%d",ChunkSize);
    cout << endl;

    // print format
    printf("\%c",Format[0]);
    printf("\%c",Format[1]);
    printf("\%c",Format[2]);
    printf("\%c",Format[3]);
    cout << endl;

    // print sub chunk 1 ID
    printf("\%c",Subchunk1ID[0]);
    printf("\%c",Subchunk1ID[1]);
    printf("\%c",Subchunk1ID[2]);
    printf("\%c",Subchunk1ID[3]);
    cout << endl;

    // print sub chunk 1 size
    printf("%d",Subchunk1Size);
    cout << endl;

    // print audio format
    printf("%hd",AudioFormat);
    cout << endl;

    // print number of channels
    printf("%hd",NumChannels);
    cout << endl;    

    return 0;
}

但是,非常有線的是,我在輸入文件OS.wav上運行此代碼。 它輸出信息:

RIFF
307201488
WAVE
Fake
2
0
28006

您可以看到“ fmt”是“假”。

然后,我使用sox通過以下方式轉換此wav文件:

sox OS.wav test.wav

然后再次運行我的代碼。 它具有以下信息:

RIFF
307200050
WAVE
fmt 
18
3
2

我什么都沒改變。 但是標題信息是如此不同。 有人可以告訴我為什么會這樣嗎?

謝謝。

您假設fmt塊是RIFF/WAVE塊中的第一個子塊。 那不是要求或保證。 對RIFF / WAV格式進行更多研究。 WAVE子塊可以按任何順序出現,唯一的規則是fmt塊必須出現在data塊之前,而其他塊可以出現在它們之前,之后和之間。

解析文件的正確方法是一次遍歷子塊。 讀取chunkID和chunkSize,然后讀取指定的字節數(考慮填充)並根據需要根據chunkID處理它們,然后重復進行直到EOF。 這樣,您就可以處理您感興趣的塊,並跳過不需要的塊。 不要對它們的順序做任何假設(但要驗證一個特殊情況),並且絕對不要假設fmt塊是第一個塊,因為可能不是。

嘗試更多類似這樣的方法:

#include <iostream>
#include <istream>
#include <stdexcept>
#include <string>

using namespace std;

struct chunkHdr
{
   char id[4];
   unsigned int size;
   unsigned int pos;
};

bool isChunkID(const chunkHdr &c, char id1, char id2, char id3, char id4)
{
    return ((c.id[0] == id1) &&
            (c.id[1] == id2) &&
            (c.id[2] == id3) &&
            (c.id[3] == id4));
}

void read(ifstream &f, void *buffer, streamsize size, chunkHdr *parent)
{
    if (!f.read(static_cast<char*>(buffer), size))
    {
        if (f.eof())
            throw runtime_error("Unexpected EOF while reading from file");
        throw runtime_error("Unable to read from file");
    }
    if (parent) parent->pos += size;
}

void skip(ifstream &f, streamsize size, chunkHdr *parent)
{
    if (!f.seekg(size, ios_base::cur))
        throw runtime_error("Unable to read from file");
    if (parent) parent->pos += size;
}

void read(ifstream &f, chunkHdr &c, chunkHdr *parent)
{
    read(f, c.id, 4, parent);
    read(f, &(c.size), 4, parent);
    c.pos = 0;
}

int main(int argc, char * argv[])
{
    // Buffers etc..
    chunk riff, wave, chk;
    bool fmtFound = false;

    try
    {
        // Open the wave file
        ifstream wavFile(argv[1], ios_base::binary);
        if (!wavFile)
            throw runtime_error("Unable to open file");

        // check the RIFF header
        read(wavFile, riff, NULL);
        if (!isChunkID(riff, 'R', 'I', 'F', 'F'))
            throw runtime_error("File is not a RIFF file");
        cout << "RIFF Size: " << riff.size << endl;

        // check the WAVE header
        read(wavFile, wave.id, 4, &riff);
        wave.size = riff.size - 4;
        wave.pos = 0;

        cout << "RIFF Type: '" << string(wave.id, 4) << "'" << endl;
        if (!isChunkID(wave, 'W', 'A', 'V', 'E'))
            throw runtime_error("File is not a WAV file");

        // read WAVE chunks
        while (wave.pos < wave.size)
        {
            read(wavFile, chk, &wave);
            cout << "Chunk: '" << string(chk.id, 4) << "', Size: " << chk.size << endl;

            if (isChunkID(chk, 'f', 'm', 't', ' '))
            {
                if (fmtFound)
                    throw runtime_error("More than one FMT chunk encountered");
                fmtFound = true;

                unsigned int SampleRate, ByteRate;
                unsigned short AudioFormat, NumChannels, BlockAlign, BitsPerSample, ExtraSize;

                read(wavFile, &AudioFormat, 2, &chk);
                read(wavFile, &NumChannels, 2, &chk);
                read(wavFile, &SampleRate, 4, &chk);
                read(wavFile, &ByteRate, 4, &chk);
                read(wavFile, &BlockAlign, 2, &chk);

                cout << "  Audio Format: " << AudioFormat << endl;
                cout << "  Channels: " << NumChannels << endl;
                cout << "  Sample Rate: " << SampleRate << endl;
                cout << "  Byte Rate: " << ByteRate << endl;
                cout << "  BlockAlign: " << BlockAlign << endl;

                if (chk.size >= 16)
                {
                    read(wavFile, &BitsPerSample, 2, &chk);
                    cout << "  Bits per Sample: " << BitsPerSample << endl;
                }

                if (chk.size >= 18)
                {
                    read(wavFile, &ExtraSize, 2, &chk);
                    cout << "  Extra Size: " << ExtraSize << endl;

                    if (ExtraSize > 0)
                    {
                        // read and process ExtraSize number of bytes as needed...
                        skip(wavFile, ExtraSize, &chk);
                    }
                }

                if (chk.pos < chk.size)
                    skip(wavFile, chk.size - chk.pos, &chk);
            }
            else if (isChunkID(chk, 'd', 'a', 't', 'a'))
            {
                if (!fmtFound)
                    throw runtime_error("No FMT chunk encountered before DATA chunk");

                // read and process chk.size number of bytes as needed...
                skip(wavFile, chk.size, &chk);
            }

            // read other chunks as needed...

            else
            {
                // skip an unwanted chunk
                skip(wavFile, chk.size, &chk);
            }

            // all done with this chunk
            wave.pos += chk.pos;

            // check for chunk padding
            if (chk.size % 2)
                skip(wavFile, 1, &wave);
        }
    }
    catch (const exception &e)
    {
        cout << "Error! " << e.what() << endl;
    }

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM