Audio Unit詳解

一胰默、什么是Audio Unit

iOS提供了音頻處理插件鹏漆,支持混合遵倦、均衡节吮、格式轉(zhuǎn)換和實(shí)時輸入/輸出用于錄制脖隶、播放体啰、離線渲染和實(shí)時對話如VoIP(互聯(lián)網(wǎng)協(xié)議語音)龄毡。你可以從iOS應(yīng)用動態(tài)加載和使用它赎瑰,這些強(qiáng)大和靈活的插件叫做Audio Unit薄声。

Audio units通常工作在一個封閉對象的上下文中当船,該對象為audio processing graph,如下圖默辨。在此例中德频,你的app通過一個或多個callback functions發(fā)送audio到第一個audio unit,并對每個audio unit單獨(dú)控制廓奕。I/O輸出unit抱婉,直接連接輸出硬件。

audio_unit.png

Audio units提供非常有用的個性化功能桌粉,如立體聲像蒸绩,混音,音量控制铃肯,音頻電平測量患亿。

二、Audio unit用在哪些方面

1押逼、低延遲的同時音頻I/O(輸入和輸出)步藕,例如VoIP應(yīng)用
2、響應(yīng)回放合成聲音挑格,例如用于音樂游戲或或合成樂器
3咙冗、使用特定的音頻單元功能,例如回聲消除漂彤,混音雾消,或者音調(diào)均衡
4灾搏、一種處理鏈架構(gòu),讓你靈活的將音頻處理模塊組裝起來立润,這是iOS中唯一提供此功能的音頻API

三狂窑、Audio Units in iOS

iOS根據(jù)功能提供了七種audio unit,分為四類桑腮,如下圖:


category.png

3.1 Effect Unit
iOS4提供了一個effect unit泉哈,即iPod Equalizer,與內(nèi)置iPod應(yīng)用程序使用的均衡器相同破讨。要查看該audio unit的iPod應(yīng)用程序用戶界面丛晦,請轉(zhuǎn)至Setting> iPod> EQ。 使用此audio unit時添忘,您必須提供自己的UI采呐。 該audio unit提供一組預(yù)設(shè)均衡曲線,如低音增強(qiáng)器搁骑,流行音樂和口語

3.2 Mixer Units
iOS提供兩個mixer units斧吐。3D Mixer unit是OpenAL構(gòu)建的基礎(chǔ)。在大多數(shù)情況下仲器,如果需要3D Mixer unit的功能煤率,最佳選擇是使用OpenAL,它提供更適合游戲應(yīng)用的更高級API乏冀。

Multichannel Mixer unit可以為任意數(shù)量的單聲道或立體聲流提供混音蝶糯,并帶有立體聲輸出。你可以打開或關(guān)閉每個輸入辆沦,設(shè)置其輸入增益昼捍,并設(shè)置其立體聲平移位置。

3.3 I/O Units
iOS提供三個I/O unit肢扯。Remote I/O是最常用的妒茬。它連接輸入和輸出音頻硬件,并為你提供對各個傳入和傳出音頻樣品值的低延遲訪問蔚晨。它提供硬件音頻格式和應(yīng)用程序音頻格式之間的格式轉(zhuǎn)換乍钻,通過Format Converter unit進(jìn)行格式轉(zhuǎn)換。

Voice-Processing I/O unit通過添加聲學(xué)回聲消除來擴(kuò)展遠(yuǎn)程I/O單元铭腕,以用于VoIP或語音聊天應(yīng)用程序银择。它還提供自動增益校正,語音處理質(zhì)量和靜音累舷。

Generic Output unit不連接到音頻硬件浩考,而是提供將處理鏈的輸出發(fā)送到應(yīng)用程序。通常使用Generic Output unit 進(jìn)行離線音頻處理

3.4 Format Converter Unit
iOS4提供被盈,通常通過I/O單元間接使用

五怀挠、使用兩種方式來獲取audio unit

要在運(yùn)行時查找audio unit析蝴,需要為AudioComponentDescription數(shù)據(jù)結(jié)構(gòu)指定type,subtype绿淋,manufacturer。無論是audio unit還是audio process graph API尝盼。

AudioComponentDescription audioDesc = {0};
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;

不同的audio unit的AudioComponentDescription設(shè)置如下圖表:


component_description_setting.png

5.1 使用AudioComponentDescription初始化Audio Unit:

// find component
AudioComponent compoent = AudioComponentFindNext(NULL, &audioDesc);
// create new instance
AudioComponentInstanceNew(compoent, &audioUnit);

5.2 使用AUGraph來初始化audio unit:

// Declare and instantiate an audio processing graph
AUGraph processingGraph;
NewAUGraph (&processingGraph);
 
// Add an audio unit node to the graph, then instantiate the audio unit
AUNode ioNode;
AUGraphAddNode (processingGraph, &audioDesc, &ioNode);
AUGraphOpen (processingGraph); // indirectly performs audio unit instantiation
 
// Obtain a reference to the newly-instantiated I/O unit
AudioUnit ioUnit;
AUGraphNodeInfo (processingGraph, ioNode, NULL, &ioUnit);

六吞滞、使用scope和elements來指定audio units的各個部分

Audio unit的各個部分組織成scopes and element,如下圖所示盾沫。當(dāng)調(diào)用函數(shù)去配置和控制audio unit時裁赠,你可以指定scope和element以標(biāo)識函數(shù)的特點(diǎn)目標(biāo)。


scope_elements.png

scope是audio unit內(nèi)的編程上下文赴精。雖然global scope可能暗示佩捞,但這些上下文從不嵌套。一般是使用一個常量值來自AudioUnitScope枚舉蕾哟。

element是嵌套在audio unit scope中的編程上下文一忱。當(dāng)element是輸入或輸出scope的一部分時,它類似于物理音頻設(shè)備中的信號總線谭确,因此有時成為總線帘营。

global scope適用于整個audio unit,不與任何特定音頻流相關(guān)聯(lián)逐哈。它只有一個元素芬迄,即0。某些屬性昂秃,如每個切片最大幀數(shù)(kAudioUnitProperty_MaximumFramesPerSlice)禀梳,僅適用于global scope

輸入和輸出scopes直接參與通過audio unit移動一個或多個音頻流。正如你所期待的那樣肠骆,音頻輸入scope進(jìn)入從輸出scope離開算途。屬性或參數(shù)可以作為整體應(yīng)用于輸入scope或輸出scope,某些屬性只能應(yīng)用于scope特定的element

七哗戈、AudioUnitSetProperty配置audio unit

AudioUnitProperty是一個鍵值對郊艘。以下是audio unit開發(fā)中常用的一些屬性:
kAudioOutputUnitProperty_EnableIO:用于在I/O unit上啟用和禁用input or output。默認(rèn)情況輸出已啟用唯咬,輸入已禁用
kAudioUnitProperty_ElementCount:用于配置mixer unit上輸入elements的數(shù)量
kAudioUnitProperty_MaximumFramesPerSlice:用于指定audio unit應(yīng)準(zhǔn)備響應(yīng)于渲染調(diào)用而產(chǎn)生的音頻數(shù)據(jù)最大幀數(shù)纱注。不需要為I/O unit設(shè)置該值,因?yàn)樗鼈円杨A(yù)先配置為處理系統(tǒng)請求的任何切片大小胆胰。對于其它audio unit狞贱,你必須將此屬性設(shè)置為4096以處理屏幕睡眠,除非設(shè)備上正在運(yùn)行音頻輸入蜀涨。當(dāng)音頻輸入運(yùn)行時瞎嬉,系統(tǒng)保持切片大小為1024
kAudioUnitProperty_StreamFormat:用于指定特定音頻單元輸出或輸出總線的音頻流數(shù)據(jù)格式

發(fā)現(xiàn)屬性的可用性蝎毡,訪問其值以及監(jiān)聽其值的更改使用以下函數(shù)

  • AudioUnitGetPropertyInfo:發(fā)現(xiàn)屬性是否可用,則為你提供其值的數(shù)據(jù)大小以及是否可以更改該值
  • AudioUnitGetProperty氧枣,AudioUnitSetProperty:獲取或設(shè)置屬性的值
  • AudioUnitAddPropertyListener沐兵,AudioUnitRemovePropertyListenerWithUserData:安裝或刪除回調(diào)函數(shù)以監(jiān)視屬性值的更改

八、設(shè)置和獲取parameter

audio unit parameter是用戶可調(diào)節(jié)的設(shè)置便监,可在audio unit產(chǎn)生音頻時改變扎谎。實(shí)際上,大多數(shù)parameters是在audio unit正在執(zhí)行處理時烧董,實(shí)時調(diào)整的毁靶。它也是鍵值對的形式。每個parameter的值是32位浮點(diǎn)類型逊移。使用以下函數(shù)來設(shè)置或獲取parameter的值:

  • AudioUnitGetParameter
  • AudioUnitSetParameter

九预吆、I/O Unit的特征

I/O_unit.png

上圖I/O Unit有兩個element,但它們是獨(dú)立的胳泉,例如拐叉,你可以根據(jù)應(yīng)用程序的需要使用enable I/O屬性(kAudioOutputUnitProperty_EnableIO)來獨(dú)立啟用或禁用某個element。每個element都有Input scope和Output scope胶背。

I/O Unit的element 1連接音頻的輸入硬件巷嚣,在上圖中由麥克風(fēng)表示。開發(fā)者只能訪問控制Output scope
I/O Unit的element 0連接音頻的輸出硬件钳吟,在上圖中由揚(yáng)聲器表示廷粒。開發(fā)者只能訪問控制Input scope

input element is element 1(單詞Input的字母“I”,類似1)
output element is element 0 (單詞Output的字母“O”红且,類型0)

十坝茎、Auio Processing Graphs Manage Audio Units

使用數(shù)據(jù)類型AUGraph,用于構(gòu)建和管理audio unit處理鏈暇番。它可以利用多個音頻單元和多個渲染回調(diào)函數(shù)的功能嗤放,允許你創(chuàng)建幾乎任何你能想象的音頻處理解決方案。

AUGraph是線程安全的壁酬,它能夠動態(tài)地重新配置處理鏈次酌。例如,你可以安全的插入均衡器舆乔,甚至可以在播放時交換混音器輸入的不同渲染回調(diào)函數(shù)岳服。事實(shí)上AUGraph是iOS唯一提供的API,用于在音頻應(yīng)用中執(zhí)行此類動態(tài)重新配置希俩。

AUNode來表示graph上下文中的單個audio unit吊宋。當(dāng)使用graph是,你通常與node交互颜武,而不是直接與audio unit交互

當(dāng)你將graph放在一起時璃搜,你必須配置每個audio unit拖吼。為此你必須通過audio unit API直接與audio unit進(jìn)行交互。audio unit node本身是不可配置的

你還可以將AUNode實(shí)例作為復(fù)雜graph中的元素这吻,通過定義node來表示完整audio processing subgraph吊档。在這種情況下,subgraph末尾必須是Generic Output unit(一種不連接到硬件設(shè)備的I/O unit)

總而言之橘原,構(gòu)建audio processing graph需要三個任務(wù):
1籍铁、添加node到graph
2、直接配置nodes表示的audio units
3趾断、互連nodes

AUGraph提供了以下函數(shù)來重新配置:
AUGraphAddNode,AUGraphRemoveNode:添加或移除audio unit node
AUGraphConnectNodeInput吩愧,AUGraphDisconnectNodeInput:添加或移除nodes之間的connections
AUGraphSetNodeInputCallback:connecting一個渲染回調(diào)給audio unit的input bus

十一芋酌、一些設(shè)計(jì)模式

I/O Pass Through

I/O pass-through模式將傳入的音頻直接發(fā)送到硬件輸出,中間沒有處理音頻數(shù)據(jù)雁佳。


I/O.png
I/O Without a Render Callback Function

在Remote I/O unit的elements之間添加一個或多個其它audio unit脐帝,可以構(gòu)建出更有用的應(yīng)用,因?yàn)闆]有回調(diào)函數(shù)糖权,則無法直接操作音頻堵腹,限制了實(shí)用性。


I/O_No_Callback.png
I/O with a Render Callback Function

在Remote I/O unit之間添加一個回調(diào)函數(shù)星澳,可以在傳入音頻到達(dá)輸出硬件之前對其進(jìn)行操作疚顷。比如使用渲染回調(diào)函數(shù)調(diào)整輸出音量,添加顫音禁偎,鈴聲調(diào)制腿堤,回聲或其他效果。通過使用Accelerate框架中提供的傅立葉和卷積函數(shù)如暖,你的可能性是無窮盡的


render_callback.png
Output-Only with a Render Callback Function

適用于游戲和音樂合成app笆檀,將渲染回調(diào)函數(shù)直接連接到Remote I/O的Output element的input scope


only_output.png
complex pattern
complex.png

參考文章:
Audio Unit Hosting Guide for iOS

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市盒至,隨后出現(xiàn)的幾起案子酗洒,更是在濱河造成了極大的恐慌,老刑警劉巖枷遂,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件樱衷,死亡現(xiàn)場離奇詭異,居然都是意外死亡登淘,警方通過查閱死者的電腦和手機(jī)箫老,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黔州,“玉大人耍鬓,你說我怎么就攤上這事阔籽。” “怎么了牲蜀?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵笆制,是天一觀的道長。 經(jīng)常有香客問我涣达,道長在辆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任度苔,我火速辦了婚禮匆篓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寇窑。我一直安慰自己鸦概,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布甩骏。 她就那樣靜靜地躺著窗市,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饮笛。 梳的紋絲不亂的頭發(fā)上咨察,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音福青,去河邊找鬼摄狱。 笑死,一個胖子當(dāng)著我的面吹牛素跺,可吹牛的內(nèi)容都是我干的二蓝。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼指厌,長吁一口氣:“原來是場噩夢啊……” “哼刊愚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起踩验,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鸥诽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后箕憾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牡借,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年袭异,在試婚紗的時候發(fā)現(xiàn)自己被綠了钠龙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖碴里,靈堂內(nèi)的尸體忽然破棺而出沈矿,到底是詐尸還是另有隱情,我是刑警寧澤咬腋,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布羹膳,位于F島的核電站,受9級特大地震影響根竿,放射性物質(zhì)發(fā)生泄漏陵像。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一寇壳、第九天 我趴在偏房一處隱蔽的房頂上張望醒颖。 院中可真熱鬧,春花似錦壳炎、人聲如沸图贸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至偿洁,卻和暖如春撒汉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涕滋。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工睬辐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宾肺。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓溯饵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锨用。 傳聞我的和親對象是個殘疾皇子丰刊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容