1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
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; 状态-》索引=索引; }。 |
|
|
|
只有小组成员才能发言,加入小组>>
788 浏览 0 评论
1151 浏览 1 评论
2527 浏览 5 评论
2860 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2709 浏览 6 评论
keil5中manage run-time environment怎么是灰色,不可以操作吗?
1068浏览 3评论
193浏览 2评论
455浏览 2评论
368浏览 2评论
M0518 PWM的电压输出只有2V左右,没有3.3V是怎么回事?
453浏览 1评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 15:44 , Processed in 0.915359 second(s), Total 77, Slave 58 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号