WAV系列之一:G711编解码原理及代码实现

参考自:a-law原理及算法实现
    G711编码原理及代码

G711也称为PCM(脉冲编码调制),是国际电信联盟制定出来的一套语音压缩标准,主要用于电话。G711编码的声音清晰度好,语音自然度高,但压缩效率低,数据量大常在32Kbps以上(推荐使用64Kbps)。它主要用脉冲编码调制对音频采样,采样率为8KHz。它利用一个64Kbps未压缩通道传输语音讯号。其压缩率为1:2,即把16位数据压缩成8位。G.711是主流的波形声音编解码器。

G.711 标准下主要有两种压缩算法。一种是µ-law algorithm (又称often u-law, ulaw, mu-law),主要运用于北美和日本;另一种是a-law algorithm,主要运用于欧洲和世界其他地区。其中,后者是特别设计用来方便计算机处理的。这两种算法都使用一个采样率为8kHz的输入来创建64Kbps的数字输出。

1、a-law

a-law也叫g711a,输入的是13位(其实是S16的高13位),使用在欧洲和其他地区,这种格式是经过特别设计的,便于数字设备进行快速运算。在WAV文件中的识别标志是 WAVE_FORMAT_ALAW

目前最主要的用途是将13bit的数据转化成为8bit的数据,13bit的最高位是符号位,转化成为的8bit并不是线性的,而是每几位都有其意义。

  • 第7位: 代表符号位,1表示正数,0表示负数,这点和一般的计算机系统正好相反
  • 第4-6位: 这实际上是一个表示一种幂级数的位
  • 第0-3位: 是具体的量化数值

运算过程如下:

(1) 取符号位并取反得到s,

(2) 获取强度位eee,获取方法如图所示

(3) 获取高位样本位wxyz

(4) 组合为seeewxyz,将seeewxyz逢偶数位取反,编码完毕
在这里插入图片描述
示例:

输入pcm数据为3210,二进制对应为(0000 1100 1000 1010)

二进制变换下排列组合方式(0 0001 1001 0001010)

(1) 获取符号位最高位为0,取反,s=1

(2) 获取强度位0001,查表,编码制应该是eee=100

(3) 获取高位样本wxyz=1001

(4) 组合为11001001,逢偶数位取反为10011100

编码完毕。

编码代码如下:

#define MAX  (32635)   
void encode(unsigned char *dst, short *src, size_t len)
{
    
   for(int i = 0; i < len ; i++)
    {
   

 //      *dst++ =  *src++;
        short pcm  = *src++;
        int sign = (pcm & 0x8000) >> 8;
        if(sign != 0)
            pcm = -pcm;
        if(pcm > MAX)   pcm = MAX;
        int exponent = 7;
        int expMask;
        for(expMask = 0x4000; (pcm & expMask) == 0 && exponent >0; exponent--,expMask >>= 1){
   }
        int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;
        unsigned char alaw = (unsigned char)(sign | exponent << 4 | mantissa);
        *dst++ = (unsigned char)(alaw ^0xD5);   
    }     
} 

译码代码如下:


void decode(short *dst, unsigned char *src, size_t len)
{
   
    for(size_t i=0; i < len  ; i++)
    {
   
        unsigned char alaw = *src++;
        alaw ^= 0xD5;
        int sign = alaw & 0x80;
        int exponent = (alaw & 0x70) >> 4;
        int data = alaw & 0x0f;
        data <<= 4;
        data += 8;   //丢失的a 写1
        if(exponent != 0)  //将wxyz前面的1补上
            data += 0x100;
        if(exponent > 1)
            data <<= (exponent - 1);

        *dst++ = (short)(sign == 0 ? data : -data);

    }
}
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值