ADPCM算法
本文最后更新于:2023年6月29日 晚上
简介
ADPCM(Adaptive Differential Pulse Code Modulation, 自适应差分脉冲编码调制) 是一种音频信号数字化编码技术, 音频压缩标准 G.722, G.723, G.726 中都会使用到 ADPCM
预备知识
PCM-脉冲编码调制-Pulse Code Modulation
音频输入为 16bit 的有符号整数
假设输入样本分别为
- 1024,1000,980,970,970,980,1000,1010,1024,1030,1020,1010
那么存储时需要开辟 12*16bit = 192bit,需要大量的空间
为了减少存储开销,Differential Pulse Code Modulation, 差分脉冲编码调制被提出
DPCM-差分脉冲编码调制-Differential Pulse Code Modulation
利用声波的连续性,一般来说,相邻采样值的差值较小,可以用较小的位数来存储
可将![[ADPCM算法#^c764ad]]进行差分运算,上述可编码为
- 1024,-24,-20,-10,0,10,20,10,14,6,-10,-10
若求原来的采样值,只需(需要注意的是,DPCM 编码是无损的,也就是可以复原成原来的采样值)
大部分情况下,只需要 4bit 来表示,但是存在一些情况,比如无法用 4bit 的数值表示,于是 ADPCM 被提出
正课
ADPCM-自适应差分脉冲编码调制-Adaptive Differential Pulse Code Modulation
(本文以 IMA-ADPCM 算法实现进行说明)
主要思想
- 利用量化差分值(diffq)取代原有差分值(diff)进行差分运算
何为量化差分值?
量化差分值
由 DPCM 可以看出,差分值具有很大的范围,可以取遍范围内的任何一个整数,无法用 4bit 的值来表示
而 ADPCM 的量化差分值是用 4bit 的 ADPCM 代码code与一个可变的步长step来表示,假定 step 可在中取若干个数,构成一个 StepTable
现不加说明的给定 code(4bit)各位的含义
- a 代表符号,也就是正负
- b 是 1 时,代表 1 倍的 step 步长值
- c 是 1 时,代表 0.5 倍的 step 步长值
- d 是 1 时,代表 0.25 倍的 step 步长值
举个例子:
,代表 code 是正数,对应的步长值
,代表 code 是负数,对应的步长值
而量化差分值的计算方法是
(注:1/8 的步长值是 IMA ADPCM 算法规定的,不同实现算法这部分不同)
这么计算之后,diffq 也可以取遍的很大一部分数值,同时 diffq 只需要 4bit 的值与一个 step 值便可以计算出来,与 diff 的 16bit 相比,减小了很大的存储空间
现在回顾主要思想
利用量化差分值(diffq)取代原有差分值(diff)进行差分运算
既然要取代,我们就应该尽可能在当前的 step 下,尽可能的让 diffq 接近 diff 值
如何实现呢?
让 diffq 接近 diff
首先,diffq 应该要与 diff 有相同的符号,也就是说,,那么 code 的第一位()应该是 0,否则是 1
在当前 step 下,如果 diff 值大于一倍步长,那么为了让 diffq 尽可能靠近 diff,那么 diffq 值也应该大于一倍步长,根据 diffq 的计算方式,那么 code 的第二位()应该是 1,否则 code 的第二位是 0
接下来将 diff 减去当前 step 值,如果这时候 diff 大于 0.5 倍步长,那么同理 code 的第三位()应该是 1,否则是 0
接下来将 diff 减去 0.5 倍 step 值,如果这时候 diff 大于 0.25 倍步长,那么同理 code 的第四位()应该是 1,否则是 0
这样,我们就得到了在当前 step 下最接近 diff 值的 diffq 的值,同时求出了 code 值
一个问题:
这样计算出来的 diffq 的绝对值的范围大致在 2 倍 step 范围内,假如此时的 diff 的绝对值远大于 step 值,要怎么办?
这就对每次选取的 step 值有着一定的要求
step 步长的选定
我们可以进行大胆的假定,假如这次的 diff 值远大于步长值,那么下一个采样值的 diff 值应该也是远大于这次的步长值,那么为了减小误差,我们就应该让下一次的步长值扩大 ^ce108a
我们定义一个 index 值,用于选取 step 值
其中 index 与 code 与 step 的关系应该满足:
- 当 index 变大的时候,step 对应变大;index 变小的时候,step 对应变小
- 当 code 大于 4 或者小于-4 的时候,也就是 diff 的绝对值大于 1 倍步长的时候,index 应该变大,这样可以使 step 变大
总结一下,index 受到 code 的影响,而 step 受到 index 的影响
我们观察 IMA-ADPCM 给定的 index 和 step 表(注意 IMA-ADPCM 中 index 是 8bit 整数)
1 |
|
step 表随着下标的增加而增加
index 表在 code 为 0~3 与-3~0 的时候为 0xff,其余为 2,4,6,8
我们令
index = index + IndexTable[code]
step = StepTable[index]
code 为 0~3 与-3~0 时,,由于 index 是 8bit 数据,必然会溢出,溢出之后得到的数据相当于 index-1,此时对应的 step 值变小
code 大于 4 或者小于-4 时,index 加上了一个大于 0 的数,使 index 变大,此时对应的 step 值变大,符合要求
注意,这些 step 与 index 是在当前采样值下计算的,是在下一次的采样值下使用的
现在 step 也解决了,也编码完了,如何解码呢
解码
同 DPCM 原理一样,通过计算量化差分值的和,得到解码数据
不过,此时得到的数据与原数据是有差异的,故而 ADPCM 是有损压缩
代码实现
1 |
|