视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
ADPCM压缩算法
2025-09-25 03:15:47 责编:小OO
文档
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);

}

 下载本文

显示全文
专题