1. http://www.leiphone.com/news/201406/record.htmlphp
本文做者是科通芯城的何順義工程師。html
想必你們都有這樣的經歷:接到朋友從火車站、地鐵、會場、KTV等場合打來的電話,有時候很難聽清楚,有時候卻聽得很清晰。這是爲何?android
一般咱們會認爲是對方信號不穩定,因此通話質量有好有壞。其實否則,這種環境下可否聽清對方講話,主要取決於對方手機錄音和降噪功能的優劣。同時,這也是高端手機和普通手機的一個重要區別。git
任何功能的差異,歸根到底,都是硬件和軟件的差異。在本文中,筆者將花較長的篇幅和網友們分享一下手機的錄音、降噪的原理;所須要的硬件、算法;以及不一樣的硬件、算法,在使用體驗上的差異。但願對你們能有些幫助。程序員
首先說一下爲何要強調手機的錄音功能。算法
很簡單,手機是用來通話的。通話的過程,首先要把說話的人的聲音錄下來,而後聽者才能夠聽獲得。因此,錄音功能對於通話,是基礎而重要的。數據庫
對於手機的錄音過程,簡單地講,須要通過三個階段,兩個環節。三個環節是:「聲音——模擬電信號——數字電信號」。兩個環節是:「麥克風」和「ADC(analog digital converter/數字模擬轉換器)」。麥克風負責把「聲音」轉化爲「模擬電信號」,ADC負責把「模擬電信號」轉化爲「數字電信號」。因此說,麥克風和ADC的品質直接決定錄音功能的品質。編程
麥克風你們比較熟悉,這裏再也不贅述,主要講一下ADC。api
如何衡量一個ADC的品質?簡單點講,看兩個參數:採樣速度和量化位數。什麼是採樣速度和量化位數?能夠這麼理解,採樣速度表明速度,而量化位數表明精度。這兩個數值都是越大越好。數組
那麼,怎麼知道手機中ADC的「採樣速度」和「量化位數」呢?辦法是有的:
先下載一個叫「RecForg」的免費APP,安裝運行以後,找到「設置」菜單,進入後界面以下圖所示▼
上圖中,有兩個紅色方框:「採樣率」和「音頻格式」。這兩個子菜單分別對應ADC的「採樣速度」和「量化位數」。
能夠看出,有三個檔位是灰色不可選的:12kHz、24kHz、 48kHz。而其它全部檔位均可以選擇。這說明筆者手機ADC的「採樣速率」有5個檔位,最高爲44kHz。同時,筆者也測試過朋友的小米2,發現其最高的採樣速率是48kHz。這說明小米2使用的ADC要比筆者手機的ADC高一個等級。
在「設置」菜單界面,點擊「音頻格式」子菜單進入以後,會看到下圖▼
上圖說明,筆者手機的ADC的「量化位數」是16位。
很簡單吧?須要說明的是,筆者發現APP「RecForg」只在android平臺手機上能夠找到,而在IOS裏是沒有的。若是你們想查看Iphone的ADC的參數,能夠嘗試找一些相似的錄音軟件,碰碰運氣,說不許會有發現呢。
在「錄音過程和硬件」部分,講到了錄音須要的硬件,以及硬件性能對於錄音質量的影響。
若是在安靜的環境中,軟件對於通話的影響並不大。然而,手機是移動通訊設備,通話場景不肯定,極可能是在嘈雜環境中的。在這種狀況下,降噪算法對於通話質量就相當重要了。
降噪是怎麼回事?簡單點說,就是經過算法,從接收到的聲音中分離出人聲和噪聲,把人聲增強,把噪聲抑制,從而提升通話質量。道理很簡單,但在具體實現上,算法很是複雜,各手機公司通常都不會本身作降噪算法,而是採用相關專業公司的方案。
說到降噪,不得不提audience公司。這是一家專門從事移動通訊音頻技術的全球領導公司,通俗點說,就是作音頻降噪算法的公司。蘋果、三星、HTC、Google、LG、華爲、夏普、魅族、小米等都是audience的客戶,若是要列舉採用audience芯片的機型,將會是一張很是長的名單。
那麼,不一樣的降噪算法,體現用戶體驗上,會有什麼區別呢?
咱們能夠在嘈雜的環境中,能夠進行兩種試驗。(一)、在嘈雜環境中,使用「免提通話」,對方能夠聽很清楚的條件下,說話者和手機的最大距離是多遠?(二)、在嘈雜環境中,手機能夠語音識別的最大距離是多遠?筆者測試過一些高端手機和普通手機,結果差異還蠻大。你們若是有興趣,也能夠試一試。
上面是從體驗方面來講降噪性能。那麼除了主觀感覺,是否能夠有一個客觀的、直觀的展示呢?答案也是確定的。見下圖▼
上圖是iphone4s和小米2播放通道的頻率響應曲線。能夠明顯地看出,iphone4s在低頻(<80Hz)和高頻段(>1.4Hz)都作了相應的降噪處理,只保留和人聲頻段。而小米2只在高頻段有降噪處理。這也說明和iphone4s相比,小米在一些細節上仍是有必定提高空間。
2. http://blog.163.com/l1_jun/blog/static/143863882013517105217611/
前文書我們說到IOS下如何錄製一個wav格式的音頻,然而如今的狀況確實安卓不支持wav格式,因而有看官說了,你個二百五,就不能選個安卓支持的格式錄製麼,我很負責任的說,蘋果和谷歌掐架,苦的就是咱們這幫苦逼的技術人員。。。安卓的格式蘋果全不支持,看好是全不,不是所有,反過來蘋果的格式,安卓也不慣着。。。。
固然上有政策下有對策是萬年不變的真理,Ios與安卓的音頻互通是難不倒咱們偉大的程序員的,而目前解決這個問題方案有不少種但大體如下3種方式,且聽我細細道來。
第一種方案對於服務器負荷較大,不管是安卓端亦或是IOS端都將音頻傳輸到服務器,經過服務器進行轉換再進行轉發。這種作法能夠不受系統限制,可是信息量較大時對服務器負荷較大,對服務器端的要求很高。據傳聞,微信就是採用這種方式進行的語音IM交互
第二種方案是不論IOS端仍是安卓端都統一使用相同的第三方音頻庫進行編解碼處理,而後再進行網絡傳輸,優勢是可供選擇的音頻庫很是多,能夠根據本身不一樣的需求選擇各類各樣的音頻格式,可是由於不管是IOS端仍是安卓端都須要對其進行i編碼解碼處理,而項目初期並無設計這方面的需求因此若是雙端都進行修改修改量實在太大。一樣據傳聞,同爲語音IM的成熟案例微米就是依靠Speex的三方開源庫來完成的,這種格式體積小,能降噪,是目前比較受推崇的方式。
我採用的是第三種方式,amr格式的音頻文件是安卓系統中默認的錄音文件,也算是安卓支持的很方便的音頻文件,IOS系統曾經是支持這種格式的文件,自4.3之後才取消了對amr的支持(緣由應該不須要我多說。。。),可見,amr格式的音頻文件並不是IOS處理不了的,由於有了這樣的概念和潛意識的植入,我就開始一門心思在網絡上找尋各類各樣的實例以及demo,我要作的就是把問題儘可能都解決在IOS端。終於功夫不負有心人,最終讓我得以成功的在IOS端成功的轉換出安卓端可使用的amr文件。接下來,咱們就說說如何在IOS端完成wav與amr文件的互轉。
首先推薦給大夥提供一個demo在下面的鏈接下載。此demo轉載自中國開源社區,本人發自心裏的向發佈者Jeans大人致以最崇高的敬意。
http://www.oschina.net/code/snippet_562429_12400
demo下載打開項目後將以下四個源碼文件以及兩個庫文件拖入本身的項目,引用AudioToolbox.framework、CoreAudio.framework以及AVFouncation.framework便可完成類庫的導入
打開咱們導入的頭文件就會發現有又大量的struct,而在開啓ARC項目中是禁止使用struct和union的,而咱們的項目確實能夠開啓ARC的,這裏涉及到一個知識點,以前也在網絡上看到有人提問在開啓ARC後改如何使用struct,我也是接觸這個項目以後開始涉及混編才瞭解該如何解決這個問題, 只要將Compile Sources As(設置編譯源)的設置爲Ojbective-C++或者將包含到聲名struct和union頭文件的實做文件的擴展名改成.mm就能夠在項目中使用struct和union了,可是請注意此時你編寫的代碼再也不是純粹的Objective-C語言了,而是涉及到Objective-C++,此處涉及到混編的問題,咱們再後面還會再講解混編相關的內容,但並不會不少,感興趣的看官能夠本身查找資料。回到原題,若是在導入文件後遇到了編譯錯誤,請點擊項目的TARGETS下的Build Settings找到如下編譯設置並按照圖內容修改
注意,若是是新建空項目Compile Sources As的設置在According to File Type(依照文件類型選擇編譯源)的模式下應該也能夠正常編譯,儘可能不要設置爲Ojbective-C++進行編譯,我是由於項目中含有其餘的SDK須要用到因此才如此設置,一旦設置成Ojbective-C++會和咱們以後講的網絡傳輸篇中所使用的SDK產生必定衝突很那解決。因此此最好保持According to File Type。
文件正常導入以後就能夠直接使用轉換方法了,和常規的SDK不一樣,這個庫並不是以累的形式封裝的,而是數個功能函數,因此並不須要咱們去構造對象,接下來咱們說一下轉換時具體用到的方法,雖然這些方法簡單易用,可是我仍是願意爲你們提供一點便利,所謂幫人到底送佛送到西,下面我每個方法的名稱、功能、參數說明以及使用示例貼出以供你們參考~。
哦~對了不要忘記,咱們的第一步永遠都是導入頭文件
#import 「amrFileCodec.h」;
接下來咱們開始第一個函數EncodeWAVEFileToAMRFile從函數名稱中就可看出,此方法是將WAV轉換爲AMR文件的,咱們先來看一下示例
參數列表也並非很複雜4個參數分別問:1.WAV的文件地址,2.AMR的文件地址,3.音頻通道數,也就是咱們上篇文章中所提到錄製音頻的最後一個參數,聲道數量。4.編碼位數,一樣在上一篇文章中咱們也已經介紹過再也不贅述。
接下來第二個函數,DecodeAMRFileToWAVEFile這個參數與前一個功能正好相反,是從amr轉換爲WAV,下面是具體代碼示例
這個參數能夠說較上一個更加簡單,第一個參數是須要一個AMR的文件地址也就是源,第二個參數則是目標地址也就是一個WAV文件的地址,簡單的兩個參數就可完成調用了。須要注意的是,此處所使用的地址和以前咱們再使用AVFouncation的時候又不一樣了,它既不是要NSString的字符串,也不是NSURL對象而是一個const char的指針,可是這並非問題,實例代碼中所轉換的方法並非最簡的只是急於演示因此拖拽出來的,但願有心的看官能夠自行過濾,過眼不過心是編程大忌。
相對於導入能夠說使用的方法簡單的一塌糊塗,並不須要咱們多少功夫,也沒有那麼高深莫測,可是測試仍是要下必定功夫的,通過實機檢測IOS下錄製出的WAV轉換爲AMR以後放到安卓平臺能夠正常播放,而安卓錄製的AMR文件拿到IOS下轉換出WAV同樣能夠播放徹底沒有任何問題。可是這個方法也是有必定的弊端,音頻轉換的速度較慢,若是是時間較長的音頻文件轉換起來會有短期頓卡,可是用來實現語音IM聊天是徹底能夠知足的
至此咱們本地音頻處理篇的內容所有完結,也算是告一段落,可是咱們如今只是在本地機器上實現了正確的音頻轉換以及播放,想要完成語音IM聊天咱們還差關鍵的環節就是與服務器的交互,詳細的內容,咱們將在下一篇文章中介紹,盡請關注IOS、安卓IM語音聊天開發初探部分心得——異步Socket傳輸篇
3. http://bbs.csdn.net/topics/330148955
4. http://blog.sina.com.cn/s/blog_4b55f6860101e5an.html
語音識別開源SDK
1.什麼是OpenEars
OpenEars是面向iOS平臺的一個離線的語音識別和text-to-speech(文字語音轉換)開發工具包。由於是離線的,它無需象Siri那樣須要和服務器進行網絡鏈接。固然,還要強調一點的是,OpenEars主要是針對英語的。最重要的是,它是免費的。除了基本的免費功能,它還提供了能夠用來擴展基本功能的付費插件,也即Politepix OpenEars插件。
使用OpenEars,能夠在iPhone和iPad應用中輕鬆實現英語的語音識別和TTS(語音合成)功能,並可以使用開源的CMU Pocketsphinx,CMU Flite,CMUCLMTK類庫。
OpenEars 平臺也是一個完整的開發平臺,其中包含了免費的OpenEArs SDK,以及一些拓展的功能插件(付費)。
考慮到我朝開發人員多數是屌絲出身,這裏先介紹免費的SDK,等你們熟悉了以後再自行探索付費功能插件。
對於iPhone本地應用來講,要實現高精確度的大容量詞彙識別目前來講是很是困難的,即使是Siri也須要利用強大的服務器數據庫來完成這一任務。不過Pocketsphinx(OpenEars所使用的開源語音識別引擎)可以作到在iPhone本地應用中根據環境和其它因素來識別英語詞彙。
當前OpenEars的最新版本是1.2.5,下載地址:http://www.politepix.com/wp-content/uploads/OpenEarsDistribution.tar.bz2
2.OpenEars的功能特性
OpenEars目前有如下的功能特性:
1. 在後臺線程中連續監聽,並根據須要暫停或繼續語言處理,而這些操做在iPhone4中僅佔用4%的CPU(包括語言解碼,語音合成)。
2. 支持9種語音類型,包括男性和女性,速度和質量在必定的範圍內,並可在使用的過程當中更改。
3. 能夠更改語音合成的音高,音速和變化。
4. 判斷當前耳機是否在插孔中,而後僅當耳機在插孔中時才繼續語言識別。
5. 支持藍牙語音設備(實驗中)。
6. 語音識別和語音合成的結果能夠被當前應用的任一類所共享
7. 支持JSGF語法
8. 根據NSArray或NSString中的輸入來動態生成新的ARPA語言模型
9. 動態切換ARPA語言模型或JSGF語法
10. 測試已有的錄音
11. 能夠經過標準的Objective-C方法進行交互
12. 全部的語音識別和語音合成功能均在內存中完成,無需寫入到音頻文件中再讀取。
13. 包裝在一個Cocoa標準風格的框架中
注意:
在使用OpenEars的時候,儘可能直接在設備上測試應用,在模擬器上的識別精度會有所降低。
此外,在Xcode4.5中蘋果已經刪除armv6架構編譯。若是須要爲armv6設備編譯,可使用OpenEars以前的舊版本,但該版本不會繼續更新,也沒法用於編譯armv7s設備。http://www.politepix.com/wp-content/uploads/OpenEarsDistributionLegacy.tar.bz2
3.OpenEars的安裝和使用
(1)首先下載框架:
http://www.politepix.com/wp-content/uploads/OpenEarsDistribution.tar.bz2
(2)在Xcode中建立本身的應用,並添加AudioToolbox和AVFoundation框架。
(3)將所下載壓縮包中的Frameworks文件夾拖到項目中
接下來呢?~如今就已經能夠開始使用OpenEars了。
爲了熟悉它的基本功能,能夠先嚐試運行示例項目。由於示例項目支持ARC,因此最好使用最新的Xcode版本。
4. OpenEars示例項目簡介
在我第一次使用OpenEars的示例項目時,由於受了Siri的影響,因而嘗試說了一大堆,結果發現這個簡單示例項目支持的是詞彙識別,而不是句子的識別。仍是很有些失望的。
不過最起碼它仍是能夠識別出你所說的單詞,精確度還很高。
在Xcode中打開OpenEarsSampleApp,項目的結果很是簡單,首先是OpenEars的特有框架,而後是AudioToolbox和AVFoundation這兩個標準框架,固然還有其它幾個幾乎每一個項目都會用到的框架。
隨便打開一個.xib文件,會看到項目的佈局。
兩個文本框,兩個標籤,還有四個按鈕。
打開ViewController.h,會看到它遵循OpenEarsEventsObserverDelegatex協議。在頭文件裏面定義了多個方法,其中四個IBAction方法是咱們重點要了解的。
切換到ViewControlller.m,來看看幾個方法的實現代碼。
最重要的固然是startListening方法,只有一行代碼,startListeningWithLanguageModelAtPath:dictionaryAtPath:languageModelIsJSGF方法須要知道所使用的語法文件,詞典文件,以及該語法是不是JSGF。在單個語音識別循環中,只能使用JSGF或ARPA語法文件中的一種,而不能在兩種類型中切換。
ARPA語法一般是.languagemodel或.DMP後綴的文件,而JSGF語法則是.gram後綴的文件。
若是你只是想識別某個單獨的語音wav文件,可使用如下方式:
NSString *wavPath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] resourcePath], @"test.wav"];
[self.pocketsphinxController runRecognitionOnWavFileAtPath:wavPath usingLanguageModelAtPath:self.pathToGrammarToStartAppWith dictionaryAtPath:self.pathToDictionaryToStartAppWith languageModelIsJSGF:FALSE]; // Starts the recognition loop.
示例中的方法適用於進行連續語音識別。
在viewDidLoad方法中主要是指定了startListening 方法中所使用的參數,而後調用了startListening方法和startDisplayingLevels方法。
這裏使用的默認詞典和語法是OpenEars1.dic和OpenEras1.languagemodel(在Frameworks文件中自帶的)。
須要注意的是startDisplayingLevels方法是這個示例項目中特有的方法,這裏就不詳細介紹了。
此外就是OpenEarsEventsObserver的協議實現方法,稍做修改就能夠在其它項目中使用。
當用戶說出change model後,就會將詞典和語法切換到動態生成的詞典,也就是languageArray中的幾個單詞。
在設備上運行項目後,首先看到以下界面:
默認的詞典裏面只支持Backward,change,forward,go,left,model,right,turn幾個單詞。當你說change model後,就切換到由程序數組動態生成的詞典,就能夠支持change,model,Monday,Tuesday,…Sunday, QUIDNUNC。
爲了進一步測試,我嘗試把viewDidLoad裏面的詞組更換爲:
NSArray *languageArray = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects: // All capital letters.
@"APPLE",
@"Steve Jobs",
@"Tim Cook",
@"MICROSOFT",
@"FOOD",
@"MONEY",
@"GAME",
@"IPHONE",
@"SIRI",
nil]];
再次運行測試,當說出change model的指令後,程序對於新的詞組均可以識別並輸出,如圖:
說明這個識別是與大小寫無關的。
而後來測試對句子的識別,將viewDidLoad中的詞組修改成以下:
NSArray *languageArray = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects: // All capital letters.
@"APPLE",
@"Steve Jobs",
@"Tim Cook",
@"I love Apple",
@"I am hungry",
@"I really really need money",
@"I'm not a baby",
@"IPHONE",
@"SIRI",
nil]];
再次測試,基本上識別精度仍然很高,但連續識別的時候容易跟以前的句子弄混,不過這個體驗問題不難解決。
這樣的話,示例項目的目的已經基本上達到。咱們對示例項目作一些修改就能夠爲本身所用。
2013年2月7日