错误在读wav文件与C ++ [英] error in reading a wav file with C++
问题描述
我有一个.wav文件,我想用C来阅读++。我做的RIFF文件头的一些研究,写了code加载它。
I have a .wav file and I want to read it in C++. I have done some research on the RIFF file header and wrote a code to load it.
#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运行这个code。它输出的信息:
However, it is very wired that I run this code on my input file OS.wav. It output the information:
RIFF
307201488
WAVE
Fake
2
0
28006
您可以看到FMT是假货。
You can see the "fmt" is "Fake".
然后我用SOX通过这个WAV文件转换:
Then I use sox to convert this wav file by:
sox OS.wav test.wav
和再次运行我的code。它具有信息:
and run my code again. It has the information:
RIFF
307200050
WAVE
fmt
18
3
2
我没有改变任何事情。但首部信息是如此不同。谁能告诉我,为什么出现这种情况吗?
I did not change any thing. But the header information is so different. Could anyone tell me why this happen, please?
感谢您。
推荐答案
您正在承担的 FMT
块被内的第一个分块中的 RIFF / WAVE
块。这不是一个要求或担保。请在RIFF / WAV格式的一些调查研究。 WAVE
子块可以出现在任何命令,唯一的规则是,该 FMT
块必须在<$出现C $ C>数据块,但其他数据块可以出现之前,之后,并在他们之间。
You are assuming the fmt
chunk is the first sub-chunk within the RIFF/WAVE
chunk. That is not a requirement or a guarantee. Do some more research on the RIFF/WAV format. WAVE
sub-chunks can appear in any order, the only rule being that the fmt
chunk must appear before the data
chunk, but other chunks can appear before, after, and in between them.
分析文件正确的方法是通过分块一次循环。阅读chunkID和CHUNKSIZE,然后读取的字节指定数量(以填充进去),并根据需要在chunkID处理它们,然后重复,直到EOF。这可以让你处理你感兴趣的块并跳过你不关心的人。不要做任何假设他们的订单(但不要验证一种特殊情况),并且绝对不承担 FMT
块是第一个块,因为它可能不可以。
The correct way to parse your file is to loop through the sub-chunks one at a time. Read a chunkID and chunkSize, then read the specified number of bytes (taking padding into account) and process them according to the chunkID as needed, and then repeat until EOF. This lets you process the chunks you are interested in and skip the ones you don't care about. Don't make any assumptions about their order (but do validate the one special case), and definitely don't assume the fmt
chunk is the first chunk, because it might not be.
尝试这样的东西更多:
#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;
}
这篇关于错误在读wav文件与C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!