最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

ADPCM压缩算法

来源:动视网 责编:小OO 时间:2025-09-25 03:15:47
文档

ADPCM压缩算法

ADPCM压缩算法ADPCM(AdaptiveDifferentialPulseCodeModulation),是一种针对16bits(或8bits或者更高)声音波形数据的一种有损压缩算法,它将声音流中每次采样的16bit数据以4bit存储,所以压缩比1:4.而且压缩/解压缩算法非常简单,所以是一种低空间消耗,高质量高效率声音获得的好途径。保存声音的数据文件后缀名为.AUD的大多用ADPCM压缩。ADPCM主要是针对连续的波形数据的,保存的是波形的变化情况,以达到描述整个波形的目的,由于它的编
推荐度:
导读ADPCM压缩算法ADPCM(AdaptiveDifferentialPulseCodeModulation),是一种针对16bits(或8bits或者更高)声音波形数据的一种有损压缩算法,它将声音流中每次采样的16bit数据以4bit存储,所以压缩比1:4.而且压缩/解压缩算法非常简单,所以是一种低空间消耗,高质量高效率声音获得的好途径。保存声音的数据文件后缀名为.AUD的大多用ADPCM压缩。ADPCM主要是针对连续的波形数据的,保存的是波形的变化情况,以达到描述整个波形的目的,由于它的编
ADPCM压缩算法

 ADPCM(Adaptive Differential Pulse Code Modulation),是一种针对 16bits( 或8bits或者更高) 声音波形数据的一种有损压缩算法,它将声音流中每次采样的 16bit 数据以 4bit 存储,所以压缩比 1:4. 而且压缩/解压缩算法非常简单,所以是一种低空间消耗,高质量高效率声音获得的好途径。保存声音的数据文件后缀名为 .AUD 的大多用ADPCM 压缩。

  ADPCM 主要是针对连续的波形数据的,保存的是波形的变化情况,以达到描述整个波形的目的,由于它的编码和解码的过程却很简洁,列在后面,相信大家能够看懂。

  8bits采样的声音人耳是可以勉强接受的,而 16bit 采样的声音可以算是高音质了。ADPCM 算法却可以将每次采样得到的 16bit 数据压缩到 4bit 。需要注意的是,如果要压缩/解压缩得是立体声信号,采样时,声音信号是放在一起的,需要将两个声道分别处理。

ADPCM 压缩过程    

  首先我们认为声音信号都是从零开始的,那么需要初始化两个变量 

    int index=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,sb=8;      // 取绝对值

      else sb = 0 ;               // sb 保存的是符号位

      code = 4*delta / step_table[index];  (取余运算)  // 根据 steptable[]得到一个 0-7 的值

      if (code>7) code=7;            // 它描述了声音强度的变化量

      index += index_adjust[code] ;       // 根据声音强度调整下次取steptable 的序号

      if (index<0) index=0;           // 便于下次得到更精确的变化量的描述

      else if (index>88) index=88;

      prev_sample=cur_sample;

      outputode(code|sb);            // 加上符号位保存起来

    }

 

ADPCM 解压缩过程 

  接压缩实际是压缩的一个逆过程,同样其中的 getnextcode() 应该得到一个编码,,而 outputsample() 可以将解码出来的声音信号保存起来。这段代码同样使用了同一个的 setp_table[] 和 index_adjust() 附在后面:

    int index=0,cur_sample=0;

    while (还有数据要处理) 

    {

        code=getnextcode();                       // 得到下一个数据

        if ((code & 8) != 0) sb=1 else sb=0;

        code&=7;                            // 将 code 分离为数据和符号

        delta = (step_table[index]*code)/4+step_table[index]/8;     // 后面加的一项是为了减少误差

        if (sb==1) delta=-delta;

        cur_sample+=delta;                        // 计算出当前的波形数据

        if (cur_sample>32767) output_sample(32767);

        else if (cur_sample<-32768) output_sample(-32768);

        else output_sample(cur_sample);

        index+=index_adjust[code];

        if (index<0) index=0;

        if (index>88) index=88;

     }

附表 

     int index_adjust[8] = {-1,-1,-1,-1,2,4,6,8};

     int step_table[] = { 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,54,84,7132,7845,8630,9493,10442,11487,12635,139,

152,16818,18500,20350,22385,24623,27086,29794,32767 }

TCPMP原代码赏析

/*****************************************************************************

 *

 * This program is free software ; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License as published by

 * the Free Software Foundation; either version 2 of the License, or

 * (at your option) any later version.

 *

 * This program is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

 * GNU General Public License for more details.

 *

 * You should have received a copy of the GNU General Public License

 * along with this program; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

 *

 * $Id: adpcm.h 271 2005-08-09 08:31:35Z picard $

 *

 * The Core Pocket Media Player

 * Copyright (c) 2004-2005 Gabor Kovacs

 *

 ****************************************************************************/

#ifndef __ADPCM_H

#define __ADPCM_H

#define ADPCM_CLASS  FOURCC('A','D','P','C')

#define ADPCM_MS_ID  FOURCC('A','D','M','S')

#define ADPCM_IMA_ID FOURCC('A','D','I','M')

#define ADPCM_IMA_QT_ID FOURCC('A','D','I','Q')

#define ADPCM_G726_ID FOURCC('G','7','2','6')

extern void ADPCM_Init();

extern void ADPCM_Done();

#endif

/*****************************************************************************

 *

 * This program is free software ; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License as published by

 * the Free Software Foundation; either version 2 of the License, or

 * (at your option) any later version.

 *

 * This program is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

 * GNU General Public License for more details.

 *

 * You should have received a copy of the GNU General Public License

 * along with this program; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

 *

 * $Id: adpcm.c 565 2006-01-12 14:11:44Z picard $

 *

 * The Core Pocket Media Player

 * Copyright (c) 2004-2005 Gabor Kovacs

 *

 ****************************************************************************/

#include "../common/common.h"

#include "adpcm.h"

#include "g726/g72x.h"

typedef struct state 

{

    int Predictor;

    int StepIndex;

    int Step;

    int Sample1;

    int Sample2;

    int CoEff1;

    int CoEff2;

    int IDelta;

} state;

typedef struct adpcm

{

 codec Codec;

 buffer Data;

 int Channel; //IMA_QT

 int16_t* Buffer;

 state State[2];

 g726_state G726[2];

} adpcm;

static const int IndexTable[16] = 

{

    -1, -1, -1, -1, 2, 4, 6, 8,

    -1, -1, -1, -1, 2, 4, 6, 8,

};

static const int StepTable[] = 

{

    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,

    54, 84, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 139,

    152, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767

};

// AdaptationTable[], AdaptCoeff1[], and AdaptCoeff2[] are from libsndfile

static const int AdaptationTable[] = 

{

 230, 230, 230, 230, 307, 409, 512, 614,

 768, 614, 512, 409, 307, 230, 230, 230

};

static const int AdaptCoeff1[] = 

{

 256, 512, 0, 192, 240, 460, 392

};

static const int AdaptCoeff2[] = 

{

 0, -256, 0, , 0, -208, -232

};

static _INLINE int IMA_Calc(state* s, int v)

{

    int StepIndex;

    int Predictor;

    int Diff,Step;

    Step = StepTable[s->StepIndex];

    StepIndex = s->StepIndex + IndexTable[v];

    if (StepIndex < 0)

  StepIndex = 0;

    else if (StepIndex > 88)

  StepIndex = 88;

    Diff = ((2 * (v & 7) + 1) * Step) >> 3;

    Predictor = s->Predictor;

    if (v & 8) 

  Predictor -= Diff;

    else 

  Predictor += Diff;

 if (Predictor > 32767)

  Predictor = 32767;

 else if (Predictor < -32768)

  Predictor = -32768;

    s->Predictor = Predictor;

    s->StepIndex = StepIndex;

    return Predictor;

}

static _INLINE int MS_Calc(state* s, int v)

{

    int Predictor;

    Predictor = ((s->Sample1 * s->CoEff1) + (s->Sample2 * s->CoEff2)) >> 8;

    Predictor += ((v & 0x08) ? v-0x10:v) * s->IDelta;

 if (Predictor > 32767)

  Predictor = 32767;

 else if (Predictor < -32768)

  Predictor = -32768;

    s->Sample2 = s->Sample1;

    s->Sample1 = Predictor;

    s->IDelta = (AdaptationTable[v] * s->IDelta) >> 8;

    if (s->IDelta < 16)

  s->IDelta = 16;

    return Predictor;

}

static int Process(adpcm* p, const packet* Packet, const flowstate* State)

{

 int i;

 int Predictor;

 const uint8_t* In;

 const uint8_t* InEnd;

 int16_t* Out = p->Buffer;

 if (Packet)

 {

  if (Packet->RefTime >= 0)

   p->Codec.Packet.RefTime = Packet->RefTime;

  BufferPack(&p->Data,0);

  BufferWrite(&p->Data,Packet->Data[0],Packet->Length,1024);

 }

 else

  p->Codec.Packet.RefTime = TIME_UNKNOWN;

 if (!BufferRead(&p->Data,&In,p->Codec.In.Format.Format.Audio.BlockAlign))

  return ERR_NEED_MORE_DATA;

 InEnd = In + p->Codec.In.Format.Format.Audio.BlockAlign;

 switch (p->Codec.Node.Class)

 {

 case ADPCM_G726_ID:

 {

  g726_state *g1,*g2;

  g1 = g2 = &p->G726[0];

  if (p->Codec.In.Format.Format.Audio.Channels==2)

   ++g2;

  switch (p->Codec.In.Format.Format.Audio.Bits)

  {

  case 2:

   for (;In   {

    Out[0] = (int16_t)g726_16_decoder(In[0] >> 6,g1);

    Out[1] = (int16_t)g726_16_decoder(In[0] >> 4,g2);

    Out[2] = (int16_t)g726_16_decoder(In[0] >> 2,g1);

    Out[3] = (int16_t)g726_16_decoder(In[0],g2);

   }

   break;

  case 3:

   InEnd -= 2;

   for (;In   {

    Out[0] = (int16_t)g726_24_decoder(In[0] >> 5,g1);

    Out[1] = (int16_t)g726_24_decoder(In[0] >> 2,g2);

    Out[2] = (int16_t)g726_24_decoder((In[0] << 1) | (In[1] >> 7),g1);

    Out[3] = (int16_t)g726_24_decoder(In[1] >> 4,g2);

    Out[4] = (int16_t)g726_24_decoder(In[1] >> 1,g1);

    Out[5] = (int16_t)g726_24_decoder((In[1] << 2) | (In[2] >> 6),g2);

    Out[6] = (int16_t)g726_24_decoder(In[2] >> 3,g1);

    Out[7] = (int16_t)g726_24_decoder(In[2] >> 0,g2);

   }

   break;

  case 4:

   for (;In   {

    Out[0] = (int16_t)g726_32_decoder(In[0] >> 4,g1);

    Out[1] = (int16_t)g726_32_decoder(In[0],g2);

   }

   break;

  case 5:

   InEnd -= 4;

   for (;In   {

    Out[0] = (int16_t)g726_40_decoder(In[0] >> 3,g1);

    Out[1] = (int16_t)g726_40_decoder((In[0] << 2) | (In[1] >> 6),g2);

    Out[2] = (int16_t)g726_40_decoder(In[1] >> 1,g1);

    Out[3] = (int16_t)g726_40_decoder((In[1] << 4) | (In[2] >> 4),g2);

    Out[4] = (int16_t)g726_40_decoder((In[2] << 1) | (In[3] >> 7),g1);

    Out[5] = (int16_t)g726_40_decoder(In[3] >> 2,g2);

    Out[6] = (int16_t)g726_40_decoder((In[3] << 3) | (In[4] >> 5),g1);

    Out[7] = (int16_t)g726_40_decoder(In[4] >> 0,g2);

   }

   break;

  }

  break;

 }

 case ADPCM_IMA_QT_ID:

 {

  int No,Ch;

  Ch = p->Codec.In.Format.Format.Audio.Channels;

  for (No=0;No  {

   state *s;

   s = &p->State[0];

   s->Predictor = (int16_t)((In[1] & 0x80) | (In[0] << 8));

   s->StepIndex = In[1] & 0x7F;

   if (s->StepIndex > 88)

    s->StepIndex = 88;

   In+=2;

   InEnd=In+32;

   Out = p->Buffer+No;

   for (;In   {

    *Out = (int16_t)IMA_Calc(s, In[0] & 0x0F);

    Out+=Ch;

    *Out = (int16_t)IMA_Calc(s, In[0] >> 4);

    Out+=Ch;

   }

  }

  Out = p->Buffer+Ch*;

  break;

 }

 case ADPCM_IMA_ID:

 {

  state *s1,*s2;

  s1 = &p->State[0];

  s1->Predictor = (int16_t)(In[0] | (In[1] << 8));

  In+=2;

  s1->StepIndex = *In++;

  if (s1->StepIndex > 88)

   s1->StepIndex = 88;

  ++In;

  if (p->Codec.In.Format.Format.Audio.Channels == 2)

  {

   s2 = &p->State[1];

   s2->Predictor = (int16_t)(In[0] | (In[1] << 8));

   In+=2;

   s2->StepIndex = *In++;

   if (s2->StepIndex > 88)

    s2->StepIndex = 88;

   ++In;

   for (i=4;In   {

    Out[0] = (int16_t)IMA_Calc(s1, In[0] & 0x0F);

    Out[1] = (int16_t)IMA_Calc(s2, In[4] & 0x0F);

    Out[2] = (int16_t)IMA_Calc(s1, In[0] >> 4);

    Out[3] = (int16_t)IMA_Calc(s2, In[4] >> 4);

    if (--i==0)

    {

     i=4;

     In+=4;

    }

   }

  }

  else

  {

   for (;In   {

    Out[0] = (int16_t)IMA_Calc(s1, In[0] & 0x0F);

    Out[1] = (int16_t)IMA_Calc(s1, In[0] >> 4);

   }

  }

  break;

 }

 case ADPCM_MS_ID:

 {

  state *s1,*s2;

  s1 = &p->State[0];

  s2 = p->Codec.In.Format.Format.Audio.Channels==2 ? &p->State[1] : s1;

  Predictor = *In++;

  if (Predictor > 7)

   Predictor = 7;

  s1->CoEff1 = AdaptCoeff1[Predictor];

  s1->CoEff2 = AdaptCoeff2[Predictor];

  if (s2 != s1)

  {

   Predictor = *In++;

   if (Predictor > 7)

    Predictor = 7;

   s2->CoEff1 = AdaptCoeff1[Predictor];

   s2->CoEff2 = AdaptCoeff2[Predictor];

  }

  s1->IDelta = (int16_t)(In[0] | (In[1] << 8));

  In+=2;

  if (s2 != s1)

  {

   s2->IDelta = (int16_t)(In[0] | (In[1] << 8));

   In+=2;

  }

  s1->Sample1 = (int16_t)(In[0] | (In[1] << 8));

  In+=2;

  if (s2 != s1)

  {

   s2->Sample1 = (int16_t)(In[0] | (In[1] << 8));

   In+=2;

  }

  s1->Sample2 = (int16_t)(In[0] | (In[1] << 8));

  In+=2;

  if (s2 != s1)

  {

   s2->Sample2 = (int16_t)(In[0] | (In[1] << 8));

   In+=2;

  }

  *Out++ = (int16_t)s1->Sample1;

  if (s2 != s1) *Out++ = (int16_t)s2->Sample1;

  *Out++ = (int16_t)s1->Sample2;

  if (s2 != s1) *Out++ = (int16_t)s2->Sample2;

  for (;In  {

   Out[0] = (int16_t)MS_Calc(s1, In[0] >> 4);

   Out[1] = (int16_t)MS_Calc(s2, In[0] & 0x0F);

  }

  break;

 }

 }

 p->Codec.Packet.Length = (uint8_t*)Out - (uint8_t*)p->Buffer;

 return ERR_NONE;

}

static int UpdateInput(adpcm* p)

{

 BufferClear(&p->Data);

 free(p->Buffer);

 p->Buffer = NULL;

 if (p->Codec.In.Format.Type == PACKET_AUDIO)

 {

  PacketFormatPCM(&p->Codec.Out.Format,&p->Codec.In.Format,16);

  if (!p->Codec.In.Format.Format.Audio.BlockAlign)

   p->Codec.In.Format.Format.Audio.BlockAlign = 1024;

  if (p->Codec.Node.Class == ADPCM_IMA_QT_ID)

   p->Codec.In.Format.Format.Audio.BlockAlign = (32+2)*p->Codec.In.Format.Format.Audio.Channels;

  if (p->Codec.Node.Class == ADPCM_G726_ID)

  {

   p->Codec.In.Format.Format.Audio.BlockAlign = 120;

   g726_init_state(&p->G726[0]);

   g726_init_state(&p->G726[1]);

  }

  p->Buffer = (int16_t*) malloc(sizeof(int16_t)*4*p->Codec.In.Format.Format.Audio.BlockAlign);

  if (!p->Buffer)

   return ERR_OUT_OF_MEMORY;

  p->Codec.Packet.Data[0] = p->Buffer;

 }

 return ERR_NONE;

}

static int Flush(adpcm* p)

{

 if (p->Codec.Node.Class == ADPCM_G726_ID)

 {

  g726_init_state(&p->G726[0]);

  g726_init_state(&p->G726[1]);

 }

 BufferDrop(&p->Data);

 p->Channel = 0;

 return ERR_NONE;

}

static int Create(adpcm* p)

{

 p->Codec.Process = (packetprocess)Process;

 p->Codec.UpdateInput = (nodefunc)UpdateInput;

 p->Codec.Flush = (nodefunc)Flush;

 return ERR_NONE;

}

static const nodedef ADPCM =

{

 sizeof(adpcm)|CF_ABSTRACT,

 ADPCM_CLASS,

 CODEC_CLASS,

 PRI_DEFAULT,

 (nodecreate)Create,

 NULL,

};

static const nodedef ADPCM_MS =

{

 0, //parent size

 ADPCM_MS_ID,

 ADPCM_CLASS,

 PRI_DEFAULT,

 NULL,

 NULL,

};

static const nodedef ADPCM_IMA =

{

 0, //parent size

 ADPCM_IMA_ID,

 ADPCM_CLASS,

 PRI_DEFAULT,

 NULL,

 NULL,

};

static const nodedef ADPCM_IMA_QT =

{

 0, //parent size

 ADPCM_IMA_QT_ID,

 ADPCM_CLASS,

 PRI_DEFAULT,

 NULL,

 NULL,

};

static const nodedef ADPCM_G726 =

{

 0, //parent size

 ADPCM_G726_ID,

 ADPCM_CLASS,

 PRI_DEFAULT,

 NULL,

 NULL,

};

void ADPCM_Init()

{

 NodeRegisterClass(&ADPCM);

 NodeRegisterClass(&ADPCM_MS);

 NodeRegisterClass(&ADPCM_IMA);

 NodeRegisterClass(&ADPCM_IMA_QT);

 NodeRegisterClass(&ADPCM_G726);

}

void ADPCM_Done()

{

 NodeUnRegisterClass(ADPCM_MS_ID);

 NodeUnRegisterClass(ADPCM_IMA_ID);

 NodeUnRegisterClass(ADPCM_IMA_QT_ID);

 NodeUnRegisterClass(ADPCM_G726_ID);

 NodeUnRegisterClass(ADPCM_CLASS);

}

 

文档

ADPCM压缩算法

ADPCM压缩算法ADPCM(AdaptiveDifferentialPulseCodeModulation),是一种针对16bits(或8bits或者更高)声音波形数据的一种有损压缩算法,它将声音流中每次采样的16bit数据以4bit存储,所以压缩比1:4.而且压缩/解压缩算法非常简单,所以是一种低空间消耗,高质量高效率声音获得的好途径。保存声音的数据文件后缀名为.AUD的大多用ADPCM压缩。ADPCM主要是针对连续的波形数据的,保存的是波形的变化情况,以达到描述整个波形的目的,由于它的编
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top