這篇文章是系列文章的第2篇。第一篇在這里聲波配網(wǎng)原理。
在聲波傳輸?shù)陌l(fā)送端,我們要做的事情用下面這張圖就可以概括:
也就是通過三步,我們就可以把我們要傳輸?shù)奈谋拘畔⒆兂陕曇舭l(fā)送出去谷婆。
下面我們來一步一步的看:
1.從字符到數(shù)組角標(biāo)的映射:
這一步可以看成是第二步的預(yù)處理,從字符到頻率映射的一個過渡辽聊。把字符對應(yīng)的頻率存儲在一個叫FREQUENCIES的數(shù)組中:
FREQUENCIES {1760,1810,1870,......}
因為默認是支持ASCII碼字符纪挎,而鍵盤能輸入的字符其實只在32到127之間,所以把這96個字符映射到FREQUENCIES數(shù)組中角標(biāo)0~95的頻率跟匆。而我們在用Base64規(guī)則轉(zhuǎn)碼中文字符時也只需要用到這96個字符中的(0-9,A-Z,a-z异袄,+,-,=)。所以其實用來傳遞信息的數(shù)據(jù)區(qū)的話贾铝,數(shù)據(jù)區(qū)域有96個頻率就足夠了隙轻。
關(guān)于重復(fù)標(biāo)志和順序標(biāo)志的使用,在后面的文章之進一步優(yōu)化-提高傳輸速率中會提到垢揩,暫時先忽略~~~
開始標(biāo)志:需要一個信號告訴我們的接收端在什么時候可以開始解析了玖绿,同時這個標(biāo)志還有一個重要的作用->對齊音節(jié),這個作用在寫解碼的時候會詳細的描述叁巨。
結(jié)束標(biāo)志:需要一個信號告訴我們的接收端本次傳輸結(jié)束斑匪。
2.根據(jù)角標(biāo)查找頻率:
這個不用蠢作者多說了吧~數(shù)組查詢O(1)~沒毛病
3.把頻率變成正弦波音頻信號:
建立字符和頻率的一一映射關(guān)系之后,如果我們想發(fā)出”單頻率”的聲音,就需要自己構(gòu)造特定頻率的正弦函數(shù)蚀瘸。
1)正弦波生成公式:
energy =
這個是蠢作者采用的正弦波生成公式狡蝶,其中frame是采樣點的位置,sample_rate是采樣率(44100Hz),frequency是需要生成正弦波的頻率贮勃√叭牵回憶一下高中數(shù)學(xué),這個正弦波的周期應(yīng)該是:T=sample_rate/frequency寂嘉。
正弦波的頻率F是:F=2*pi*frequency/sample_rate
所以解碼端通過快速傅里葉變換解碼出正弦波的頻率F以后奏瞬,該正弦波攜帶的信息頻率應(yīng)該是frequency = F*sample_rate/(2*pi)。
正弦波公式的選取可以隨意調(diào)整泉孩,保證能正確的逆向解析出其中的信息頻率就好硼端。
MAX_VOLUME可以用來調(diào)節(jié)最后生產(chǎn)的音頻信號的響度(振幅)大小,識別成功率和播放的音頻的響度也有很大的關(guān)系寓搬。
2)將正弦波存成PCM數(shù)據(jù)格式:
有了energy公式珍昨,相當(dāng)于有了從頻域到時域的傳輸門,但要把時域上連續(xù)的聲音信號變成我們的設(shè)備能播放的數(shù)字信號句喷,我們還需要了解兩個基本知識:
NO1.采樣率(sample_rate):
是指每一秒要采集聲音的次數(shù)镣典。因為自然界的音頻信號,例如人說話唾琼,產(chǎn)生的是模擬信號(時間連續(xù)的信號)骆撇。如果我們想把聲音錄制下來的話,并沒有辦法把整個連續(xù)的聲音信號都錄制下來父叙,只能離散的采樣,每隔一段時間采集一次數(shù)據(jù)肴裙,將模擬信號轉(zhuǎn)化成數(shù)字信號趾唱,這樣才能在計算機的數(shù)字世界中存儲。很明顯蜻懦,采樣點的多少大大的影響著錄制音頻記錄聲音信息的多少甜癞,也就是音頻的質(zhì)量。如果采樣點多宛乃,那么質(zhì)量就高悠咱,聽起來就和原聲的差別小征炼;相對的析既,采樣點少,質(zhì)量就次谆奥,聽起來就和原聲不一樣眼坏。
NO2.采樣定理:
既然采樣率高,錄音的質(zhì)量就高酸些,那么宰译,是不是采樣率越高越好呢檐蚜?
當(dāng)然不是啦。
隨著采樣率的提高沿侈,雖然質(zhì)量提高了闯第,但是采樣的難度也對應(yīng)的增加了,而且缀拭,采樣出來的數(shù)據(jù)需要存儲咳短,采樣率越高,產(chǎn)生的數(shù)據(jù)文件就越大智厌,那么在網(wǎng)絡(luò)中傳輸用的時間就越長诲泌。質(zhì)量高的音樂比一般的音樂體積大就是這個原因。
那么采樣率到底設(shè)成多少比較好了铣鹏?
有一個有名的采樣定理“奈奎斯特定理”幫我們解決了這個難題:
如果采樣的頻率高于信號最高頻率的兩倍敷扫,采樣之后的數(shù)字信號就可以完整的保留下原始信號中的信息。
因為人的聽力范圍在20HZ-20000HZ诚卸,所以一般采樣頻率在44.1kHZ葵第,也就是一分鐘44100次。選擇44100Hz的采樣率合溺,肯定能很好的記錄我們的正弦波了卒密。
蠢作者建議,我們字符映射的范圍在人耳聽力的范圍內(nèi)比較好棠赛,因為這樣一般的硬件設(shè)備才能夠播放哮奇,過高或者過低,就不能兼容所有的手機機型或者其他硬件設(shè)備了睛约。當(dāng)然低頻段由于受環(huán)境的噪音干擾比較大鼎俘,也不太建議采用。蠢作者自己用了1700HZ到15000Hz之間的頻率辩涝,寶寶們可以自己調(diào)整贸伐。不要小看這些頻率的選定哈,對識別的成功率影響很大怔揩。因為高頻的低頻分量很可能會干擾我們正確的解碼捉邢。
好啦,知道了數(shù)字世界通過采樣的方式來記錄聲音信息商膊,那么我們怎么把采樣的結(jié)果存儲下來呢伏伐?我選用了PCM文件格式來存儲音頻數(shù)據(jù)。
知識點:
NO1.每個音節(jié)持續(xù)時間(duration)
如果把傳輸一個字符的正弦波看做是一個音節(jié)晕拆,那么每個音節(jié)的持續(xù)時間同樣也影響到我們對聲音信號的記錄和還原秘案。對識別聲波的成功率有著重要的影響。當(dāng)durantion變大時,音節(jié)持續(xù)時間變成,采樣點變多,聲音信號的還原度變高蝗蛙,解析出的音頻中攜帶的頻率信息出錯率變低。同時吼旧,采樣點變多,PCM文件變大未舟,音節(jié)變長圈暗,傳輸過程變長,傳輸速率降低裕膀。
蠢作者選擇了0.1S的持續(xù)時間员串,這個寶寶們可以自己定。
NO2.每個音節(jié)的采樣點unit_sample
我們已經(jīng)選定了采樣率和每個音節(jié)的持續(xù)時間昼扛。很自然的就可以計算出存儲每個音節(jié)信息的采樣點數(shù)目unit_sample = duration * sample_rate寸齐。
在發(fā)送端我們只要把每個采樣點都通過energy公式計算出來,存儲下來就OK了抄谐。
NO3.每個采樣點的存儲方式
那么每個采樣點到底怎么存了渺鹦?需要稍稍了解一下PCM文件格式。
每個采樣數(shù)據(jù)記錄的是振幅,采樣精度取決于儲存空間的大小:
1字節(jié)(也就是8bit)只能記錄256個數(shù),也就是只能將振幅劃分成256個等級;
2字節(jié)(也就是16bit)可以細到65536個數(shù),這已是CD標(biāo)準(zhǔn)了;
4字節(jié)(也就是32bit)能把振幅細分到4294967296個等級,好好好厲害有沒有~~~~~
所以我們在發(fā)送端生成的振幅和接收端錄音收到的振幅大小并不能保證完全一樣蛹含,況且這個值是受播放設(shè)備和錄音設(shè)備兩者之間距離的影響的毅厚,后面我們分析接收端解碼的時候要注意到這一點。
通常我們說的雙聲道(stereo),意味著采樣是雙份的,文件也差不多要大一倍浦箱。PCM中的聲音數(shù)據(jù)是沒有壓縮的吸耿,如果是單聲道的文件,采樣數(shù)據(jù)按時間的先后順序依次存入酷窥。如果是雙聲道的文件珍语,采樣數(shù)據(jù)按時間先后順序交叉地存入。
我們采用16位單聲道的PCM格式存儲就足夠了竖幔,8位的也太粗糙了一點。
由上述energy公式計算出的值是float的是偷,要轉(zhuǎn)成PCM文件讓播放器播放拳氢,需要將float先轉(zhuǎn)成16位的整數(shù):
float frame_value_16 = MAX_SHORT * frame_value_float;
MAX_SHORT= 32767.
在接收端也需要從16位整數(shù)轉(zhuǎn)回float:
float f_value = (float) tempShort[j]/32768.0;
所以大概的從頻率到音頻信號的代碼大概是這樣:
這樣生成的PCM文件,我們可以直接丟給播放器播放蛋铆,也可以寫到本地存儲馋评,寫到本地存儲的應(yīng)用場景是,由服務(wù)器生成一段攜帶文本信息的音頻刺啦,然后客戶端拉取之后播放留特。
好啦~~~~聲波傳輸編碼的過程就是這樣啦~~~比較簡單~~~
我要用洪荒之力寫解碼的過程啦~
------------
喜歡的話記得點個喜歡奧~
筆芯