我正在搞乱音频文件并学习如何提取样本以进行操作而不是。现在我正在使用.wav文件,并假设标头是44个字节,样本大小是16位。
所以我编写了这段代码,它接受两个char值并将其存储为2字节短,以便我可以将其转换为32位浮点数。
short ss = ((0x0000 | data[i*2+1]) & 0xff) << 8;
short fs = (0x0000 | data[i*2]) & 0xff;
short s = fs | ss;
最初我使用memcpy(&s, &data[i*2], 2)
来执行此操作。他们都实现了我想做的事情,并且我能够获取值并将其流式传输到输出缓冲区并且工作正常。
我想知道执行按位运算是否值得,而不仅仅是简单地调用memcpy性能。
答案 0 :(得分:1)
根据编译时使用的各种优化等,对于如此小的副本(两个字节),memcpy会明显变慢。有几种方法可以使这更好。例如,您可以使用union来允许编译器访问内存字的不同部分。
inline float getSamp(char *data, int i)
{
union char_short
{
char d[2];
short s;
} sdata;
float f;
sdata.d[1] = data[i*2+1];
sdata.d[0] = data[i*2];
f = sdata.s / 32768.0f; // using 32768 because this is signed,
// and the maximum negative value is -32768.
// This gets you a range of -1 to +0.9999695
return f;
}
由于数组索引,这种方法仍然不是最优的。
使用内联(因此不执行调用)和位操作可以进一步优化。此外,取消引用该数组可以节省一些数组地址计算。如果您可以将数据点保存到正确的字节,您甚至可以保存此解除引用。
inline float getSample(char *data, int i);
{
char *d = &data[2 * i];
short sdata = ((*d) & 0x00FF);
d++;
sdata |= ((*d << 8) & 0xFF00);
return sdata / 32768.0f;
}
虽然您可以进一步调整,但由于编译器的优化会为您带来更多优势,因此不值得付出努力。
所以,回答这个问题 - 这取决于。你移动了多少记忆,你做了多少操纵?鉴于目前多核处理器的速度,音频太容易了。但是,如果您使用的是速度和内存大小很重要的小型ARM嵌入式系统,那么最后一个例程将会产生很大的不同。
祝你好运
答案 1 :(得分:0)
不太重要,但memcpy
会慢一点很多。可能慢2到3倍。它需要一个带循环计数的循环。