📄 microsoft adpcm 编码解码算法.txt
字号:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <vector> int AdaptationTable [] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; typedef struct _ADPCM_COEF_SET { short coef1; short coef2; }ADPCM_COEF_SET; ADPCM_COEF_SET CoeffTable[] = { 256, 0, 512, -256, 0, 0, 192, 64, 240, 0, 460, -208, 392, -232 }; /* force memory align to 1 byte */ #pragma pack(push,1) typedef unsigned short WORD; typedef unsigned int DWORD; typedef unsigned char BYTE; typedef struct _RIFFWAVECHUNK { DWORD id; DWORD size; DWORD format; }RIFFWAVE_CHUNK; typedef struct _WAVEFORMATEX { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; }WAVEFORMAT_EX; typedef struct _WAVEFORMATCHUNK { DWORD id; DWORD size; WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; }FORMAT_CHUNK; typedef struct _MICROSOFT_ADPCM_FORMAT { DWORD id; DWORD size; WAVEFORMAT_EX format; WORD wSamplesPerBlock; WORD wNumCoef; ADPCM_COEF_SET coeffs[7]; }MICROSOFT_ADPCM_FORMAT; typedef struct _DATA_CHUNK { DWORD id; DWORD size; BYTE data[1]; }DATA_CHUNK; typedef struct { DWORD id; DWORD size; DWORD nSamples; }FACT_CHUNK; typedef struct{ DWORD id; DWORD size; }CHUNK; typedef struct{ BYTE predictor; short iDelta; short iSample1; short iSample2; BYTE pNibbles[1]; }BLOCK; #pragma pack(pop) class Wavfile{ std::vector <char*> chunks; char* pEncoded; int totalSize; int curSize; public: Wavfile(const char* path); int encode(); int Wavfile::writeEncodedFile(char* path); void calculateCoefficient(ADPCM_COEF_SET& coeff,short* pdata,int len) { double alpha = 0; double beta = 0; double gama = 0; double m=0,n=0; int i; for( i=2;i <len;++i ) { alpha += (double)pdata[i-1]*pdata[i-1]; beta += (double)pdata[i-1]*pdata[i-2]; gama += (double)pdata[i-2]*pdata[i-2]; m += (double)pdata[i]*pdata[i-1]; n += (double)pdata[i]*pdata[i-2]; } coeff.coef1 = (m*gama-n*beta)*256/(alpha*gama-beta*beta); coeff.coef2 = (m*beta-n*alpha)*256/(beta*beta-alpha*gama); } int getClosestCoefficientIndex(ADPCM_COEF_SET& coeff) { unsigned diff = -1; int index = 0; for( int i=0;i <sizeof(CoeffTable)/sizeof(CoeffTable[0]); ++i) { int dx = (CoeffTable[i].coef1-coeff.coef1); int dy = (CoeffTable[i].coef2-coeff.coef2); if( dx*dx+dy*dy < diff ) diff = dx*dx+dy*dy, index = i; } return index; } BYTE trimToNibble(char c) { if( c>7 ) c = 7; if( c <-8 ) c = -8; if( c <0 ) c = c&0x0f; return c; } void addBlock(char* p,int size) { if( size+curSize >= totalSize ) { totalSize = (size+totalSize)*2; pEncoded = (char*)realloc(pEncoded,totalSize); } memcpy(&pEncoded[curSize],p,size); curSize += size; } DATA_CHUNK* getDataChunk() { for(int i=0;i <chunks.size();++i) if( *(DWORD*)(chunks[i])==0x61746164 ) return (DATA_CHUNK*)(chunks[i]); return NULL; } FORMAT_CHUNK* getFormatChunk() { for(int i=0;i <chunks.size();++i) if( *(DWORD*)(chunks[i])==0x20746d66 ) return (FORMAT_CHUNK*)(chunks[i]); return NULL; } ~Wavfile() { for(int i=0;i <chunks.size();++i) delete[] chunks[i]; if( pEncoded!=NULL ) free(pEncoded); } }; Wavfile::Wavfile(const char* path) { pEncoded = NULL; totalSize = 0; curSize = 0; FILE* fp = fopen(path,"rb"); CHUNK ch; chunks.reserve(4); fread(&ch,sizeof(ch),1,fp); if( ch.id!=0x46464952 ) { fclose(fp); return; } char* p = new char[sizeof(ch)+ch.size]; *((CHUNK*)p) = ch; fread(p+sizeof(ch),4,1,fp); chunks.push_back(p); fread(&ch,sizeof(ch),1,fp); while( !feof(fp) ) { char* p = new char[sizeof(ch)+ch.size]; *((CHUNK*)p) = ch; fread(p+sizeof(ch),ch.size,1,fp); chunks.push_back(p); fread(&ch,sizeof(ch),1,fp); } fclose(fp); } int Wavfile::encode() { static BYTE blockbuff[256]; BLOCK* pbuff = (BLOCK*)blockbuff; DATA_CHUNK* pChunk = this->getDataChunk(); ADPCM_COEF_SET coeff; int len = pChunk->size; short* p = (short*)pChunk->data; short* pend = p + (len+1)/2; this->calculateCoefficient(coeff,p,500); int index = this->getClosestCoefficientIndex(coeff); ADPCM_COEF_SET* pCoeff = &CoeffTable[index]; pbuff->iSample2 = *p++; pbuff->iSample1 = *p++; short iDelta = (pCoeff->coef1*pbuff->iSample1 + pCoeff->coef2*pbuff->iSample2)/256 - *p; iDelta /= 4; if( iDelta <=0 ) iDelta = (-iDelta)+1; pbuff->iDelta = iDelta; pbuff->predictor = index; short iSample1 = pbuff->iSample1; short iSample2 = pbuff->iSample2; int flag = 0; BYTE bytebuff = 0; int cnt = 0; while( p <pend ) { short iPredSamp = (pCoeff->coef1*iSample1 + pCoeff->coef2*iSample2)/256; char iErrorDelta = (*p - iPredSamp)/iDelta; int remainder = (*p-iPredSamp)%iDelta; if( remainder>iDelta/2 ) ++iErrorDelta; if( iErrorDelta>7 ) iErrorDelta = 7; if( iErrorDelta <-8 ) iErrorDelta = -8; short iNewSample = iPredSamp + iErrorDelta*iDelta; iDelta = iDelta * AdaptationTable[trimToNibble(iErrorDelta)]/256; if( iDelta <1 ) iDelta = 1; iSample2 = iSample1; iSample1 = iNewSample; ++p; if( !flag ) flag = 1, bytebuff = trimToNibble(iErrorDelta); else { flag = 0; bytebuff = (bytebuff < <4) | trimToNibble(iErrorDelta); pbuff->pNibbles[cnt++] = bytebuff; if( !(cnt <249) ) { addBlock((char*)pbuff,256); cnt = 0; if( !(p <pend) ) break; this->calculateCoefficient(coeff,p,500); index = this->getClosestCoefficientIndex(coeff); pCoeff = &CoeffTable[index]; pbuff->predictor = index; pbuff->iDelta = iDelta; pbuff->iSample2 = *p++; pbuff->iSample1 = *p++; iSample1 = pbuff->iSample1; iSample2 = pbuff->iSample2; } } } if( cnt <249 ) { while( cnt <249 ) pbuff->pNibbles[cnt++] = 0; addBlock( (char*)pbuff,256 ); } return len/2; } int Wavfile::writeEncodedFile(char* path) { RIFFWAVE_CHUNK rc; rc.id = 0x46464952; rc.format = 0x45564157; FACT_CHUNK fc; fc.id = 0x74636166; fc.size = 4; fc.nSamples = encode(); MICROSOFT_ADPCM_FORMAT fmtc; fmtc.id = 0x20746d66; fmtc.size = sizeof(fmtc)-8; fmtc.wNumCoef = 7; fmtc.wSamplesPerBlock = 500; memcpy( &fmtc.coeffs[0],&CoeffTable[0],sizeof(CoeffTable) ); fmtc.format.wFormatTag = 0x02; fmtc.format.nBlockAlign = 256; fmtc.format.nAvgBytesPerSec = 4096; fmtc.format.nSamplesPerSec = 8000; fmtc.format.nChannels = 1; fmtc.format.wBitsPerSample = 4; fmtc.format.cbSize = 32; DATA_CHUNK dc; dc.id = 0x61746164; dc.size = curSize; rc.size = 4+sizeof(fmtc)+sizeof(fc)+sizeof(dc.id)+sizeof(dc.size)+dc.size; FILE* fp = fopen(path,"wb"); fwrite(&rc,sizeof(rc),1,fp); fwrite(&fmtc,sizeof(fmtc),1,fp); fwrite(&fc,sizeof(fc),1,fp); fwrite(&dc.id,sizeof(dc.id),1,fp); fwrite(&dc.size,sizeof(dc.size),1,fp); fwrite(pEncoded,curSize,1,fp); fclose(fp); return rc.size; } int main(int argc,char** argv) { if( argc!= 3 ) { printf("invalid argumentsn"); return 1; } Wavfile thefile(argv[1]); FORMAT_CHUNK* p = thefile.getFormatChunk(); if( p==NULL ) { printf("invalid wave file!!n"); return 1; } if( p->wFormatTag!=1 ) { printf("not a raw windows wav format!!!n"); return 1; } if( p->nChannels!=1 | | p->nSamplesPerSec!=8000 ) { printf("wrong sample rate or channelsn"); printf("only support 8000 samplesPerSec and mono channeln"); return 1; } thefile.writeEncodedFile(argv[2]); return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -