C ++ - 阅读在16位.wav文件 [英] C++ - Reading in 16bit .wav files
问题描述
我想在一个.wav文件,我还以为是给我正确的结果,但是,当我绘制在Matlab或Python相同的音频文件读取,结果是不同的。
I'm trying to read in a .wav file, which I thought was giving me the correct result, however, when I plot the same audio file in Matlab or Python, the results are different.
这是我得到的结果是:
这就是,Python(绘出matplotlib)的结果表明了:
This is the result that Python (plotted with matplotlib) gives:
结果似乎并没有不同,但是,当涉及到分析,这是搞乱我的结果。
The results do not seem that different, but, when it comes to analysis, this is messing up my results.
下面是code的转换:
Here is the code that converts:
for (int i = 0; i < size; i += 2)
{
int c = (data[i + 1] << 8) | data[i];
double t = c/32768.0;
//cout << t << endl;
rawSignal.push_back(t);
}
我在哪里去了?因为,这种转换看似正常并且不产生这样的类似的结果。
Where am I going wrong? Since, this conversion seems fine and does produce such a similar results.
感谢
编辑:
code读头/数据:
Code to read the header / data:
voidreadHeader(ifstream& file) {
s_riff_hdr riff_hdr;
s_chunk_hdr chunk_hdr;
long padded_size; // Size of extra bits
vector<uint8_t> fmt_data; // Vector to store the 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;
{
do
{
file.read(reinterpret_cast<char*>(&chunk_hdr), sizeof(chunk_hdr));
if (!file) return false;
padded_size = ((chunk_hdr.size + 1) & ~1);
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]);
sample_rate2 = fmt->sample_rate;
if (fmt->format_tag == 1) // PCM
{
if (chunk_hdr.size < sizeof(s_pcmwavefmt)) return false;
s_pcmwavefmt *pcm_fmt = reinterpret_cast<s_pcmwavefmt*>(fmt);
bits_per_sample = pcm_fmt->bits_per_sample;
}
else
{
if (chunk_hdr.size < sizeof(s_wavefmtex)) return false;
s_wavefmtex *fmt_ex = reinterpret_cast<s_wavefmtex*>(fmt);
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...
}
}
//cout << "extra_size=" << fmt_ex->extra_size << endl;
}
else if (memcmp(chunk_hdr.id, "data", 4) == 0)
{
// process chunk data, according to fmt, as needed...
size = padded_size;
if(bits_per_sample == 16)
{
//size = padded_size / 2;
}
data = new unsigned char[size];
file.read(data, size);
file.ignore(padded_size);
if (!file) return false;
}
{
// process other chunks as needed...
file.ignore(padded_size);
if (!file) return false;
}
}while (!file.eof());
return true;
}
}
这是这里的转换为双发生什么:
This is where the "conversion to double" happens :
if(bits_per_sample == 8)
{
uint8_t c;
//cout << size;
for(unsigned i=0; (i < size); i++)
{
c = (unsigned)(unsigned char)(data[i]);
double t = (c-128)/128.0;
rawSignal.push_back(t);
}
}
else if(bits_per_sample == 16)
{
for (int i = 0; i < size; i += 2)
{
int c;
c = (unsigned) (unsigned char) (data[i + 2] << 8) | data[i];
double t = c/32768.0;
rawSignal.push_back(t);
}
请注意如何8位文件正常工作?
Note how "8bit" files work correctly?
推荐答案
我怀疑你的问题可能是数据
是签署阵列的字符
值。所以,当你做到这一点:
I suspect your problem may be that data
is an array of signed char
values. So, when you do this:
int c = (data[i + 1] << 8) | data[i];
...它实际上没有做你想要的东西。让我们看一些简单的例子。
… it's not actually doing what you wanted. Let's look at some simple examples.
如果数据[I + 1] == 64
和数据[I] == 64
,这是怎么回事是0x4000的| 0X40,或0x4040,都好。
If data[i+1] == 64
and data[i] == 64
, that's going to be 0x4000 | 0x40, or 0x4040, all good.
如果数据[I + 1] == -64
和数据[I] == -64
,这将是0xffffc000 | 0xffffffc0,或0xffffffc0,这显然是错误的。
If data[i+1] == -64
and data[i] == -64
, that's going to be 0xffffc000 | 0xffffffc0, or 0xffffffc0, which is obviously wrong.
如果你使用 unsigned char型
值,这会工作,因为不是-64这些数字将是192,你会最终0xC000时|将0xC0或0xc0c0,就像你想要的。 (但是,那么你的 /32768.0
会给你号码0.0至2.0,当你presumably想-1.0到1.0的范围内。)
If you were using unsigned char
values, this would work, because instead of -64 those numbers would be 192, and you'd end up with 0xc000 | 0xc0 or 0xc0c0, just as you want. (But then your /32768.0
would give you numbers in the range 0.0 to 2.0, when you presumably want -1.0 to 1.0.)
提示有修复,很难不知道究竟你正在试图做的。显然,你想要某种16位小端整数格式转换成某种形式的浮点格式,但很多依赖于这些格式的具体细节,并且没有提供任何详情。默认的.wav格式是16位无符号小尾数整数,因此仅仅使用无符号字符*
将解决方程式的一部分。但我不知道使用64位浮点数从0.0到2.0的音频格式,我不知道什么音频格式,你实际上是瞄准了,所以我不能说什么 /32768.0
实际上应该是,只是它可能是错误的。
Suggesting a "fix" is difficult without knowing what exactly you're trying to do. Obviously you want to convert some kind of 16-bit little-endian integer format into some kind of floating-point format, but a lot rests on the exact details of those formats, and you haven't provided any such details. The default .wav format is 16-bit unsigned little-endian integers, so just using unsigned char *
would fix that part of the equation. But I don't know of any audio format that uses 64-bit floating point numbers from 0.0 to 2.0, and I don't know what audio format you're actually aiming for, so I can't say what that /32768.0
should actually be, just that it's probably wrong.
这篇关于C ++ - 阅读在16位.wav文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!