ADPCM(Adaptive Differential Pulse Code Modulation),是针对16bits(或8bits)声音数据数据的一种有损压缩算法,声音流中每次采样的16bit数据以4bit 存储所以,压缩比 1:4。另外压缩/解压缩非常简单,所以是一种低消耗,高效率声音获得的好方法。保存声音的数据文件后缀名为.AUD的大多数ADPCM压缩算法。ADPCM
主要是针对连续的。
8bits的声音人耳是可以勉强了解的,因为它的编码和解码的过程很简单,列在我们身边,相信大家能够了解。ADPCM算法可以将每次采样得到的16bit数据压缩到4bit。需要注意的是,要压缩/解压缩得到声音信号,时,信号是放在一起的,需要将两个声道分别处理。
ADPCM过程压缩
首先我们认为声音信号都是从零开始的,那么需要初始化两个变量
INT索引= 0,prev_sample = 0;
下面的循环将包括处理声音数据流,注意其中的getnextsample()应该得到一个16bit的数据,而outputdata()可以计算出来的数据保存起来,程序中的step_table[],index_adjust[]附在后面:
int index=0,prev_sample:=0;
while (还有数据要处理)
{
cur_sample=getnextsample(); // 得到当前的采样数据
delta=cur_sample-prev_sample; // 计算出和上一个的增量
if (delta《0) delta=-delta,***=8; // 取绝对值
else *** = 0 ; // *** 保存是符号位
code = 4*delta / step_table[index]; // 根据 steptable[] 得到一个 0-7 的值
if (code》7) code=7; //它描述了声音强度的变化量
指数 += index_adjust[code] ; //根据声音强度调整下一步取steptable的顺序
if (index《0) index=0; // 容易下一个得到更合适的变化量的描述
else if (index》88) index=88;
prev_sample=cur_sample;
输出(代码| ***);// 加上符号位保存起来
}
ADPCM解压缩过程
接压缩实际是压缩的一个逆过程,同样的,其中的 getnextcode() 应该得到一个编码,,而 outputsample() 可以将解码出来的声音信号保存起来。这种代码同样使用了同一个的 setp_table[] 和 index_adjust () 附在后面:
int index=0,cur_sample=0;
while (还有数据要处理)
{
code=getnextcode(); // 得到下一个数据
if ((code & 8) != 0) ***=1 else ***=0;
代码&=7; // 将代码分离为数据和符号
delta = (step_table[index]*code)/4+step_table[index]/8; //一个加的珍珠是为了减少负
if (***==1) delta=-delta;
cur_sample+=delta; // 计算出当前的数据
》32767) output_sample(32767);
否则 if (cur_sample《-32768) output_sample(-32768);
否则 output_sample(cur_sample);
index+=index_adjust[代码];
如果(指数《0)指数=0;
如果(指数》88)指数=88;
}
附 ADPCM压缩算法实现
/******************************************** *****************
版权所有 1992 年,荷兰阿姆斯特丹 Stichting Mathematisch Centrum
。
保留所有权利特此授予出于任何目的免费
使用、复制、修改和分发本软件及其
文档的许可,
前提是所有副本中
均出现上述版权声明,并且该版权声明和本许可声明均出现在
支持文档,以及 Stichting Mathematisch 的名字
未经事先明确的书面许可,不得将 Centrum 或 CWI 用于与软件分发有关的广告或宣传。
STICHTING MATHEMATISCH CENTRUM 不
承担与本软件有关的所有保证,包括对适销性和
适用性的所有默示保证,在
任何情况下,STICHTING MATHEMATISCH CENTRUM 均不对任何第三方或第三方
使用利润,无论是在
合同,疏忽诉讼或其他民事行为,所产生OUT
与使用或连接或性能本软件所引发的。
****************************************************** ****************/
/*
** Intel/DVI ADPCM 编码器/解码器。
**
** 该编码器的算法取自 IMA Compatability Project
**会议录,第 2 卷,第 2 期;1992 年 5 月。
**
** 1.2 版,92 年 12 月 18 日。
**
** 更改日志:
** - 修正了一个愚蠢的错误,其中增量计算为
** stepsize*code/4 而不是 stepsize*(code+0.5)/4。
** - 有一个逐一错误导致它
在蓝色月亮中选择** 错误的增量。
** - 已删除 NODIVMUL 定义。现在总是
使用移位、加法和减法来完成计算。事实证明,因为标准
** 是使用 shift/add/subtract 定义的,您需要一些修复代码
**(因为使用 shift/add/sub 的 div/mul 模拟产生了一些
真正的 div/mul 不会产生的舍入** 错误),并且所有结果代码
** 运行速度比一直使用 shift 慢。
** - 更改了一些变量名称以使其更有意义。
*/
#include “adpcm.h”
#include /*DBG*/
#ifndef __STDC__
#define signed
#endif
/* Intel ADPCM 阶跃变化表 */
static int indexTable[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
static int stepsizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307
, 3,4,4,4, 4 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 4, 4, 5, 30, 4, 5, 30, 4, 30, 30
5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,
15289,16818,18500,20350,22385,24623,27086,29794,32767
};
void
adpcm_coder(indata, outdata, len, state)
短输入数据[];
字符输出数据[];
内里;
struct adpcm_state *state;
{
短 *输入; /* 输入缓冲区指针 */ 有
符号字符 *outp; /* 输出缓冲区指针 */
内部值;/* 当前输入样本值 */
int sign; /* 当前 adpcm 符号位 */
int delta; /* 当前 adpcm 输出值 */
int diff; /* val 和 valprev 的区别 */
int step; /* 步长 */
int valpred; /* 预测输出值 */
int vpdiff; /* 当前对 valpred 的更改 */
int index; /* 当前步长变化索引 */
int outputbuffer; /* 保留前 4 位值的位置 */
int bufferstep; /* 在输出缓冲区/输出之间切换 */
outp = (signed char *)outdata;
inp = 数据;
valpred = 状态-》 valprev;
索引 = 状态-》 索引;
step = stepsizeTable[index];
缓冲步 = 1;
for ( ; len 》 0 ; len-- ) {
val = * inp ++;
/* 第 1 步 - 计算与先前值的
差异*/ diff = val - valpred;
符号 = (差异 《 0) ? 8 : 0;
如果(符号)差异=(-差异);
/* 第 2 步 - 划分和钳位 */
/* 注意:
** 此代码 *近似* 计算:
** delta = diff*4/step;
** vpdiff = (delta+0.5)*step/4;
** 但在移位步骤中位被丢弃。这样做的最终结果是
** 即使你有快速的 mul/div 硬件,你也不能
很好地利用它,因为修复太昂贵了。
*/
增量 = 0;
vpdiff = (步骤》》 3);
如果(差异》 = 步){
delta = 4;
差异 -= 步骤;
vpdiff += 步;
}
步 》》= 1;
if ( diff 》= step ) {
delta |= 2;
差异 -= 步骤;
vpdiff += 步;
}
步 》》= 1;
if ( diff 》= step ) {
delta |= 1;
vpdiff += 步;
}
/* 第 3 步 - 更新前一个值 */
if ( sign )
valpred -= vpdiff;
否则
valpred += vpdiff;
/* 第 4 步 - 将前一个值限制为 16 位 */
if ( valpred 》 32767 )
valpred = 32767;
否则如果 ( valpred 《 -32768 )
valpred = -32768;
/* 第 5 步 - 组合值,更新索引和步长值 */
delta |= sign;
index += indexTable[delta];
如果(索引 《 0)索引 = 0;
如果(指数》 88)指数= 88;
step = stepsizeTable[index];
/* 第 6 步 - 输出值 */
if ( bufferstep ) {
outputbuffer = (delta 《《 4) & 0xf0;
} else {
*outp++ = (delta & 0x0f) | 输出缓冲区;
}
bufferstep = !bufferstep;
}
/* 输出最后一步,如果需要 */
if ( !bufferstep )
*outp++ = outputbuffer;
状态-》 valprev = valpred;
状态-》索引=索引;
}
void
adpcm_decoder(indata, outdata, len, state)
char indata[];
短输出数据[];
内里;
struct adpcm_state *state;
{
签名字符 *inp; /* 输入缓冲区指针 */
short *outp; /* 输出缓冲区指针 */
int 符号;/* 当前 adpcm 符号位 */
int delta; /* 当前 adpcm 输出值 */
int step; /* 步长 */
int valpred; /* 预测值 */
int vpdiff; /* 当前对 valpred 的更改 */
int index; /* 当前步长变化索引 */
int inputbuffer; /* 放置下一个 4 位值 */
int bufferstep; /* 在输入
缓冲区/输入之间切换 */ outp = outdata;
inp = (signed char *)indata;
valpred = 状态-》 valprev;
索引 = 状态-》 索引;
step = stepsizeTable[index];
缓冲步 = 0;
for ( ; len 》 0 ; len-- ) {
/* Step 1 - 获取增量值 */
if ( bufferstep ) {
delta = inputbuffer & 0xf;
} else {
inputbuffer = *inp++;
delta = (inputbuffer 》》 4) & 0xf;
}
bufferstep = !bufferstep;
/* 第 2 步 - 查找新的索引值(稍后)*/
index += indexTable[delta];
如果(索引 《 0)索引 = 0;
如果(指数》 88)指数= 88;
/* 第 3 步 - 分离符号和幅度 */
sign = delta & 8;
delta = delta & 7;
/* 第 4 步 - 计算差异和新预测值 */
/*
** 计算 ‘vpdiff = (delta+0.5)*step/4’,但请参阅 adpcm_coder 中的注释
**。
*/
vpdiff = 步骤 》》 3;
if (delta & 4) vpdiff += step;
if ( delta & 2 ) vpdiff += step》》1;
if ( delta & 1 ) vpdiff += step》》2;
如果(符号)
valpred -= vpdiff;
否则
valpred += vpdiff;
/* 第 5 步 - 钳制输出值 */
if ( valpred 》 32767 )
valpred = 32767;
否则如果 ( valpred 《 -32768 )
valpred = -32768;
/* 第 6 步 - 更新步长值 */
step = stepsizeTable[index];
/* 第 7 步 - 输出值 */
*outp++ = valpred;
状态-
》 valprev = valpred;
状态-》索引=索引;
}。
ADPCM(Adaptive Differential Pulse Code Modulation),是针对16bits(或8bits)声音数据数据的一种有损压缩算法,声音流中每次采样的16bit数据以4bit 存储所以,压缩比 1:4。另外压缩/解压缩非常简单,所以是一种低消耗,高效率声音获得的好方法。保存声音的数据文件后缀名为.AUD的大多数ADPCM压缩算法。ADPCM
主要是针对连续的。
8bits的声音人耳是可以勉强了解的,因为它的编码和解码的过程很简单,列在我们身边,相信大家能够了解。ADPCM算法可以将每次采样得到的16bit数据压缩到4bit。需要注意的是,要压缩/解压缩得到声音信号,时,信号是放在一起的,需要将两个声道分别处理。
ADPCM过程压缩
首先我们认为声音信号都是从零开始的,那么需要初始化两个变量
INT索引= 0,prev_sample = 0;
下面的循环将包括处理声音数据流,注意其中的getnextsample()应该得到一个16bit的数据,而outputdata()可以计算出来的数据保存起来,程序中的step_table[],index_adjust[]附在后面:
int index=0,prev_sample:=0;
while (还有数据要处理)
{
cur_sample=getnextsample(); // 得到当前的采样数据
delta=cur_sample-prev_sample; // 计算出和上一个的增量
if (delta《0) delta=-delta,***=8; // 取绝对值
else *** = 0 ; // *** 保存是符号位
code = 4*delta / step_table[index]; // 根据 steptable[] 得到一个 0-7 的值
if (code》7) code=7; //它描述了声音强度的变化量
指数 += index_adjust[code] ; //根据声音强度调整下一步取steptable的顺序
if (index《0) index=0; // 容易下一个得到更合适的变化量的描述
else if (index》88) index=88;
prev_sample=cur_sample;
输出(代码| ***);// 加上符号位保存起来
}
ADPCM解压缩过程
接压缩实际是压缩的一个逆过程,同样的,其中的 getnextcode() 应该得到一个编码,,而 outputsample() 可以将解码出来的声音信号保存起来。这种代码同样使用了同一个的 setp_table[] 和 index_adjust () 附在后面:
int index=0,cur_sample=0;
while (还有数据要处理)
{
code=getnextcode(); // 得到下一个数据
if ((code & 8) != 0) ***=1 else ***=0;
代码&=7; // 将代码分离为数据和符号
delta = (step_table[index]*code)/4+step_table[index]/8; //一个加的珍珠是为了减少负
if (***==1) delta=-delta;
cur_sample+=delta; // 计算出当前的数据
》32767) output_sample(32767);
否则 if (cur_sample《-32768) output_sample(-32768);
否则 output_sample(cur_sample);
index+=index_adjust[代码];
如果(指数《0)指数=0;
如果(指数》88)指数=88;
}
附 ADPCM压缩算法实现
/******************************************** *****************
版权所有 1992 年,荷兰阿姆斯特丹 Stichting Mathematisch Centrum
。
保留所有权利特此授予出于任何目的免费
使用、复制、修改和分发本软件及其
文档的许可,
前提是所有副本中
均出现上述版权声明,并且该版权声明和本许可声明均出现在
支持文档,以及 Stichting Mathematisch 的名字
未经事先明确的书面许可,不得将 Centrum 或 CWI 用于与软件分发有关的广告或宣传。
STICHTING MATHEMATISCH CENTRUM 不
承担与本软件有关的所有保证,包括对适销性和
适用性的所有默示保证,在
任何情况下,STICHTING MATHEMATISCH CENTRUM 均不对任何第三方或第三方
使用利润,无论是在
合同,疏忽诉讼或其他民事行为,所产生OUT
与使用或连接或性能本软件所引发的。
****************************************************** ****************/
/*
** Intel/DVI ADPCM 编码器/解码器。
**
** 该编码器的算法取自 IMA Compatability Project
**会议录,第 2 卷,第 2 期;1992 年 5 月。
**
** 1.2 版,92 年 12 月 18 日。
**
** 更改日志:
** - 修正了一个愚蠢的错误,其中增量计算为
** stepsize*code/4 而不是 stepsize*(code+0.5)/4。
** - 有一个逐一错误导致它
在蓝色月亮中选择** 错误的增量。
** - 已删除 NODIVMUL 定义。现在总是
使用移位、加法和减法来完成计算。事实证明,因为标准
** 是使用 shift/add/subtract 定义的,您需要一些修复代码
**(因为使用 shift/add/sub 的 div/mul 模拟产生了一些
真正的 div/mul 不会产生的舍入** 错误),并且所有结果代码
** 运行速度比一直使用 shift 慢。
** - 更改了一些变量名称以使其更有意义。
*/
#include “adpcm.h”
#include /*DBG*/
#ifndef __STDC__
#define signed
#endif
/* Intel ADPCM 阶跃变化表 */
static int indexTable[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
static int stepsizeTable[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307
, 3,4,4,4, 4 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 4, 4, 5, 30, 4, 5, 30, 4, 30, 30
5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,
15289,16818,18500,20350,22385,24623,27086,29794,32767
};
void
adpcm_coder(indata, outdata, len, state)
短输入数据[];
字符输出数据[];
内里;
struct adpcm_state *state;
{
短 *输入; /* 输入缓冲区指针 */ 有
符号字符 *outp; /* 输出缓冲区指针 */
内部值;/* 当前输入样本值 */
int sign; /* 当前 adpcm 符号位 */
int delta; /* 当前 adpcm 输出值 */
int diff; /* val 和 valprev 的区别 */
int step; /* 步长 */
int valpred; /* 预测输出值 */
int vpdiff; /* 当前对 valpred 的更改 */
int index; /* 当前步长变化索引 */
int outputbuffer; /* 保留前 4 位值的位置 */
int bufferstep; /* 在输出缓冲区/输出之间切换 */
outp = (signed char *)outdata;
inp = 数据;
valpred = 状态-》 valprev;
索引 = 状态-》 索引;
step = stepsizeTable[index];
缓冲步 = 1;
for ( ; len 》 0 ; len-- ) {
val = * inp ++;
/* 第 1 步 - 计算与先前值的
差异*/ diff = val - valpred;
符号 = (差异 《 0) ? 8 : 0;
如果(符号)差异=(-差异);
/* 第 2 步 - 划分和钳位 */
/* 注意:
** 此代码 *近似* 计算:
** delta = diff*4/step;
** vpdiff = (delta+0.5)*step/4;
** 但在移位步骤中位被丢弃。这样做的最终结果是
** 即使你有快速的 mul/div 硬件,你也不能
很好地利用它,因为修复太昂贵了。
*/
增量 = 0;
vpdiff = (步骤》》 3);
如果(差异》 = 步){
delta = 4;
差异 -= 步骤;
vpdiff += 步;
}
步 》》= 1;
if ( diff 》= step ) {
delta |= 2;
差异 -= 步骤;
vpdiff += 步;
}
步 》》= 1;
if ( diff 》= step ) {
delta |= 1;
vpdiff += 步;
}
/* 第 3 步 - 更新前一个值 */
if ( sign )
valpred -= vpdiff;
否则
valpred += vpdiff;
/* 第 4 步 - 将前一个值限制为 16 位 */
if ( valpred 》 32767 )
valpred = 32767;
否则如果 ( valpred 《 -32768 )
valpred = -32768;
/* 第 5 步 - 组合值,更新索引和步长值 */
delta |= sign;
index += indexTable[delta];
如果(索引 《 0)索引 = 0;
如果(指数》 88)指数= 88;
step = stepsizeTable[index];
/* 第 6 步 - 输出值 */
if ( bufferstep ) {
outputbuffer = (delta 《《 4) & 0xf0;
} else {
*outp++ = (delta & 0x0f) | 输出缓冲区;
}
bufferstep = !bufferstep;
}
/* 输出最后一步,如果需要 */
if ( !bufferstep )
*outp++ = outputbuffer;
状态-》 valprev = valpred;
状态-》索引=索引;
}
void
adpcm_decoder(indata, outdata, len, state)
char indata[];
短输出数据[];
内里;
struct adpcm_state *state;
{
签名字符 *inp; /* 输入缓冲区指针 */
short *outp; /* 输出缓冲区指针 */
int 符号;/* 当前 adpcm 符号位 */
int delta; /* 当前 adpcm 输出值 */
int step; /* 步长 */
int valpred; /* 预测值 */
int vpdiff; /* 当前对 valpred 的更改 */
int index; /* 当前步长变化索引 */
int inputbuffer; /* 放置下一个 4 位值 */
int bufferstep; /* 在输入
缓冲区/输入之间切换 */ outp = outdata;
inp = (signed char *)indata;
valpred = 状态-》 valprev;
索引 = 状态-》 索引;
step = stepsizeTable[index];
缓冲步 = 0;
for ( ; len 》 0 ; len-- ) {
/* Step 1 - 获取增量值 */
if ( bufferstep ) {
delta = inputbuffer & 0xf;
} else {
inputbuffer = *inp++;
delta = (inputbuffer 》》 4) & 0xf;
}
bufferstep = !bufferstep;
/* 第 2 步 - 查找新的索引值(稍后)*/
index += indexTable[delta];
如果(索引 《 0)索引 = 0;
如果(指数》 88)指数= 88;
/* 第 3 步 - 分离符号和幅度 */
sign = delta & 8;
delta = delta & 7;
/* 第 4 步 - 计算差异和新预测值 */
/*
** 计算 ‘vpdiff = (delta+0.5)*step/4’,但请参阅 adpcm_coder 中的注释
**。
*/
vpdiff = 步骤 》》 3;
if (delta & 4) vpdiff += step;
if ( delta & 2 ) vpdiff += step》》1;
if ( delta & 1 ) vpdiff += step》》2;
如果(符号)
valpred -= vpdiff;
否则
valpred += vpdiff;
/* 第 5 步 - 钳制输出值 */
if ( valpred 》 32767 )
valpred = 32767;
否则如果 ( valpred 《 -32768 )
valpred = -32768;
/* 第 6 步 - 更新步长值 */
step = stepsizeTable[index];
/* 第 7 步 - 输出值 */
*outp++ = valpred;
状态-
》 valprev = valpred;
状态-》索引=索引;
}。
举报