Microsoft-ADPCM編碼與解碼原理與實(shí)例_第1頁(yè)
Microsoft-ADPCM編碼與解碼原理與實(shí)例_第2頁(yè)
Microsoft-ADPCM編碼與解碼原理與實(shí)例_第3頁(yè)
Microsoft-ADPCM編碼與解碼原理與實(shí)例_第4頁(yè)
Microsoft-ADPCM編碼與解碼原理與實(shí)例_第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Microsoft ADPCM 編碼解碼算法因?yàn)榉N種原因,最近需要把原始的wav文件壓縮成ADPCM格式。但是網(wǎng)上幾乎搜不到相關(guān)的中文資料?;讼喈?dāng)長(zhǎng)的時(shí)間,七拼八湊的從一些文章中得到了些信息,終于搞定了它。為了方便遇到跟我一樣麻煩的人,我決定把它詳細(xì)的寫下來(lái)。1. 關(guān)于DPCMDPCM是differential pulse code modulation的縮寫,也就是差分脈沖編碼調(diào)制的意思。他的主要思想是通過(guò)已知的數(shù)據(jù)預(yù)測(cè)下一個(gè)數(shù)據(jù),然后傳遞預(yù)測(cè)值與實(shí)際值之間的差值。具體的細(xì)節(jié)可以在很多信號(hào)處理相關(guān)的書上找到。一般的DPCM編碼器都是采用的線性預(yù)測(cè)。假設(shè)傳遞的數(shù)據(jù)是X1,X2,.Xn,而下一

2、個(gè)數(shù)據(jù),Xn+1還是未知??梢酝ㄟ^(guò)前面的X1,X2,.Xn的加權(quán)和來(lái)預(yù)測(cè)Xn+1,也就是Xn+1 = (Ai*Xi),其中i屬于1.n為了簡(jiǎn)化計(jì)算,大部分編碼的實(shí)現(xiàn)只取前兩項(xiàng),也就是, Xn+1 = a*Xn + b*Xn-1, 現(xiàn)在,最主要的事情就是如何對(duì)a,b進(jìn)行取值,才能使得Xn+1的誤差最小。如果假設(shè) xi 是預(yù)測(cè)值,xi是實(shí)際值,那么,(xi-xi)2 最小的時(shí)候,a,b就是最優(yōu)的。設(shè) F=(Xi-Xi)2,因?yàn)?Xi = a*Xi-1 + b*Xi-2,可以得出,F(xiàn)是關(guān)于a,b的二元函數(shù).也就是 F=f(a,b) ??梢苑謩e對(duì)a和b求偏導(dǎo)數(shù),求出它的極值點(diǎn)。fa(a,b) = 0

3、;fb(a,b) = 0 ;可以得到a * (Xi-1)2 + b * (Xi-1)*(Xi-2) =Xi*Xi-1a * (Xi-1)*(Xi-2) + b * (Xi-2)2=Xi*Xi-2如果設(shè)alpha = (Xi-1)2beta= (Xi-1)*(Xi-2)gama= (Xi-2)2m = Xi*Xi-1 n = Xi*Xi-2上面的式子就可以寫成a*alpha + b*beta = ma*beta + b*gama = n算出alpha,beta,gama,m,n以后,a和b的值就可以計(jì)算出來(lái)了,實(shí)際上我們只需要一個(gè)循環(huán)遍歷前n個(gè)數(shù)就能把它們都求出來(lái)。2. ADPCM的思想如果直接

4、使用DPCM進(jìn)行編碼的話,是得不到什么壓縮的效率的。緣故是,需要傳輸或保存的是預(yù)測(cè)值后的值與實(shí)際值之間的差值,這與原來(lái)的數(shù)據(jù)占用同樣的空間。為了滿足我們?cè)嫉膲嚎s數(shù)據(jù)的動(dòng)機(jī),你可以對(duì)這些差值進(jìn)行各種各樣的編碼。因?yàn)椋蟛糠智闆r下,差值都是像1,1,1,2,3,5,5,5之類的數(shù)??梢詫?duì)它們進(jìn)行通常的游程編碼或者h(yuǎn)uffman編碼,運(yùn)氣好的話能夠得到很大的壓縮比。這樣做會(huì)有一個(gè)很大的弊端。因?yàn)橛行?shù)據(jù)可能之間的聯(lián)系會(huì)呈線性或者某種連續(xù)函數(shù)的性質(zhì)。但是大部分情況下,數(shù)據(jù)的分布還是有一定的離散性的。當(dāng)數(shù)據(jù)之間出現(xiàn)很大的跳躍的時(shí)候,這種方法就顯得很蒼白無(wú)力了。我們可以這么做,每次對(duì)得到的差值用一個(gè)隨著

5、差值大小變化的數(shù)來(lái)除。這樣就可以隨著差值的變化,不斷調(diào)整比例因子。這樣出現(xiàn)較大的跳躍時(shí)也能把我們要存儲(chǔ)的差值限定在一個(gè)較小的范圍之內(nèi)。如果你現(xiàn)在有些迷惑,沒(méi)事,我們換種方式來(lái)說(shuō)明一下。假設(shè)差值是 diff,也就是 diff = Xi - Xi,那么,diff就有可能變動(dòng)很大,如果引入一個(gè)不斷變化的因子iDelta,那么,diff = diff / iDelta,而對(duì)于iDelta,每當(dāng)diff變大的時(shí)候,他就變大比較大,當(dāng)diff變得比較小的時(shí)候,他就相應(yīng)的減小。這樣,我們的diff就能保持相對(duì)的穩(wěn)定了。通過(guò)iDelta的引入,可以使得我們的DPCM編碼自動(dòng)的適應(yīng)數(shù)據(jù)間大幅度的跳躍。這就是自適

6、應(yīng)脈沖編碼調(diào)制,ADPCM的主要思想。你現(xiàn)在可能會(huì)想,iDelta到底怎么變化,才能自動(dòng)的匹配diff的變化? 一種可行的方法就是,把它定義為diff的一個(gè)函數(shù),這個(gè)函數(shù)根據(jù)不同的diff的值的大小取不同大小的值。通常我們會(huì)做一個(gè)iDelta值的表,通過(guò) diff作為索引,這樣,就可以根據(jù)不同的diff值,iDelta就可以作相應(yīng)的變化了。3. WAV文件的格式IMA-ADPCM壓縮的音頻文件并沒(méi)有一個(gè)統(tǒng)一的格式。我們現(xiàn)在只考慮微軟的自己的wav格式。apple公司的網(wǎng)站上有一篇寫得很不錯(cuò)的 technical note, 可以看后面的鏈接地址。wav文件是微軟定義的一系列資源文件中的一個(gè)。這

7、些文件通常是由一系列的chunk組成。所有的文件都以RIFF標(biāo)記開(kāi)頭,然后指出文件的大小。接著表明類型,比如WAVE,MIDI等. 一個(gè)wav文件的結(jié)構(gòu)大致如下_| RIFF WAVE Chunk|groupID = RIFF|riffType = WAVE|_| Format Chunk| ckID = fmt |_|_| Sound Data Chunk | ckID = data|_|_|一般每一個(gè)chunk都有一個(gè)id和一個(gè)size來(lái)表明chunk的類型和大小,這樣就可以很容易的將chunk讀出。id一般是四個(gè)字節(jié),用ASCII 碼的值來(lái)標(biāo)記,比如data chunk的id就是data

8、,而format chunk的id就是fmt .要注意的是,size表明的大小是以字節(jié)為單位的,而且不包括id和size字段本身所占的空間。原始的wave文件一般只有兩個(gè)chunk,也就是fmt和data,原則上,你可以添加任何的其他chunk,用來(lái)添加不同的信息.這也是wav文件出現(xiàn)很多變種的原因.windows下一般有兩種格式的wav文件,一種是普通未壓縮的原始數(shù)據(jù),另一種就是采用了ADPCM壓縮了的。無(wú)論哪一種,你都可以使用現(xiàn)存的播放器播放。未壓縮的存儲(chǔ)格式比較簡(jiǎn)單,只需要一個(gè)format chunk來(lái)描述格式信息,然后再用一個(gè)data chunk來(lái)存儲(chǔ)數(shù)據(jù)?,F(xiàn)在的wave文件按規(guī)定都必

9、須包括一個(gè)fact chunk,而且在fmt chunk里必須包含一個(gè)擴(kuò)展了的format description,這通過(guò)一個(gè)WAVEFORMATEX的結(jié)構(gòu)來(lái)描述,但是以WAVE_FORMAT_PCM為格式的文件并不需要這些額外的信息。下面是WAVEFORMATEX的定義typedef struct waveformat_extended_tag WORD wFormatTag;/* format type */WORD nChannels;/* number of channels (i.e. mono, stereo.) */DWORD nSamplesPerSec; /* sample

10、rate */DWORD nAvgBytesPerSec; /* for buffer estimation */WORD nBlockAlign;/* block size of data */WORD wBitsPerSample;/* Number of bits per sample of mono data */WORD cbSize; /* The count in bytes of the extra size */ WAVEFORMATEX;其中wFormatTag標(biāo)明了文件的類型,這樣我們就可以判斷后面的數(shù)據(jù)是以什么方式來(lái)存儲(chǔ)和表示的了,比如,#define WAVE_FOR

11、MAT_PCM 0x0001 這樣,WAVE_FORMAT_PCM表示的就是普通的原始wav文件格式。再比如,#define WAVE_FORMAT_ADPCM 0x0002 我們就可以知道,wFormatTag的值為WAVE_FORMAT_ADPCM就是以ADPCM壓縮的格式了。具體的文件的類型有很多種,詳細(xì)的定義可以在mmreg.h頭文件里找到。WAVEFORMATEX是所有的format所共有的一個(gè)頭部,不同格式會(huì)在后面添加自己的相關(guān)的數(shù)據(jù)段,添加的段的字節(jié)數(shù)可以通過(guò)cbSize來(lái)得到。cbSize用來(lái)描述不同的格式后面添加的多余的字節(jié)數(shù)。比如WAVE_FORMAT_ADPCM格式的fo

12、rmat的這個(gè)值就是32,表明還有32個(gè)字節(jié)在后面。另外一些字段會(huì)在后面解釋。fact chunk是一個(gè)值得注意的chunk,現(xiàn)在的wav文件,無(wú)論是否壓縮,都必須包含一個(gè)fact chunk,用來(lái)存儲(chǔ)文件文件相關(guān)的信息。但是現(xiàn)在它里面只定義了一個(gè)字段,用來(lái)指出文件里一個(gè)有多少個(gè)sample。4. WAVE_FORMAT_ADPCM 的wav文件格式再回到我們前面討論的DPCM,對(duì)于預(yù)測(cè)后得到的差值diff,我們應(yīng)該怎么處理它才能的比較好的壓縮比?比如我們的數(shù)據(jù)是3,3,4,7,9,2. 可以注意到,如果預(yù)測(cè)做的比較好的話,得到的差值可能會(huì)很小,甚至為0,假設(shè)我們的原始的音頻數(shù)據(jù)時(shí)16位的,那

13、么,如果仍然使用16位來(lái)存儲(chǔ)這些數(shù)據(jù),肯定是一種浪費(fèi)。很直觀的,你會(huì)想到減少每一個(gè)diff的存儲(chǔ)空間,沒(méi)錯(cuò),這就是ADPCM格式壓縮的wav文件采用的方法。在壓縮過(guò)的wav文件里,每一個(gè)diff使用4個(gè)bit來(lái)存儲(chǔ)的,被稱作一個(gè)nibble。這樣,我們將一個(gè)16bit的原始數(shù)據(jù)縮減到4bit,可以得到一個(gè)穩(wěn)定的4:1的壓縮比。因?yàn)槲覀儾捎玫氖穷A(yù)測(cè)編碼,這就需要選擇預(yù)測(cè)的系數(shù)a和b,我們?cè)谇懊嬉呀?jīng)詳細(xì)的推導(dǎo)過(guò)了a和b的計(jì)算方法?,F(xiàn)在,我們需要解決的是,一個(gè)wav文件,我們是對(duì)整個(gè)文件計(jì)算來(lái)得出合理的a和b嗎?顯然,對(duì)整個(gè)文件采用相同預(yù)測(cè)系數(shù)并不實(shí)際,首先是計(jì)算起來(lái)麻煩,再一個(gè),一個(gè)wav文件太長(zhǎng)

14、,如果對(duì)整個(gè)文件采用相同的a和b起不到什么效果,對(duì)于局部的數(shù)據(jù),偏差仍然會(huì)是很大,這就喪失了我們的初衷。不妨這么考慮,我們將音頻數(shù)據(jù)分成不同的塊,分別對(duì)每一塊求不同的系數(shù),來(lái)進(jìn)行預(yù)測(cè)編碼,一般聲音都是連續(xù)的,在一個(gè)局部的小區(qū)域里變化很小,所以a和b就能很準(zhǔn)確的預(yù)測(cè)出每一個(gè)值了。在apple下系統(tǒng)下,每一個(gè)塊稱作一個(gè)packet,以64個(gè)sample為固定的大小。而在windows下被稱作一個(gè)block,他的大小是可變的,所包含的sample的個(gè)數(shù)由nSamplesPerBlock來(lái)指出,后面我們會(huì)看到. 在WAVEFORMATEX結(jié)構(gòu)里的nBlockAlign描述了每一個(gè)block所占的字節(jié)數(shù)

15、.不同的采樣率會(huì)有不同的大小,下面是blockAlign在不同采樣率大小下的值nSamplesPerSec x ChannelsnBlockAlign8k25611k25622k51244k1024這樣,我們可以把壓縮后的數(shù)據(jù)以block為單位存儲(chǔ)在data chunk里.但是,除了壓縮的數(shù)據(jù)以外,我們同樣還需要存儲(chǔ)當(dāng)前塊的a和b系數(shù)的值.下面是ADPCM格式的format chunk的具體定義 typedef struct adpcmcoef_tag int iCoef1;int iCoef2; ADPCMCOEFSET;typedef struct adpcmwaveformat_tag

16、WAVEFORMATEX wfxx;WORD wSamplesPerBlock;WORD wNumCoef;ADPCMCOEFSET aCoeffwNumCoef; ADPCMWAVEFORMAT;這下子就很清楚了,ADPCMCOEFSET里的兩個(gè)正是我們的系數(shù)a和b,ADPCMWAVEFORMAT擴(kuò)展了WAVEFORMATEX的結(jié)構(gòu),添加了一些列自有的信息,wSamplesPerBlock表明了每一個(gè)block里含有多少個(gè)sample,而wNumCoef說(shuō)明了后面的系數(shù)表的大小.微軟定義了一個(gè)7個(gè)的標(biāo)準(zhǔn)的系數(shù)表,當(dāng)然,你也可以在后面添加自己的系數(shù),下面是他的定義:Coef SetCoef1C

17、oef20 256 01 512 -2562 0 03 192 644 240 05 460 -2086 392 -232每一個(gè)coef是使用定點(diǎn)數(shù)來(lái)表示的,這樣是為了方便存儲(chǔ)和加快編解碼的速度,使用的時(shí)候需要把它除以256得到實(shí)際的值可以通過(guò)我們前面的方法算出來(lái)a和b,然后再在這里找出和a和b最近的一組數(shù). 因?yàn)橥ǔG闆r下,音頻文件的數(shù)據(jù)量是相當(dāng)大的,如果對(duì)每個(gè)樣本都算出最優(yōu)的a和b,他們的存儲(chǔ)就會(huì)占相當(dāng)大的空間, 如果我們只用這七個(gè),可以把他們放在文件頭里的一個(gè)表里面,然后對(duì)每一個(gè)block只需要存儲(chǔ)他們最近的系數(shù)在表里的索引值就行了. ADPCMWAVEFORMAT里的aCoeff存儲(chǔ)的

18、就是這個(gè)系數(shù)表.ADPCM壓縮格式存儲(chǔ)的wav文件,一般包含三個(gè)chunk,一個(gè)是 format chunk,就是我們上面的那個(gè)ADPCMWAVEFORMAT結(jié)構(gòu). 接著會(huì)有一個(gè)fact chunk,這是必不可少的,現(xiàn)在它里面只有一個(gè)字段,就是整個(gè)文件含有的sample的個(gè)數(shù).接下來(lái)是最重要的data chunk, 它里面存儲(chǔ)的就是我們的數(shù)據(jù),里面是一個(gè)block接一個(gè)block存儲(chǔ)的。一般block由三部分組成,分別是header,data,padding。header的定義:typedef struct adpcmblockheader_tag BYTE bPredictornChanne

19、ls;int iDeltanChannels;int iSamp1nChannels;int iSamp2nChannels; ADPCMBLOCKHEADER;bPredictor就是我們前面說(shuō)過(guò)的系數(shù)表的索引值。如果文件的channel不止一個(gè),那么不同的channel就挨個(gè)向后排。channels12stereo_ _| left| right|_|_|123_ _ _| left| right| center|3 channel|_|_|_|1234_ _ _ _| front| front| rear| rear|quad| left| right| left| right|_|_|

20、_|_|1234_ _ _ _ _| left| center| right| surround |4 channel|_|_ _|_|_|123456_ _ _ _ _ _| left| left| center| right| right|surround |6 channel| center| center|_|_|_|_|_|_ADPCMBLOCKHEADER結(jié)構(gòu)里的iDelta是iDelta的初始值。iSample1和iSample2是用來(lái)預(yù)測(cè)后面數(shù)據(jù)的初始的兩個(gè)samplevalue。需要注意的是,iSample1實(shí)際上是第二個(gè)sample的值,而iSample2則是第一個(gè)。這樣做

21、是為了方便編解碼。header后面緊接著就是數(shù)據(jù)了。data里面是4bit接4bit的sample數(shù)據(jù)。如果存儲(chǔ)的數(shù)據(jù)沒(méi)有到整整一個(gè)block,那么就要在最后存一系列的0來(lái)使整體大小填滿整個(gè)block,這被叫做padding5. 編碼和解碼首先要說(shuō)明的是,我們通過(guò)預(yù)測(cè)之后的到的diff,需要再除上一個(gè)iDelta的比例因子,得到的值就是我們要存儲(chǔ)的結(jié)果。這個(gè)值一般被稱作 iErrorDelta,他一般是一個(gè)可正可負(fù)的有符號(hào)數(shù)。因?yàn)槲覀冃枰堰@個(gè)iErrorDelta存儲(chǔ)到一個(gè)nibble里,需要對(duì)他作一定的裁剪,因?yàn)橐粋€(gè)nibble是4bit的,如果用補(bǔ)碼表示,他的范圍從-8到7,很明顯,我們

22、的iErrorDelta只要大于7或者小于-8就都得用7或-8 來(lái)表示,這樣就喪失了一些精度。不過(guò)這些損失是很少的,因?yàn)槿绻覀兊念A(yù)測(cè)和iDelta比較好的話,大部分的iErrorDelta都會(huì)落在-8到7之間。即使喪失一點(diǎn)點(diǎn)音質(zhì),人的耳朵基本上聽(tīng)不出來(lái),可以忽略它的影響。每次產(chǎn)生新的iErrorDelta之后,都要根據(jù)iErrorDelta的值對(duì)iDelta的值進(jìn)行更改。以使得iDelta能夠自動(dòng)適應(yīng)sample 的變化。因?yàn)橐粋€(gè)iErrorDelta被限定到4bit,我們就完全可以做一個(gè)16項(xiàng)的表來(lái)表示它。下面的這個(gè)就是microsoft的標(biāo)準(zhǔn)的 adaptation tableint A

23、daptationTable = 230, 230, 230, 230, 307, 409, 512, 614,768, 614, 512, 409, 307, 230, 230, 230 ;好了,我們現(xiàn)在已經(jīng)把一切前提工作都做完了,下面就是具體的編碼及解碼步驟了,因?yàn)榫幗獯a對(duì)于每一個(gè)block都是相同的,我們僅僅使用一個(gè)block來(lái)說(shuō)明。編碼:對(duì)每一個(gè)block,編碼的過(guò)程是通過(guò)下面的幾個(gè)步驟進(jìn)行的確定需要使用的系數(shù)predictor確定初始的iDelta值輸出block header編碼并輸出數(shù)據(jù)其中predictor的確定已經(jīng)在開(kāi)頭部分詳細(xì)的描寫了。我們只要找出與a和b最相近的系數(shù)表的索

24、引值就行了。初始的idelta的值確定有很多種,你可以對(duì)每一個(gè)block都使用相同的iDelta值。也可以通過(guò)開(kāi)始的幾個(gè)數(shù)據(jù)來(lái)估計(jì)iDelta,比如,通過(guò)算出第一個(gè)sample的預(yù)測(cè)值跟實(shí)際值之間的diff,可以使用diff/4來(lái)表示iDelta,這樣iErrorDelta的值就能剛好被限制在-8到 7的比較靠中間的位置每一個(gè)block的初始iDelta的值也可以使用前一個(gè)block的最后一個(gè)iDelta的值來(lái)確定。不過(guò)需要注意,第一個(gè)block的初始iDelta的值需要單獨(dú)考慮。當(dāng)predictor和初始的iDelta確定之后,block header就可以寫出了。首先將每一個(gè)channel

25、的predictor輸出再將每一個(gè)channel的iDelta輸出接著將16bit的第二個(gè)sample的PCM值輸出(iSample1)最后將16bit的第一個(gè)sample的PCM值輸出(iSample2)下面就是對(duì)剩下的數(shù)據(jù)編碼了。如果block里還有sample尚待編碼/ 通過(guò)前兩個(gè)sample預(yù)測(cè)下一個(gè)sample的值lPredSamp = (iSamp1 * iCoef1) + (iSamp2 *iCoef2) / 256/ 計(jì)算iErrorDeltaiErrorDelta = (Sample(n) - lPredSamp) / iDelta如果iErrorDelta大于7,把它設(shè)成7

26、如果iErrorDelta小于-8,把它設(shè)成-8把iErrorDelta作為一個(gè)nibble輸出/算出使用iDelta和iErrorDelta預(yù)測(cè)得到的新的sample的值 lNewSamp = lPredSample + iDelta * iErrorDelta把lNewSamp限定到16bit所允許的大小/調(diào)整iDelta的值iDelta = iDelta * AdaptionTable iErrorDelta / 256把iDelta限定到16bit所允許大小的范圍內(nèi),并確保它不為0/更新預(yù)測(cè)用的兩個(gè)sample的值iSamp2 = iSamp1;iSamp1 = lNewSample.

27、重復(fù)上面的過(guò)程,直到block里沒(méi)有需要再編碼的sample解碼實(shí)際上就是上述過(guò)程的逆過(guò)程。如果你把上邊的編碼過(guò)程搞明白了,解碼的過(guò)程就很簡(jiǎn)單,這里就不詳細(xì)說(shuō)了。上面就是它的整個(gè)過(guò)程,如果你還有什么不明白,可以給我發(fā)郵件: 下面是相關(guān)的一些鏈接,可以參考一下。UnderstandingTheDifferencesBetweenAppleAndWindowsIMA-ADPCM Compressed Sound Files:/technotes/tn/tn1081.htmlADPCM reference impl

28、ementation:ftp:/ftp.cwi.nl/pub/audio/adpcm.tar.gz這個(gè)描述的比較詳細(xì)一點(diǎn):/program/FORMAT/windows/wavec.htmlibsndfile:.au/erikd/libsndfile/SoX Sound eXchange:WAVE File Format:/jglatt/tech/wave.htm /courses/

29、422/projects/WaveFormat/后面附帶上我寫的一個(gè)對(duì)8000采樣率,單聲道16位的wav格式壓縮成ADPCM的代碼 .#include #include #include #include int AdaptationTable = 230, 230, 230, 230, 307, 409, 512, 614,768, 614, 512, 409, 307, 230, 230, 230;typedef struct _ADPCM_COEF_SETshort coef1;short coef2;ADPCM_COEF_SET;ADPCM_COEF_SET CoeffTable =

30、 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 _RIFFWAVECHUNKDWORD id;DWORD size;DWORD format;RIFFWAVE_CHUNK;typedef struct _WAVEFORMATEXWORD wFo

31、rmatTag;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_C

32、HUNK;typedef struct _MICROSOFT_ADPCM_FORMAT DWORD id;DWORD size;WAVEFORMAT_EX format;WORD wSamplesPerBlock;WORD wNumCoef;ADPCM_COEF_SET coeffs7;MICROSOFT_ADPCM_FORMAT;typedef struct _DATA_CHUNKDWORD id;DWORD size;BYTE data1;DATA_CHUNK;typedef structDWORD id;DWORD size;DWORD nSamples;FACT_CHUNK;typed

33、ef structDWORD id;DWORD size;CHUNK;typedef structBYTE predictor;short iDelta;short iSample1;short iSample2;BYTE pNibbles1;BLOCK;#pragma pack(pop)class Wavfilestd:vector chunks;char* pEncoded;int totalSize;int curSize;public:Wavfile(const char* path);int encode();int Wavfile:writeEncodedFile(char* pa

34、th);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;ilen;+i )alpha += (double)pdatai-1*pdatai-1; beta += (double)pdatai-1*pdatai-2; gama += (double)pdatai-2*pdatai-2; m += (double)pdatai*pdatai-1; n

35、+= (double)pdatai*pdatai-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;isizeof(CoeffTable)/sizeof(CoeffTable0); +i)int dx = (Coe

36、ffTablei.coef1-coeff.coef1); int dy = (CoeffTablei.coef2-coeff.coef2);if( dx*dx+dy*dy 7 )c = 7;if( c-8 )c = -8;if( c= totalSize )totalSize = (size+totalSize)*2;pEncoded = (char*)realloc(pEncoded,totalSize);memcpy(&pEncodedcurSize,p,size);curSize += size;DATA_CHUNK* getDataChunk()for(int i=0;ichunks.

37、size();+i)if( *(DWORD*)(chunksi)=0x61746164 )return (DATA_CHUNK*)(chunksi);return NULL;FORMAT_CHUNK* getFormatChunk()for(int i=0;ichunks.size();+i)if( *(DWORD*)(chunksi)=0x20746d66 )return (FORMAT_CHUNK*)(chunksi);return NULL;Wavfile()for(int i=0;igetDataChunk(); ADPCM_COEF_SET coeff;int len = pChun

38、k-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 = &CoeffTableindex;pbuff-iSample2 = *p+;pbuff-iSample1 = *p+;short iDelta = (pCoeff-coef1*pbuff-iSample1 +pCoeff-coef2*p

39、buff-iSample2)/256 - *p;iDelta /= 4;if( iDeltaiDelta = iDelta;pbuff-predictor = index;short iSample1 = pbuff-iSample1;short iSample2 = pbuff-iSample2;int flag = 0;BYTE bytebuff = 0;int cnt = 0;while( pcoef1*iSample1 + pCoeff-coef2*iSample2)/256;char iErrorDelta = (*p - iPredSamp)/iDelta; int remaind

40、er = (*p-iPredSamp)%iDelta; if( remainderiDelta/2 ) +iErrorDelta;if( iErrorDelta7 )iErrorDelta = 7;if( iErrorDelta-8 )iErrorDelta = -8;short iNewSample = iPredSamp + iErrorDelta*iDelta;iDelta = iDelta * AdaptationTabletrimToNibble(iErrorDelta)/256;if( iDelta1 )iDelta = 1;iSample2 = iSample1;iSample1

41、 = iNewSample;+p;if( !flag )flag = 1, bytebuff = trimToNibble(iErrorDelta);elseflag = 0;bytebuff = (bytebuffpNibblescnt+ = bytebuff; if( !(cnt249) )addBlock(char*)pbuff,256);cnt = 0;if( !(pcalculateCoefficient(coeff,p,500);index = this-getClosestCoefficientIndex(coeff); pCoeff = &CoeffTableindex; pbuff-predictor = index; pbuff-iDelta = iDelta;pbuff-iSample2 = *p+;pbuff-iSample1 = *p+;iSample1 = pbuff-iSample1;iSample2 = pbuff-iSample2;if( cnt249 )while( cntpNibblescnt+ = 0;addBlock( (char*)pbuff,256 );ret

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論