解交织PCM(* .wav)立体声音频数据

时间:2014-06-17 13:45:57

标签: c++ encoding pcm vorbis

我知道PCM数据存储为[left][right][left][right]...。我试图将立体声PCM转换为单声道Vorbis(* .ogg),据我所知,可以通过将左右声道减半((左+右)* 0.5)来实现。我实际上通过修改libvorbis sdk中的编码器示例来实现这一目标,

#define READ 1024
signed char readbuffer[READ*4];

,因此读取PCM数据

fread(readbuffer, 1, READ*4, stdin)

然后我将这两个频道减半,

buffer[0][i] = ((((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))/32768.f) + (((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))/32768.f)) * 0.5f;

它工作得很好,但是,我不明白它们如何从PCM数据中解交左右声道(即所有的位移和&#34; ANDing&#34;和#34; ORing&# 34。)

1 个答案:

答案 0 :(得分:7)

<。> .wav文件通常以 little endian 格式存储其PCM数据,每个通道每个样本16位。对于通常签名的16位PCM文件,这意味着数据实际存储为

[LEFT LSB] [LEFT MSB] [RIGHT LSB] [RIGHT MSB] ...

这样每组4个字节组成一个立体声PCM样本。因此,您可以通过查看字段i4*i来查找示例4*i+3

要从两个字节解码单个16位值,请执行以下操作:

(MSB << 8) | LSB

因为您的读缓冲区值存储为 signed 字符,所以您必须要小心,因为MSBLSB都将进行符号扩展。这对LSB来说是不可取的;因此,代码使用

0xff & (int)LSB

获取低字节的无符号版本(从技术上讲,这通过向上转换为int,并选择低8位;另一种方法是只写(uint8_t)LSB)。

请注意,MSB位于索引1和3处,LSB位于索引0和2处。因此,

((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))

((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))

只是通过使用一些位操作将字节组合成数字来获取左右通道的值为16位有符号值。

然后,将这些值中的每一个除以32768.0。请注意,带符号的16位值的范围为[-32768, 32767]。因此,除以32768得到大约[-1,1]的范围。将两个除以的值相加以得到[-2,2]范围内的数字,然后将整数乘以0.5以获得平均值(范围[-1,1]中的浮点值)。

相关问题