微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > ADPCM音频压缩

ADPCM音频压缩

时间:10-02 整理:3721RD 点击:
ADPCM音频压缩

象棋小子          1048272975

音频数据通常需要占用大量的储存空间,或者在传输时占用大量的信道带宽。可以通过特定的压缩算法压缩这些音频数据,从而减少在储存、传输时的音频数据量。ADPCM就是这样一种针对音频的压缩算法。

1. ADPCM概述

ADPCM(adaptive differential pulse code modulation),自适应差分脉冲编码调制,是一种固定码长的音频编解码器。通常,两个连续的音频样本之间具有较高的相关性,可以用先前的样本值去估算当前样本的预测值,使实际样本值与预测值之间的差值达到最小。相对于直接表达PCM值,这意味着可以使用较少的比特来表达这种差值。而ADPCM就是通过编码当前样本与预测结果之间的差异,减少音频之间的冗余信息,实现音频的压缩。

ADPCM是一种有损压缩算法,根据不同的音频质量、压缩比需求,ADPCM对音频样本之间的差值可以量化成4级(2比特)、8级(3比特)、16级(4比特)或者32级(5比特)。目前有很多ADPCM算法的实现,不同的算法区别于不同的量化等级以及预测模式,如用于电话系统的ITU-T G.726就是基于ADPCM算法。总的来说,ADPCM是基于时间域波形的编码,相对基于频域的音频编解码器来说,其算法复杂度要简单的多,是一种简单、有效、低成本的音频编解码器方案。

有一种广泛使用的ADPCM算法IMA-ADPCM,这个编解码器可以应用于不同的计算机平台,微软开发的WAV声音文件格式就支持IMA-ADPCM的编码。它是一个四位量化算法,由Interactive Multimedia Association (IMA)开发。通过查表定点预测替换掉复杂的浮点数学运算,极大地降低了算法的复杂度。因此,IMA-ADPCM的主要优点在于它的简单性,适用于各种音频信号,支持任意的音频采样率,较高的压缩率(1:4),并且具有良好的音频质量。

2. IMA-ADPCM编码

IMA-ADPCM编码把一个16位PCM采样值压缩成一个4位ADPCM编码值,压缩比为1:4。编码的实现如下:

/* Quantizer step size lookup table */

static const uint16_tStepSizeTable[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,

                            337,371,408,449,494,544,598,658,724,796,

                           876,963,1060,1166,1282,1411,1552,1707,1878,2066,

                           2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,

                           5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,

                           15289,16818,18500,20350,22385,24623,27086,29794,32767};

/* Table of index changes */

static const int8_tIndexTable[16]={0xff,0xff,0xff,0xff,2,4,6,8,0xff,0xff,0xff,0xff,2,4,6,8};

/**

* @Brief  ADPCM_Encode.

* @param sample: a 16-bit PCM sample

* @retval : a 4-bit ADPCM sample

*/

uint8_t ADPCM_Encode(int32_t sample)

{

static int16_t  index = 0;

static int32_t predsample = 0;

uint8_t code=0;

uint16_t tmpstep=0;

int32_t diff=0;

int32_t diffq=0;

uint16_t step=0;

  

step = StepSizeTable[index];

/* 2. compute diff and record sign and absolut value */

diff = sample-predsample;

if (diff < 0)  

{

   code=8;

   diff = -diff;

}   

  

/* 3. quantize the diff into ADPCM code */

/* 4. inverse quantize the code into a predicted diff */

tmpstep = step;

diffq = (step >> 3);

if (diff >= tmpstep)

{

   code |= 0x04;

   diff -= tmpstep;

   diffq += step;

}

  

tmpstep = tmpstep >> 1;

if (diff >= tmpstep)

{

   code |= 0x02;

   diff -= tmpstep;

   diffq+=(step >> 1);

}

  

tmpstep = tmpstep >> 1;

  

if (diff >= tmpstep)

{

   code |=0x01;

   diffq+=(step >> 2);

}

  

/* 5. fixed predictor to get new predicted sample*/

if (code & 8)

{

   predsample -= diffq;

}

else

{

   predsample += diffq;

}  

/* check for overflow*/

if (predsample > 32767)

{

   predsample = 32767;

}

else if (predsample < -32768)

{

   predsample = -32768;

}

  

/* 6. find new stepsize index */

index += IndexTable[code];

/* check for overflow*/

if (index <0)

{

   index = 0;

}

else if (index > 88)

{

   index = 88;

}

  

/* 8. return new ADPCM code*/

return (code & 0x0f);

}

3. IMA-ADPCM解码

IMA-ADPCM解码把一个4位ADPCM编码值解压成一个16位PCM值,解码的实现如下:

/**

* @brief  ADPCM_Decode.

* @param code: a byte containing a 4-bit ADPCM sample.

* @retval : 16-bit ADPCM sample

*/

int16_t ADPCM_Decode(uint8_t code)

{

static int16_t  index = 0;

static int32_t predsample = 0;

uint16_t step=0;

int32_t diffq=0;

  

step = StepSizeTable[index];

/* 2. inverse code into diff */

diffq = step>> 3;

if (code&4)

{

   diffq += step;

}

  

if (code&2)

{

   diffq += step>>1;

}

  

if (code&1)

{

   diffq += step>>2;

}

/* 3. add diff to predicted sample*/

if (code&8)

{

   predsample -= diffq;

}

else

{

   predsample += diffq;

}

  

/* check for overflow*/

if (predsample > 32767)

{

   predsample = 32767;

}

else if (predsample < -32768)

{

   predsample = -32768;

}

/* 4. find new quantizer step size */

index += IndexTable [code];

/* check for overflow*/

if (index < 0)

{

   index = 0;

}

if (index > 88)

{

   index = 88;

}

  

/* 5. save predict sample and index for next iteration */

/* done! static variables */

  

/* 6. return new speech sample*/

return ((int16_t)predsample);

}

4. 应用例程

main函数例程实现从数字麦克风获取音频缓存并ADPCM编码这一帧缓存,形成编码帧,再经过ADPCM解码,解码帧输出到音频输出缓存,放出声音,实现声音的回放。

通常音频的编解码都是以固定长度的音频数据为帧单位,ADPCM编码一帧的函数实现如下:

void Adpcm_FrameEncode(const int16_t*PCMBuffer, void *EncodeBuffer, int32_t Len)

{

       int32_ti;

       uint8_tHighBits;

       uint8_tCode;

       uint8_t*pCode;

      

       HighBits= 0;

       pCode= (uint8_t *)EncodeBuffer;

       for(i=0; i<Len; i++) {

              Code= ADPCM_Encode(PCMBuffer);

              if(HighBits) {

                     *pCode|= Code << 4;

                     pCode++;

                     HighBits= 0;

              }else {

                     *pCode= Code;

                     HighBits= 1;

              }

       }

}

ADPCM解码一帧的函数实现如下:

void Adpcm_FrameDecode(int16_t*PCMBuffer, const void *EncodeBuffer, int32_t Len)

{

       int32_ti;

       uint8_tHighBits;

       uint8_tCode;

       constuint8_t *pCode;

      

       HighBits= 0;

       pCode= EncodeBuffer;

       for(i=0; i<Len; i++) {

              if(HighBits) {

                     Code= *pCode >> 4;

                     pCode++;

                     HighBits= 0;

              }else {

                     Code= *pCode & 0xf;

                     HighBits= 1;

              }

              PCMBuffer= ADPCM_Decode(Code);

       }     

}

main函数中声音先编码,再解码回放的实现如下:

while (1) {

if (DmicState.Event) {

       Adpcm_FrameEncode((int16_t*)DmicState.Buffer[DmicState.ReadIndex],

EncodeBuffer, AUDIO_FRAME_SIZE);

       if(DmicState.ReadIndex >= AUDIO_NUM_BUFFERS-1) {

              DmicState.ReadIndex= 0;

       }else {

              DmicState.ReadIndex++;

       }

                     

       Adpcm_FrameDecode(PCMBuffer,EncodeBuffer, AUDIO_FRAME_SIZE);

       for(i=0; i<AUDIO_FRAME_SIZE; i++) {

              I2SState.TxBuffer[I2SState.TxWriteIndex]= PCMBuffer;

       }

       if(I2SState.TxWriteIndex >= AUDIO_NUM_BUFFERS-1) {

              I2SState.TxWriteIndex= 0;

       }else {

              I2SState.TxWriteIndex++;

       }

       DmicState.Event= 0;

}

}

5. 附录

附件为ADPCM音频压缩的MDK工程,相应的文档。

http://pan.baidu.com/s/1eS0BUQe


Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top