我编写了一些代码,根据位深度从音频缓冲区读取数据,处理它并将其写回相同的缓冲区。我必须处理16和24位深度。 16位代码工作正常但24位代码却没有。
以下是我为24位数据的每个样本所做的事情:
int data = 0;
//read data from buffer
RtlCopyMemory (&data, ((char*)Source) + head, 3);
//scale data for integer
data = data << 8;
//data processing
data = data * m_CurOutVolLevel;
//scaling down the data
data = (data >> 8);
RtlCopyMemory (((char*)Source) + head, &data, 3);
但输出不正确。有人能指出这里有什么问题吗?
由于
感谢您的建议。我实现了你们的建议,但仍有一些缺陷:
unsigned __int64 newData;
unsigned char* s = ((unsigned char*)Source) + head;
unsigned int data = ((unsigned int)s[0] << 8) | ((unsigned int)s[1] << 16) |((unsigned int)s[2] << 24);
// data processing
newData = (unsigned __int64)(data * m_pMiniport->m_CurOutVolLevel);
//divide this by 2 to the power 16
newData = (newData >> 16);
// store back
s[0] = (unsigned char)((newData >> 32) & 0xff);
s[1] = (unsigned char)((newData >> 40) & 0xff);
s[2] = (unsigned char)((newData >> 48) & 0xff);
有人看到上述代码有问题吗?
谢谢,安妮
答案 0 :(得分:1)
好吧,你使用int
,如果是在32位机器上,这通常是32位。如果数据是24位,则移位将意味着您甚至可以使用最高位。这导致两件事:
移位时第一个可能的重载,因为你的int是有符号的,如果位“24”(数据中的最高位)是1,结果中的位32将是1并且它将变为负数号。
乘法的第二个可能的溢出,假设上面没有发生,你现在很可能会过度增加32位数的边界。假设第23位置位,所以你的数字保持正确,如果m_curOutVolLevel甚至只低至2,这等于exta位移,再次你溢出。更有可能你甚至会丢失比特,因为这个数字不能再存储在32位中。
修改:可能的解决方案,如果这是问题:使用uint64_t
中的stdint.h
编辑 2 :另请注意,您的代码可能会出现endianness的问题,因为您只需将int编码为字节流(除非RtlCopyMemory
处理此问题,我怀疑)。
答案 1 :(得分:0)
您无法修改int
的部分内容,只希望代码可以使用(更不用说是可移植的了)。
假设数据以无符号的小端顺序存储,您可以像这样访问它:
unsigned char* s = ((unsigned char*)Source) + head;
uint32_t data = ((uint32_t)s[0] << 8) | ((uint32_t)s[1] << 16) | ((uint32_t)s[2] << 24);
// use data
// store back
s[0] = (unsigned char)((data >> 8) & 0xff);
s[1] = (unsigned char)((data >> 16) & 0xff);
s[2] = (unsigned char)((data >> 24) & 0xff);
但这取决于数据的存储方式。
答案 2 :(得分:0)
你需要对endianness issues这样的代码非常小心,将字节复制到一个多字节的单个变量是不安全的。
最好一次读取一个字节,这样您就可以以字节顺序的方式表达您期望每个字节着陆的值。当然,这需要您考虑源数据中多字节24位值的字节顺序。
答案 3 :(得分:0)
概括@ user786653以获得多个位深度。
uint32_t sample = 0;
for (int i = 0; i < bit_depth / 8; i++) {
sample = ((uint32_t)source[i] << (i * 8)) | sample;
}