gpt4 book ai didi

c++ - 使用 C++ 读取 wav 文件时出错

转载 作者:行者123 更新时间:2023-11-30 04:02:37 25 4
gpt4 key购买 nike

我有一个 .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”是“Fake”。

然后我使用 sox 通过以下方式转换这个 wav 文件:

sox OS.wav test.wav

然后再次运行我的代码。它有以下信息:

RIFF
307200050
WAVE
fmt
18
3
2

我没有改变任何东西。但是标题信息是如此不同。谁能告诉我为什么会这样?

谢谢。

最佳答案

您假设 fmt block 是 RIFF/WAVE block 中的第一个子 block 。这不是要求或保证。对 RIFF/WAV 格式做更多的研究。 WAVE 子 block 可以以任何顺序出现,唯一的规则是 fmt block 必须出现在 data block 之前,但其他 block 可以出现在它们之前、之后和之间。

解析文件的正确方法是一次一个地循环遍历子 block 。读取一个chunkID和chunkSize,然后读取指定字节数(考虑padding)并根据需要根据chunkID进行处理,然后重复直到EOF。这使您可以处理您感兴趣的 block 并跳过您不关心的 block 。不要对它们的顺序做出任何假设(但要验证一个特殊情况),绝对不要假设 fmt block 是第一个 block ,因为它可能不是。

尝试更像这样的东西:

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

关于c++ - 使用 C++ 读取 wav 文件时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24986506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com