将 24 位二进制 char 数组转换为 double读取二进制波形数据

问题描述

我正在尝试读取 2 的补码中存储在波形文件中的 24 位二进制数据。它存储为小端。 我正在尝试将 3 个字符数组重新解释为 int32_t,然后将其转换为 double。 我非常接近,但不知何故无法正常工作。

if (wavHead.getBits_per_Sample() == 24) {
        unsigned char int24[3];
        while (!is.eof()) {
            int32_t val = 0;
            is.read((char *) &int24,sizeof(char) * 3); //ifstream
            if(int24[2] & 0x80) {
                val = 0xff;         //Checking for sign (MSB) and inverting it to bitshift to int32 MSB
                int24[2] &= ~(0x80);
            }
            val = (val << 8) | ((u_int32_t)int24[2]);
            val = (val << 8) | ((u_int32_t)int24[1]);
            val = (val << 8) | ((u_int32_t)int24[0]);

            cout << val / 8388608.0 << endl;
            data.push_back(val / 8388608.0);
        }
    }

这是信号图。它应该是一个简单的 440 Hz 正弦音,但它没有居中,看起来有点可疑: plot of the wave file

感谢您的帮助:)

解决方法

这是错误的:

int24[2] &= ~(0x80);

考虑数字-1,编码成3个字节为FF FF FF。我们在 val 中想要的结果是 0xFFFFFFFF,其中没有未设置的位,这通常适用:在符号扩展时,您要扩展的位本身不会改变。重置它会将 -8388608 的偏移量添加到负值,因此将 -1.0 的偏移量添加到负结果(与绘图匹配)。只需删除该行就可以解决问题。这里还有一种符号扩展的替代方法(还有其他方法):

// note: nothing before this,the sign extension is applied *after* rebuilding
val = (u_int32_t)int24[2];
val = (val << 8) | ((u_int32_t)int24[1]);
val = (val << 8) | ((u_int32_t)int24[0]);
val = (val ^ (1 << 23)) - (1 << 23);