ADPCM文件解碼詳解

本文轉自:http://hi.baidu.com/sunsee/item/68d61e451921e30ec016134a

ADPCM文件解碼詳解  

一、搞了幾天終於搞定這個ADPCM解碼了,之前找了很多的資料,大致描述的都是千篇一律,但是基本上都沒有說到細節上,讓我也走了不少彎路,其實主要在細節,網上給的算法是正確的,但是直接運用根本就不行,噪音很大。這一點讓我一直很頭疼,最後還是看了英文資料,纔得到解答,還是老外的原始資料好。

二、給個英文參考網址吧

http://www.moon-soft.com/program/FORMAT/windows/wavec.htm

https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

這兩個講的很詳細,請仔細閱讀!通過閱讀我發現細節在與adpcm格式的wav文件的block的特點,每一個block包含header和data兩部分,

Typedef struct{ 

         short  sample0;    //block中第一個採樣值(未壓縮) 

         BYTE  index;     //上一個block最後一個index,第一個block的index=0;

         BYTE  reserved;   //尚未使用

}MonoBlockHeader

關鍵是我們要抓住每一個block的header裏面的信息,即sample0,運算的時候注意運用!

三、還是給個代碼吧,多的也不說了!

1、adpcm.c文件代碼

#include"adpcm.h"

/* Intel ADPCM step variation table */
staticintindexTable[16]={
    -1,-1,-1,-1,2,4,6,8,
    -1,-1,-1,-1,2,4,6,8,
};

staticintstepsizeTable[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
};

voidadpcm_decoder(char*inbuff,char*outbuff,intlen_of_in,structadpcm_state *state )
{
 int  i=0,j=0;
    chartmp_data;
    structadpcm_state *tmp_state =state;
    longstep;/* Quantizer step size */
    signedlongpredsample;/* Output of ADPCM predictor */
    signedlongdiffq;/* Dequantized predicted difference */
    intindex;/* Index into step size table */

    intSamp;
    unsignedcharSampH,SampL;
    unsignedcharinCode;
 
    /* Restore previous values of predicted sample and quantizer step
    size index
    */
    predsample =state->valprev;
    index =state->index;
 
    for(i=0;i<len_of_in*2;i++)
 {
  tmp_data=inbuff[i/2];  
  if(i%2)
   inCode=(tmp_data&0xf0)>>4;
  else
   inCode=tmp_data &0x0f;
    
  step =stepsizeTable[index];
   /* Inverse quantize the ADPCM code into a predicted difference
    using the quantizer step size
   */
    
  diffq =step >>3;
  if(inCode &4)
   diffq +=step;
  if(inCode &2)
   diffq +=step >>1;
  if(inCode &1)
   diffq +=step >>2;
    /* Fixed predictor computes new predicted sample by adding the
    old predicted sample to predicted difference
    */
  if(inCode &8)
   predsample -=diffq;
  else
   predsample +=diffq;
    /* Check for overflow of the new predicted sample
    */
   if(predsample >32767)
   predsample =32767;
   elseif(predsample <-32768)
   predsample =-32768;
    /* Find new quantizer stepsize index by adding the old index
    to a table lookup using the ADPCM code
    */
   index +=indexTable[inCode];
    /* Check for overflow of the new quantizer step size index
    */
  if(index <0)
   index =0;
  if(index >88)
   index =88;
    /* Return the new ADPCM code */
  Samp=predsample;
  if(Samp>=0)
  {
   SampH=Samp/256;
   SampL=Samp-256*SampH;
  }
  else
  {
   Samp=32768+Samp;
   SampH=Samp/256;
   SampL=Samp-256*SampH;
   SampH+=0x80;
  }
  outbuff[j++]=SampL;
  outbuff[j++]=SampH;   
 }
 
 /* Save the predicted sample and quantizer step size index for
 next iteration
 */
 state->valprev =(short)predsample;
 state->index =(char)index;
}

2、adpcm.h文件代碼

#ifndefADPCM_H
#defineADPCM_H

#ifdef__cplusplus
extern"C"{
#endif

struct adpcm_state {
    short valprev; /* Previous output value */
    char index;  /* Index into stepsize table */
};

voidadpcm_decoder(char*inbuff,char*outbuff,intlen_of_in,structadpcm_state *state );
#ifdef__cplusplus
}  /* extern "C" */
#endif

#endif/* ADPCM_H*/


3、main.c文件代碼

#include"stdio.h"
#include  "stdlib.h"
#include  "adpcm.h"


#defineCFG_BlkSize     256   

charch[CFG_BlkSize];  //用來存儲wav文件的頭信息
charsavedata[CFG_BlkSize*4];

 

unsignedcharRiffHeader[]={
      'R','I','F','F',// Chunk ID (RIFF)
      0x70,0x70,0x70,0x70,// Chunk payload size (calculate after rec!)
      'W','A','V','E',// RIFF resource format type  
   
      'f','m','t',' ',// Chunk ID (fmt )
      0x10,0x00,0x00,0x00,// Chunk payload size (0x14 = 20 bytes)
      0x01,0x00,             // Format Tag ()
      0x01,0x00,             // Channels (1)
      0x40,0x1f,0x00,0x00,// Sample Rate,  = 16.0kHz
      0x80,0x3e,0x00,0x00,// Byte rate       32.0K
   0x02,0x00,             // BlockAlign == NumChannels * BitsPerSample/8 
   0x10,0x00     // BitsPerSample 
    };
 unsignedcharRIFFHeader504[]={
  'd','a','t','a',// Chunk ID (data)
  0x70,0x70,0x70,0x70  // Chunk payload size (calculate after rec!)
};


/****************************************************************
函數名稱:    main
功能描述:   
輸入參數:    none
輸出參數:    none
****************************************************************/
voidmain(void)
{
 FILE *fpi,*fpo;
 unsignedlongiLen,temp;
 structadpcm_state ADPCMstate;
 unsignedlong=0;
 unsignedlongj;
 fpi=fopen("f:\\lk\\test.adpcm","rb");     //爲讀,打開一個wav文件
 if((fpi=fopen("f:\\lk\\test.adpcm","rb"))==NULL)  //若打開文件失敗,退出
 {
  printf("can't open this file\n");
  printf("\nread error!\n");
  printf("\n%d\n",i);
  exit(0);
 }
 fseek(fpi,0,SEEK_END);   
    iLen=ftell(fpi);
 printf("\n======================================================\n");
 printf("\n========================%d========================\n",iLen);
 printf("\n======================================================\n");
 if((iLen-44)%CFG_BlkSize)
  iLen =(iLen-44)/CFG_BlkSize+1;
 else
  iLen =(iLen-44)/CFG_BlkSize;

 

 fpo=fopen("f:\\lk\\new.pcm","rb+");                     //爲寫,打開一個wav文件
 if((fpo=fopen("f:\\lk\\new.pcm","rb+"))==NULL)          //若打開文件失敗,退出
 {
  printf("can't open this file\n");
  printf("\nwrite error!\n");
  exit(0);
 }
 fseek(fpo,0,SEEK_SET);
 fwrite(RiffHeader,sizeof(RiffHeader),1,fpo);    //寫文件riff
 fwrite(RIFFHeader504,sizeof(RIFFHeader504),1,fpo);   //寫 data塊頭
 while(i<iLen)
 {
  fseek(fpi,48+i*CFG_BlkSize,SEEK_SET);
  fread(ch,1,CFG_BlkSize,fpi);
  printf("\n======================================================\n");
  for(j=0;j<100;j++)
   printf("| %d |",ch[j]);
  printf("\n======================================================\n");
  ////////////////////////添加讀取BlockHeader部分開始////////////////////////////////
  if(==0)
  {
   ADPCMstate.index =0; //第一個block的index爲 0     當前的BlockSize爲 256 即採樣點數爲 (256-4)*2+1 = 505
  }
  else
  {
   ADPCMstate.index =ch[2];
  }
  ADPCMstate.valprev =(short)ch[0]+((short)(ch[1]))*256;   //每一個block裏面幀頭有一個未壓縮的數據 存儲時 先低後高
  savedata[0]=ch[0];     //存儲第一個沒有被壓縮的數據
  savedata[1]=ch[1];     //存儲第一個沒有被壓縮的數據
  ////////////////////////添加讀取BlockHeader部分結束////////////////////////////////
  adpcm_decoder(&ch[4],&savedata[2],CFG_BlkSize-4,&ADPCMstate);//解碼出來了   (256-4)*4 個字節   
  temp =(CFG_BlkSize-4)*4+2;
  fseek(fpo,44+i*temp,SEEK_SET);       //開始寫聲音數據
  fwrite(savedata,temp,1,fpo);
  i++;
 }
 temp *=i;
 RiffHeader[4]=(unsignedchar)((40+temp)&0x000000ff);
 RiffHeader[5]=(unsignedchar)(((40+temp)&0x0000ff00)>>8);
 RiffHeader[6]=(unsignedchar)(((40+temp)&0x00ff0000)>>16);
 RiffHeader[7]=(unsignedchar)(((40+temp)&0xff000000)>>24);
 fseek(fpo,4,SEEK_SET);
 fwrite(&RiffHeader[4],4,1,fpo);

 RiffHeader[40]=(unsignedchar)(temp&0x000000ff);
 RiffHeader[41]=(unsignedchar)((temp&0x0000ff00)>>8);
 RiffHeader[42]=(unsignedchar)((temp&0x00ff0000)>>16);
 RiffHeader[43]=(unsignedchar)((temp&0xff000000)>>24);
 fseek(fpo,40,SEEK_SET);
 fwrite(&RiffHeader[40],4,1,fpo);
 fclose(fpi);    
    fclose(fpo);  
 printf("\n==========================OK!=========================\n");
}

四、以上是給出的代碼,絕對管用,讀者在實驗時候請在vc++6.0環境下建立工程,實驗時候請在f:\\lk\\下放置一個adpcm格式的文件和一個空的pcm格式文件,當然了這個pcm和adpcm其實都是wav格式的,試驗者可以隨意命名格式,我爲了區分才這樣命名後綴的,希望我總結的能夠讀者帶來幫助,謝謝您的閱讀!



PCM數據格式


1. 音頻簡介

經常見到這樣的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等.

44100HZ 16bit stereo: 每秒鐘有 44100 次採樣, 採樣數據用 16 位(2字節)記錄, 雙聲道(立體聲);

22050HZ 8bit  mono: 每秒鐘有 22050 次採樣, 採樣數據用 8 位(1字節)記錄, 單聲道;

當然也可以有 16bit 的單聲道或 8bit 的立體聲, 等等。

採樣率是指:聲音信號在“模→數”轉換過程中單位時間內採樣的次數。採樣值是指每一次採樣週期內聲音模擬信號的積分值。


對於單聲道聲音文件,採樣數據爲八位的短整數(short int 00H-FFH);

而對於雙聲道立體聲聲音文件,每次採樣數據爲一個16位的整數(int),高八位(左聲道)和低八位(右聲道)分別代表兩個聲道。

人對頻率的識別範圍是 20HZ - 20000HZ, 如果每秒鐘能對聲音做 20000 個採樣, 回放時就足可以滿足人耳的需求. 所以 22050  的採樣頻率是常用的, 44100已是CD音質, 超過48000的採樣對人耳已經沒有意義。這和電影的每秒 24 幀圖片的道理差不多。

每個採樣數據記錄的是振幅, 採樣精度取決於儲存空間的大小:

1  字節(也就是8bit) 只能記錄 256 個數, 也就是隻能將振幅劃分成 256 個等級;

2  字節(也就是16bit) 可以細到 65536 個數, 這已是 CD 標準了;

4  字節(也就是32bit) 能把振幅細分到 4294967296 個等級, 實在是沒必要了.

如果是雙聲道(stereo), 採樣就是雙份的, 文件也差不多要大一倍.

這樣我們就可以根據一個  wav 文件的大小、採樣頻率和採樣大小估算出一個 wav 文件的播放長度。

譬如  "Windows XP 啓動.wav" 的文件長度是 424,644 字節, 它是 "22050HZ / 16bit / 立體聲" 格式(這可以從其  "屬性->摘要" 裏看到),

那麼它的每秒的傳輸速率(位速,  也叫比特率、取樣率)是 22050*16*2 = 705600(bit/s), 換算成字節單位就是  705600/8 = 88200(字節/秒), 
播放時間:424644(總字節數) /  88200(每秒字節數) ≈ 4.8145578(秒)。

但是這還不夠精確,  包裝標準的 PCM 格式的 WAVE 文件(*.wav)中至少帶有 42 個字節的頭信息, 在計算播放時間時應該將其去掉, 
所以就有:(424644-42)  / (22050*16*2/8) ≈ 4.8140816(秒). 這樣就比較精確了.

關於聲音文件還有一個概念:  "位速", 也有叫做比特率、取樣率, 譬如上面文件的位速是 705.6kbps 或 705600bps, 其中的 b 是 bit, ps  是每秒的意思;

壓縮的音頻文件常常用位速來表示,  譬如達到 CD 音質的 MP3 是: 128kbps / 44100HZ.



2. PCM數據格式

PCM(Pulse Code Modulation)也被稱爲  脈碼編碼調製。PCM中的聲音數據沒有被壓縮,如果是單聲道的文件,採樣數據按時間的先後順序依次存入。(它的基本組織單位是BYTE(8bit)或WORD(16bit))

一般情況下,一幀PCM是由2048次採樣組成的( 參 http://discussion.forum.nokia.com/forum/showthread.php?129458-請問PCM格式的音頻流,每次讀入或輸出的塊的大小是必須固定爲4096B麼&s=e79e9dd1707157281e3725a163844c49)。

如果是雙聲道的文件,採樣數據按時間先後順序交叉地存入。如圖所示:



PCM的每個樣本值包含在一個整數i中,i的長度爲容納指定樣本長度所需的最小字節數。

首先存儲低有效字節,表示樣本幅度的位放在i的高有效位上,剩下的位置爲0,這樣8位和16位的PCM波形樣本的數據格式如下所示。

樣本大小      數據格式            最小值    最大值

8位PCM       unsigned int         0       225

16位PCM      int                -32767    32767


ADPCM WAVE文件的壓縮與解壓縮

一、概述:
  本文敘述瞭如何通過IMA-ADPCM壓縮和解壓縮算法來完成從IMA-ADPCM文件轉換爲PCM文件的過程。主要包括的內容有:PCM和IMA-ADPCM WAVE文件內部結構的介紹,IMA-ADPCM壓縮與解壓縮算法,以及如何生成特有的音頻壓縮格式文件等三方面的內容。


二、WAVE文件的認識
  WAVE文件是計算機領域最常用的數字化聲音文件格式之一,它是微軟專門爲Windows系統定義的波形文件格式(Waveform Audio),由於其擴展名爲"*.wav"。
wave文件有很多不同的壓縮格式,而且現在一些程序生成的wave文件都或多或少地含有一些錯誤。這些錯誤的產生不是因爲單個數據壓縮和解壓縮算法的問題,而是因爲在壓縮和解壓縮後沒有正確地組織好文件的內部結構。所以,正確而詳細地瞭解各種WAVE文件的內部結構是成功完成壓縮和解壓縮的基礎,也是生成特有音頻壓縮格式文件的前提。
最基本的WAVE文件是PCM(脈衝編碼調製)格式的,這種文件直接存儲採樣的聲音數據沒有經過任何的壓縮,是聲卡直接支持的數據格式,要讓聲卡正確播放其它被壓縮的聲音數據,就應該先把壓縮的數據解壓縮成PCM格式,然後再讓聲卡來播放。

1.Wave文件的內部結構
WAVE文件是以RIFF(Resource Interchange File Format,"資源交互文件格式")格式來組織內部結構的。RIFF文件結構可以看作是樹狀結構,其基本構成是稱爲"塊"(Chunk)的單元,最頂端是一個“RIFF”塊,下面的每個塊有“類型塊標識(可選)”、“標誌符”、“數據大小”及“數據”等項所組成,塊的結構如表1所示:

基本chunk的內部結構表

上面說到的“類型塊標識”只在部分chunk中用到,如“WAVE”chunk中,這時表示下面嵌套有別的chunk,當使用了“類型塊標識”時,該chunk就沒有別的項(如塊標誌符,數據大小等),它只作爲文件讀取時的一個標識。先找到這個“類型塊標識”,再以它爲起來讀取它下面嵌套的其它chunk。
每個文件最前端寫入的是RIFF塊,每個文件只有一個RIFF塊。從表2中可以看出它的結構:

PCM WAVE文件的內部結構示意表

PCM格式的文件會至少多加入一個“fact”塊,它用來記錄數據解壓縮後的大小。(注意是數據而不是文件)這個“fact”塊一般加在“data”塊的前面。

2.WAVEFORMAT結構的認識

PCM和非PCM的主要區別是聲音數據的組織不同,這些區別可以通過兩者的WAVEFORMAT結構來區分。下面以PCMIMA-ADPCM來進行對比:

WAVE的基本結構WAVEFORMATEX結構定義如下:

typedef struct

{

WORD wFormatag;  //編碼格式,包括WAVE_FORMAT_PCM//WAVEFORMAT_ADPCM

WORD  nChannls;       //聲道數,單聲道爲1,雙聲道爲2;

DWORD nSamplesPerSec;//採樣頻率;

DWORD nAvgBytesperSec//每秒的數據量;

WORD  nBlockAlign;//塊對齊;

WORD  wBitsPerSample;//WAVE文件的採樣大小;

WORD  sbSize;        //PCM中忽略此值

}WAVEFORMATEX

PCM的結構就是基本結構;

IMAADPCMWAVEFORMAT結構定義如下:

Typedef struct

{

WAVEFORMATEX wfmt;

WORD nSamplesPerBlock;

}IMAADPCMWAVEFORMAT;

IMA-ADPCMwfmt->cbsize不能忽略,一般取值爲2,表示此類型的WAVEFORMAT比一般的WAVEFORMAT多出2個字節。這兩個字符也就是nSamplesPerBlock

3.“fact”chunk的內部組織

在非PCM格式的文件中,一般會在WAVEFORMAT結構後面加入一個“factchunk,結構如下:

typedef struct{

char[4];          //fact”字符串

DWORD chunksize;

DWORD datafactsize;    //數據轉換爲PCM格式後的大小。

}factchunk; 

datafactsize是這個chunk中最重要的數據,如果這是某種壓縮格式的聲音文件,那麼從這裏就可以知道他解壓縮後的大小。對於解壓時的計算會有很大的好處!

4.“datachunk的內部組織

從“datachunk的第9個字節開始,存儲的就是聲音信息的數據了,(前八個字節存儲的是標誌符“data”和後接數據大小size(DWORD)。這些數據可能是壓縮的,也可能是沒有壓縮的。

PCM中的聲音數據沒有被壓縮,如果是單聲道的文件,採樣數據按時間的先後順序依次存入。(它的基本組織單位是BYTE(8bit)WORD(16bit))如果是雙聲道的文件,採樣數據按時間先後順序交叉地存入。如圖所示:

IMA-ADPCM是壓縮格式,它是從PCM16位採樣壓縮成4位的。對於單聲道的IMA-ADPCM來說,它是將PCM的數據按時間次序依次壓縮並寫入文件中的,每個byte中含兩個採樣,低四位對應第一個採樣,高四位對應第二個採樣。而對於雙聲道的IMA-ADPCM來說,它的存儲相對就麻煩一些了,它是將PCM的左聲道的前8個採樣依次壓縮並寫入到一個DWORD中,然後寫入“datachunk裏。緊接着是右聲道的前8個採樣。以此循環,當採樣數不足8時(到數據尾端),應該把多出來的採樣用0填充。其示意圖如下:

特別注意:

IMA-ADPCM中,“datachuck中的數據是以block形式來組織的,我把它叫做“段”,也就是說在進行壓縮時,並不是依次把所有的數據進行壓縮保存,而是分段進行的,這樣有一個十分重要的好處:那就是在只需要文件中的某一段信息時,可以在解壓縮時可以只解所需數據所在的段就行了,沒有必要再從文件開始起一個一個地解壓縮。這對於處理大文件將有相當的優勢。同時,這樣也可以保證聲音效果。

Block一般是由block header (blockdata 兩者組成的。其中block header是一個結構,它在單聲道下的定義如下:

Typedef struct

{

short  sample0;    //block中第一個採樣值(未壓縮)

BYTE  index;     //上一個block最後一個index,第一個blockindex=0;

BYTE  reserved;   //尚未使用

}MonoBlockHeader;

有了blockheader的信息後,就可以不需要知道這個block前面和後面的數據而輕鬆地解出本block中的壓縮數據。對於雙聲道,它的blockheader應該包含兩個MonoBlockHeader其定義如下:

typedaf struct

{

MonoBlockHeader leftbher;

MonoBlockHeader rightbher;

}StereoBlockHeader;

在解壓縮時,左右聲道是分開處理的,所以必須有兩個MonoBlockHeader;

注1:上述的index是解壓縮算法中必須用到的一個參數。詳見後面。

注2: 關於block的大小,通常會有以下幾種情況:

對於單聲道,大小一般爲512byte,顯然這裏面可以保存的sample個數爲(512-sizeof(MonoBlockHeader))/4 + 1 = 1017個<其中"+1"是第一個存在頭結構中的沒有壓縮的sample.

對於雙聲道,大小一般爲1024byte,按上面的算法可以得出,其中的sample個數也是1017個.

4.讀取WAVE文件的方法.

在知道了WAVE文件的內部數據組織後,可以直接通過FILE或HFILE來實現文件的讀取。但由於WAVE文件是以RIFF格式來組織的,所以用多媒體輸入輸出流來操作將更加方便,可以直接在文件中查找chunk並定位數據。

三、IMA-ADPCM 編碼和解碼算法

IMA-ADPCM Intel公司首先開發的是一種主要針對16bit採樣波形數據的有損壓縮算法壓縮比爲4:1.它與通常的DVI-ADPCM是同一算法。(8bit數據壓縮時是3.2:1,也有非標準的IMA-ADPCM壓縮算法,可以達到5:1甚至更高的壓縮比)4:1的壓縮是目前使用最多的壓縮方式。

  ADPCM(Adaptive Differential Pulse Code Modulation 差分脈衝編碼調製)主要是針對連續的波形數據的保存的是相臨波形的變化情況以達到描述整個波形的目的。算法中必須用到兩個一維數組,setptab[] index_adjust[],附在下面的代碼之後。

--------------------------------------------------------------------------------

IMA-ADPCM 壓縮過程

首先我們認爲聲音信號都是從零開始的,那麼需要初始化兩個變量

int index = 0,prev_sample = 0;

但在實際使用中,prev_sample的值是每個block中第一個採樣的值。(這點在後面的block中會詳細介紹)

假設已經寫好了兩個函數:

GetNextSamp() ——得到一個16bit 的採樣數據;

SaveComCode() ——保存一個4bit 的壓縮樣品;

下面的循環將依次壓縮聲音數據流:

while (還有數據要處理) {

cur_sample = GetNextSamp();         // 得到PCM中的當前採樣數據

diff = cur_sample-prev_sample;      // 計算出和上一個的增量

if (diff<0)

{

diff=-diff;

fg=8; 

}  

else fg=0;                          // fg 保存的是符號位

code = 4*diff / steptab[index]; 

if (code>7) code=7;                 // 根據steptab[] 得到一個0~7 的值,它描述了採樣振幅的變化量

index+=index_adjust[code];          // 根據聲音強度調整下次取steptab 的序號,便於下次得到更精確的變化量的描述

if (index<0) index=0;               // 調整index的值

else if (index>88) index=88;

prev_sample=cur_sample;

SaveComCode(code|fg);                 // 加上符號位保存起來

}

--------------------------------------------------------------------------------

IMA-ADPCM 解壓縮過程

解壓縮實際是壓縮的一個逆過程,假設寫好了以下兩個函數:

GetNextCode() ——得到一個編碼(4bit

OutputSamp() ——將解碼出來的聲音信號保存起來(16bit

int index=0,cur_sample=0;

while (還有數據要處理) {

code=GetNextCode();           // 得到下一個壓縮樣品Code 4bit

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

code&=7;                      // code 分離爲數據和符號

diff = (steptab[index]*code) /4 + steptab[index] / 8;   // 後面加的一項是爲了減少誤差

if (fg==1) diff=-diff;

cur_sample+=diff;            // 計算出當前的波形數據

if (cur_sample>32767) OutputSamp(32767);

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

else OutputSamp(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 steptab[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 }; 

四、設計自己特用的壓縮聲音文件格式。

    有了上述幾節的知識,要基於IMA-ADPCM Encode/Dcode算法來設計出特有的壓縮聲音文件格式就不難了!只要 先設計好特有的文件內部結構和特殊的數據組織結構,再以此爲標準編寫壓縮和解壓縮程序就行了。由於我們已經搞清楚了PCM裏面的數據組織,所以我們還可以進行PCM文件的截取、連接、壓縮等更多功能。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章