一、简介
1 adpcm编码原理
编码步骤:
求出输入的pcm数据与预测的pcm数据(第一次为上一个pcm数据)的差值diff;
通过差分量化器算出delta(通过index(首次编码index为0)求出step,通过diff和step求出delta)。delta即为编码后的数据;
通过逆量化器求出vpdiff(通过求出的delta和step算出vpdiff);
求出新的预测valpred,即上次预测的valpred+vpdiff;
通过预测器(归一化),求出当前输入pcm input的预测pcm值,为下一次计算用;
量化阶调整(通过delta查表及index,计算出新的index值)。为下次计算用;
2 adpcm解码原理
解码步骤(其实解码原理就是编码的第三到六步):
通过逆量化器求出vpdiff(通过存储的delta和index,求出step,算出vpdiff);
求出新的预测valpred,即上次预测的valpred+vpdiff;
通过预测器(归一化),求出当前输入pcm input的预测pcm值,为下一次计算用。预测的pcm值即为解码后的数据;
量化阶调整(通过delta查表及index,计算出新的index值)。为下次计算用;
注释说明
通过编码和解码的原理我们可以看出其实第一次编码的时候已经进行了解码,即预测的pcm。
因为编码再解码后输出的数据已经被量化了。根据计算公式delta = diff*4/step;vpdiff = (delta+0.5)*step/4;考虑到都是整数运算,可以推导出:pcm数据经过编码再解码生成的预测pcm数据,如果预测pcm数据再次编码所得的数据与第一次编码所得的数据是相同的。故pcm数据经过一次编码有损后,不论后面经过几次解码再编码都是数据一样,音质不会再次损失。即相对于第一次编码后,以后数据不论多少次编解码,属于无损输出。
3 ADPCM数据存放形式
本部分为adpcm数据存放说明,属于细节部分,很多代码解码出来有噪音就是因为本部分细节不对,所以需要仔细阅读。
3.1 adpcm 数据块介绍
adpcm数据是一个block一个block存放的,block由block header (block头) 和data 两者组成的。其中block header是一个结构,它在单声道下的定义如下:
Typedef struct
{
short sample0; //block中第一个采样值(未压缩)
BYTE index; //上一个block最后一个index,第一个block的index=0;
BYTE reserved; //尚未使用
}MonoBlockHeader;
对于双声道,它的blockheader应该包含两个MonoBlockHeader其定义如下:
typedaf struct
{
MonoBlockHeader leftbher;
MonoBlockHeader rightbher;
}StereoBlockHeader;
在解压缩时,左右声道是分开处理的,所以必须有两个MonoBlockHeader;
有了blockheader的信息后,就可以不需要知道这个block前面数据而轻松地解出本block中的压缩数据。故adpcm解码只与本block有关,与其他block无关,可以只单个解任何一个block数据。
block的大小是固定的,可以自定义,每个block含的采样数nsamples计算如下:
//
#define BLKSIZE 1024
block = BLKSIZE * channels;
//block = BLKSIZE;//ffmpeg
nsamples = (block - 4 * channels) * 8 / (4 * channels) + 1;
例如audition软件就是采用上面的,单通路block为1024bytes,2041个samples,双通路block为2048,也是含有2041个sample。
而ffmpeg采用block =1024bytes,即不论单双通路都为1024bytes,通过公式可以算出单双通路的samples数分别为2041和1017;
3.2 单通路pcm格式:
3.3 双通路pcm格式:
3.4 编解码代码实现
需要特别留意双声道的处理和当数据不够1 block时的处理方式
代码包含了编码和解码测试用例,实现先编码再解码。欢迎交流学习
完整代码下载地址(本文只是详细说明了adpcm编解码,如果想wav文件编解码正确需要下载完整代码。
完整代码为0x0011 /* Intel’s DVI ADPCM */的编码解码代码实现。包括单双通路的处理和最后数据不是整块block的处理):
二、源代码
clear all;
clc
close all;
[x,fs,numbits]= wavread('C6_3_y.wav');
sign_bit=2; %两位ADPCM算法
ss=adpcm_encoder(x,sign_bit);
yy=adpcm_decoder(ss,sign_bit)';
nq=sum((x-yy).*(x-yy))/length(x);
sq=mean(yy.^2);
snr=(sq/nq);
t=(1:length(x))/fs;
subplot(211)
plot(t,x/max(abs(x)))
axis tight
title('(a)编码前语音')
xlabel('时间/s')
ylabel('幅度')
subplot(212)
plot(t,yy/max(abs(yy)))
axis tight
% APDCM解码函数
function y=adpcm_decoder(code,sign_bit)
len=length(code);
y = zeros(1,len);
ss2 = zeros(1,len);
ss2(1) = 1;
currentIndex =1;
index = [-1 4];
startval = 1;
endval = 127;
base = exp( log(2)/8 );
% 近似步长
const = startval/base;
numSteps = round( log(endval/const) / log(base) );
n = 1:numSteps;
base = exp( log(endval/startval) / (numSteps-1) );
const = startval/base;
table2 = round( const*base.^n );
for n = 2:len
% 计算量化距离
neg = code(n) >= sign_bit;
if (neg)
temp = code(n) - sign_bit;
else
temp = code(n);
end
temp2 = (temp+.5)*ss2(n-1);
if (neg)
temp2 = -temp2;
end
三、运行结果
四、备注
版本:2014a