24位音频处理

24 bit audio processing

本文关键字:处理 音频 24位      更新时间:2023-10-16

我写了一些代码,根据位深度从音频缓冲区读取数据,处理它并将其写回相同的缓冲区。我必须处理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);

有没有人看到上面的代码问题?

谢谢你,安妮

嗯,您使用int,如果它在32位机器上,则通常为32位。如果数据是24位,移动它意味着你甚至可以使用最高阶位。这会产生两种结果:

  • 移位的第一个可能的过载,因为你的int是有符号的,如果位"24"(数据中的最高位)是1,结果中的32位将是1,它将成为一个负数。

  • 第二个可能的乘法溢出,假设上面的情况没有发生,现在很可能会超出32位数字的边界。假设第23位被设置,所以你的数字保持为正,如果m_curOutVolLevel甚至只低到2,这等于一个额外的位移位,你再次溢出。更有可能的是,你甚至会丢失比特,因为这个数字不能再用32位存储了。

编辑:可能的解决方案,如果这是问题:使用stdint.h中的uint64_t

编辑2:还请注意,您的代码可以给出的问题与字节序,因为您只是将int编码成字节流(除非RtlCopyMemory处理这个,我怀疑)。

您不能修改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);

对于这样的代码,您需要非常小心端序问题,将字节复制到多字节单个变量中是不安全的。

最好一次读取一个字节,这样您就可以用无尾序的方式表示期望每个字节在值中的位置。当然,这需要您考虑数据中多字节24位值的字节排序。

泛化@user786653多位深度答案

uint32_t sample = 0;
for (int i = 0; i < bit_depth / 8; i++) {
    sample = ((uint32_t)source[i] << (i * 8)) | sample;
}