MOH*_*OHW 6 c++ encoding pcm vorbis
我知道PCM数据存储为[left][right][left][right]....我试图将立体声PCM转换为单声道Vorbis(*.ogg),据我所知,可以通过将左右声道减半((左+右)*0.5)来实现.我实际上通过修改libvorbis sdk中的编码器示例来实现这一点,
#define READ 1024
signed char readbuffer[READ*4];
Run Code Online (Sandbox Code Playgroud)
并且因此读取PCM数据
fread(readbuffer, 1, READ*4, stdin)
Run Code Online (Sandbox Code Playgroud)
然后,我将这两个频道减半,
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;
Run Code Online (Sandbox Code Playgroud)
它工作得很好,但是,我不明白他们如何从PCM数据中解交左右声道(即所有的位移和"ANDing"和"ORing").
.wav文件通常以小端格式存储其PCM数据,每个通道每个样本16位.对于通常签名的16位PCM文件,这意味着数据被物理存储为
[LEFT LSB] [LEFT MSB] [RIGHT LSB] [RIGHT MSB] ...
Run Code Online (Sandbox Code Playgroud)
这样每组4个字节组成一个立体声PCM样本.因此,您可以i通过查看包含的字节4*i来查找示例4*i+3.
要从两个字节解码单个16位值,请执行以下操作:
(MSB << 8) | LSB
Run Code Online (Sandbox Code Playgroud)
因为你读的缓冲值存储为签署的字符,你必须要小心一点,因为双方MSB并LSB会被符号扩展.这对LSB来说是不可取的; 因此,代码使用
0xff & (int)LSB
Run Code Online (Sandbox Code Playgroud)
获得低字节的无符号版本(从技术上讲,这可以通过向上转换为int,并选择低8位;另一种方法是仅写入(uint8_t)LSB).
注意,MSB位于索引1和3,LSB位于索引0和2处.因此,
((readbuffer[i*4+1]<<8) | (0x00ff&(int)readbuffer[i*4]))
Run Code Online (Sandbox Code Playgroud)
和
((readbuffer[i*4+3]<<8) | (0x00ff&(int)readbuffer[i*4+2]))
Run Code Online (Sandbox Code Playgroud)
通过使用一些位操作将字节组合成数字,只是将左右通道的值作为16位有符号值获取.
然后,将这些值中的每一个除以32768.0.请注意,带符号的16位值的范围为[-32768, 32767].因此,除以32768得到大约[-1,1]的范围.将两个除以的值相加以得到[-2,2]范围内的数字,然后将整数乘以0.5以获得平均值(范围[-1,1]中的浮点值).
| 归档时间: |
|
| 查看次数: |
2048 次 |
| 最近记录: |