我在阅读16位.wav文件时遇到问题。我已阅读标题信息,但转换似乎不起作用。
例如,在Matlab中,如果我在波形文件中读取,我会得到以下类型的数据:
-0.0064, -0.0047, -0.0051, -0.0036, -0.0046, -0.0059, -0.0051
但是,在我的C ++程序中,返回以下内容:
0.960938, -0.00390625, -0.949219, -0.00390625, -0.996094, -0.00390625
我需要以相同的方式表示数据。现在,对于8 bit
.wav文件,我执行了以下操作:
uint8_t c;
for(unsigned i=0; (i < size); i++)
{
c = (unsigned)(unsigned char)(data[i]);
double t = (c-128)/128.0;
rawSignal.push_back(t);
}
然而,当我为16位执行此操作时,这很有效:
uint16_t c;
for(unsigned i=0; (i < size); i++)
{
c = (signed)(signed char)(data[i]);
double t = (c-256)/256.0;
rawSignal.push_back(t);
}
不起作用并显示输出(上图)。
我遵循找到的标准Here
其中data
是char
数组且rawSignal
是std::vector<double>
我可能只是将转换错误但似乎无法找出原因。有人有什么建议吗?
由于
编辑:
这是现在显示的内容(在图表中):
这就是它应该显示的内容:
答案 0 :(得分:6)
这里有一些问题:
假设有一个 little-endian 架构,你的代码看起来会更像这样(非常接近Carl的答案):
for (int i = 0; i < size; i += 2)
{
int c = (data[i + 1] << 8) | data[i];
double t = c/32768.0;
rawSignal.push_back(t);
}
big-endian 架构:
for (int i = 0; i < size; i += 2)
{
int c = (data[i] << 8) | data[i+1];
double t = c/32768.0;
rawSignal.push_back(t);
}
该代码未经测试,请LMK如果不起作用。
答案 1 :(得分:1)
(首先关于little-endian / big-endian-ness。WAV只是一种容器格式,其中编码的数据可以是无数格式。大多数编解码器都是无损的(MPEG Layer-3又称MP3,是的,流可以“打包”成WAV,各种CCITT和其他编解码器。)你假设你处理某种PCM格式,你看到RAW格式的实际波,没有进行无损转换。字节序取决于生成流的编解码器。 Is the endianness of format params guaranteed in RIFF WAV files?)
这也是一个问题,如果一个PCM样本是线性比例采样整数还是有一些缩放,对数比例或其后的其他转换。我遇到的常规PCM wav文件是简单的线性比例样本,但我不是在录音或制作行业。
通往解决方案的途径:
确保解释并处理循环迭代器变量和大小。看起来大小告诉您有多少字节。你只有一半的短整数样本。请注意,由于这个原因,Bjorn的解决方案正确地将i递增2。
答案 2 :(得分:0)
16位数量的范围为-32,768到32,767,而不是-256到255(仅为9位)。使用:
for (int i = 0; i < size; i += 2)
{
c = (data[i + 1] << 8) + data[i]; // WAV files are little-endian
double t = (c - 32768)/32768.0;
rawSignal.push_back(t);
}
答案 3 :(得分:0)
你可能想要更像这样的东西:
uint16_t c;
for(unsigned i=0; (i < size); i++)
{
// get a 16 bit pointer to the array
uint16_t* p = (uint16_t*)data;
// get the i-th element
c = *( p + i );
// convert to signed? I'm guessing this is what you want
int16_t cs = (int16_t)c;
double t = (cs-256)/256.0;
rawSignal.push_back(t);
}
您的代码将8位值转换为有符号值,然后将其写入无符号变量。你应该看一下,看看它是不是你想要的。
答案 4 :(得分:0)
我的工作代码是
int8_t* buffer = new int8_t[size];
/*
HERE buffer IS FILLED
*/
for (int i = 0; i < size; i += 2)
{
int16_t c = ((unsigned char)buffer[i + 1] << 8) | (unsigned char)buffer[i];
double t = c/32768.0;
rawSignal.push_back(t);
}