2018年3月11日 星期日

Audio Effects on Unity–Native Audio Plugin SDK(2)

時光飛逝,過了半年才回來補這篇技術文章,在進入正題之前先簡述一下,這段時間 Unity 已經改版至 2018.1 beta,Native Audio Plugin 也有做一些改動。近期開發 spatial audio 的公司變多了,所以 Unity 在 spatializer 的支援也改版得地別勤勞,從原本 Unity 5.0 開始,後來 5.5 內建 Microsoft HRTF 跟 Oculus spatializer,到現在最新的 2018.1 beta 也內建了 Google Resonance spatializer,有興趣的朋友可以自行深入查詢各家的特色。本篇文章將只針對 Unity Native Audio Spatializer Plugin 的幾個 API 作介紹,也會提及一些經驗上的分享,其適用於 Unity 5.0 到 2017.3,2018.1 beta 我個人還沒試過不過理論上應該也可以支援。


在閱讀本文之前,大家可以先到這裡下載API與範例程式,從文件及範例程式,我整理出幾個設計程式的步驟:
  1. 製訂好你設計的 spatializer 有哪些參數可供外部設定,然後參考InternalRegisterEffectDefinition 函式內的寫法去註冊你的參數。
  2. 前面訂好參數後,可實作 SetFloatParameterCallback 這個 interface 來實現與外部控制單元的接口,往後在 C# script 端就可以透過 Unity audio source 物件的 setSpatializerFloat 函式將 Unity 場景中某個 audio source 的參數給傳進 plugin。
  3. CreateCallback 與 ReleaseCallback 相當然爾就是對應到 audio source 物件生成與消失時底層 plugin 物件實體的生成/消失。
  4. ProcessCallback,最重要的部份,audio source 上掛的音檔,在執行過程中會以一個個 audio frame 的方式透過 ProcessCallback 不斷的傳進來 plugin,我們必須實作這個函式去進 input buffer 進行處理後再填到 output buffer,最後就會往 audio source 所指定的 Mixer 送去。這裡需要注意的是第四個參數 length,它的單位是 sample,假設它的值是 1024,如果 inchannels = 2 (雙聲道),則代表 input buffer 一共有 1024 * 2 個 floats。
  5. 別忘了在某個地方加上這行:
    definition.flags |= UnityAudioEffectDefinitionFlags_IsSpatializer;
  6. 善用 UnityAudioSpatializerData 去取得當前 audio source 及 audio listener 的位置/旋轉資訊。
這裡我跳過對每個函式的解說,直接分享幾個心得,或許對初次接觸 audio plugin 的人沒有幫助,但相信對有開發經驗的人能節省一些錯誤的嘗試。
  • audio 演算法的設計,在這個架構下必須要將「控制」(SetFloatParameterCallback) 與「計算」(ProcessCallback) 分開,剛從 Matlab 跨過來的人可能會有點障礙。
  • Unity audio source 生成、執行、到消失時,可確定其呼叫順序為 CreateCallback -> ProcessCallback (多次) -> ReleaseCallback。
  • Unity C# script 的遊戲物通常會繼承 MonoBehavior class,它也有 Awake, Start, Enable, Update, OnDestroy 之類的 API,來對應它的 life cycle。不幸的是,這些 API 跟前面提到的 callback 沒有任何先後關係。也就是說,如果你想設計一個遊戲物件去影響一個 audio source 的效果 (例如有殘響效果的房間),請小心處理兩者的 life cycle,否則會出現你想 Update 但 audio source 已被 destroyed 的情況。
  • 當audio source播完你指定的audio clip時,Unity 5.6 及之前的版本會繼續空轉 ProcessCallback,造成CPU資源的浪費,2017 以後的版本才會停止呼叫。這算是 Unity 之前版本的 bug,但我們也是有辦法可以讓他停啦...

半年一篇CS豆知識,希望以後還有時間分享。