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豆知識,希望以後還有時間分享。

2017年8月16日 星期三

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

Reference:

1. Unity manual  for Native Audio Plugin SDK

2. Native Audio Plugins Bitbucket


在介紹主題之前,我先簡介一下 Unity 的聲音傳導過程。

Unity的元件列表中,可以找到 audio source 與 audio listener ,前者就像是喇叭,後者則是麥克風。假設我們將 audio source attach 在一個球體物件上,將 audio listener attach 在 main camera 上,再將音檔拖曳至 audio source 的 audio clip 欄位上,在按下 play 鍵時,audio source 會開始在場景中播放音檔,audio listener 則接收音訊資料並將結果輸出至電腦的音效裝置,完成這回合。只要你將任何一個人 disable 掉 (取消勾勾),就聽不到聲音。

由上圖 audio source 的屬性頁可以發現, Unity 已經提供了一些很基本 3D Sound Effect 的功能了,因此,在 Play 後你改變了兩者的相對位置及距離的話,就可以聽到聲音的方向有些許的改變。

這時候問題來了:如果我想要改變聲音的特性,或加上一些音效,該怎麼做呢?

一、MonoBehaviour.Update()

只要有一個元件它是繼承自 MonoBehaviour,當它有被 Enable,則 Unity 每過一段時間就會執行它的 Update,我們可以在取得 audio source 的 audio clip 後開始播放它,然後另外新增一個 audio clip 的物件,當 Update 被執行時將 original audio clip 丟進音效處理器,再將 output 寫去 new audio clip ,最後就是將 new audio clip attach 回 audio source 給它播放。

老實說這個作法在邏輯上看起來就怪怪的,我目前還是不懂為什麼可以新舊兩個 audio clip 同時播,卻只有新的被 attach 到 audio source,另個團隊能想到這個作法真的很厲害。

二、MonoBehaviour.OnAudioFilterRead()

原理跟上面差不多,但這個就是直接拿 original audio clip 來做,做完就寫回去並播放,在邏輯上比較合理。另外,這個 function 是由另一條 audio thread 所呼叫,因此在程式執行上比前者更有效率。

三、鏘鏘鏘鏘

沒錯!最有效率的當然是做成 Native Audio Plugin 了,原因無它,前兩者看到的函式都是 C# script,而這個方法則是在底層 (C++) 就做掉了,所以當你在 trace 其他家廠商寫的 Plugin 時,是看不到哪邊有 audio I/O 的行為的。

 

つづく

Audio Effects on Unity–Preface

好久沒有寫blog,心裡有種莫名的感動,工作兩年半來,總算在換工作後有時間可以沉澱自己所做所學並留下紀錄,做筆記對像我這個記性不好的人來說是個加深印象的好方法。

五月底加入新團隊後才剛開始接觸 Unity,在這之前我們實驗的 Unity 場景是商請另外一個團隊幫忙制作,但該團隊對於 Unity 的 audio 運作機制也不熟,所以用了一個很奇特的方式將 audio input buffer 導入某個函式內,讓我們統一在裡面處理完後再丟到 output buffer 。好處是,audio 演算法開發者不需要懂 Unity,只要寫一個 DLL export function 讓 Unity 執行到該函式時可以呼叫即可,我接手程式後上手很快,同事需要橋接新的參數也很容易;缺點是,會有 latency。

老實說我不覺得自己程式功力有多熟練,系統程式的概念多半在碩班建立,在前公司也只是寫一些小模組套用到前人已經完成的系統上。到了新團隊後,我才體會到我對程式也有某種程度上的潔癖,命名規則倒還好,我比較受不了程式架構的雜亂無章,各種神奇的全域變數飛來飛去。因此,我主動向主管提出說我自願幫忙做 code refactor 。另一方面,因為工作任務的關係我也開始研究 Unity 上各家廠商的 SDK,也可擷取別人的長處來改善現行的架構。

新工作即將到職滿三個月,就以一系列的技術文作為慶祝(?)吧!希望日後能夠持續做筆記,讓後輩們能夠更快找到出路。

喔對了,希望台電不要這時候停電,大家快用愛發電吧!

2015年1月11日 星期日

無失真壓縮製作教學 - Conversion of CD image, ape, flac, alac, etc.. CD

這篇文章其實最早在BBS個板我就有整理過這些資訊,不過為了方便給愛聽音樂同時又不想磨損寶貝CD的朋友們參考,便在blog也貼一份。

為什麼我需要將CD轉成loseless壓縮格式?給我理由!

理由實在是太容易舉了!

a. 音質跟原CD一樣,比MP3好很多。

b. 硬碟很便宜,現今硬碟都是TB級的,一張CD壓完約400MB,整顆拿來塞可以塞2000張專輯。

c. 可以寶貝你的CD不受光碟機的刮損。

d. 只要是正版CD,都可以很輕易的在網路上的資料庫找到曲目,搭配下方介紹的軟體,即可方便的聆聽。

前置作業

須安裝以下軟體:

  1. EAC
  2. MAC
  3. FLAC Frontend
  4. foobar

因為軟體的版本會更新,因此這裡並不提供連結,請自行上google查尋最新版本來使用,如操作上與我描述的有所不同歡迎留言指正。

How to: CD -> .ape + .cue or single .flac

  1. 放cd進光碟機
  2. 執行EAC
  3. alt+G (Database -> Get CD Info. from -> Remote freedb)
  4. alt+F7 (Action -> Copy Image & Create CUE Sheet -> Uncomp.)
  5. 轉檔中 ...

第4.點,就是將整張cd存成.wav,而歌曲資訊會存在 .cue。接下來的步驟分成「將.wav轉成.flac」及「將.wav轉成.ape」兩種。

如要轉成 flac ...

  1. 執行 FLAC Frontend。
  2. 讀進剛剛轉完的 .wav。
  3. 執行Encode。
  4. 轉檔中 ...
  5. 用簡單的文書編輯器(notepad or ultraeditor)開啟.cue檔。
  6. 將內文中”.wav”修改成”.flac”。

例:

FILE "Rhapsody - 2002 - Power Of The Dragonflame.wav" WAVE

改成

FILE "Rhapsody - 2002 - Power Of The Dragonflame.flac " WAVE

這時候就會轉出「一個」flac檔,直接拉到foobar的話就只有一首很長的歌。如果想在foobar裡展現出所有歌曲,請讀取.cue檔即可展開整張專輯的曲目。

第4.點,如果要轉成 .ape ...

  1. 執行 MAC (Monkey's Audio)
  2. 第一個按鈕選 Compress
  3. 讀進剛剛轉完的 .wav
  4. 再按一次 Compress
  5. 轉檔中
  6. 用簡單的文書編輯器(notepad or ultraeditor)開啟.cue檔。
  7. 將內文中”.wav”修改成”.ape ”。
  8. 同上,請用foobar讀取.cue檔即可展開整張專輯的曲目。

NOTE: 如果日文曲目無法顯示的話可找iconv.dll相關文章。

2015/01/11 補充 (alac)

最近由於工作關係開始較長時間的使用 MAC ,如果想將音樂放至 iPAD or iPhone 的話需要轉換成 alac 格式,轉換方法請直接參考以下網址:http://blog.xuite.net/ferret/blog/64836312 ,裡面有很詳盡的解說這裡我就不贅述。

至於在 MAC 環境下是否有像 foobar 的播放軟體而且是免費的,相信透過 google 找到這篇文章的你也找過非常多資料了,很可惜,同時也令人費解的,沒有。目前我在 MAC 下用的是 VLC,他的介面簡單且支援的格式也很多 (包含影片),可惜他沒有像 foobar 那樣可以有 multiple playlists,要嘛一次把所有歌都塞進去,要嘛要另存playlist但一次只能使用一個,用起來很不方便。目前我是用虛擬機器在 mbp 裡架了一個 win7,希望日後這問題可獲得改善。

 

Reference:

http://forum.pcdvd.com.tw/showthread.php?t=412694&page=1&pp=10

http://www.hydrogenaudio.org/forums/index.php?showtopic=16146

http://www.pcdvd.com.tw/printthread.php?t=409803 http://0rz.tw/fa2TI

http://www.halabond.com/archive/index.php/t-904.html

download:

foobar0.8.3 繁體中文美化版 http://forum.pcdvd.com.tw/showthread.php?t=460583&highlight=foobar iconv.dll, foo_freedb.dll http://sourceforge.net/projects/gettext http://www.dago.pmp.com.pl/foobar/foo_freedb.dll Monkey's audio http://www.monkeysaudio.com/download.html EAC http://www.exactaudiocopy.de/en/index.php/resources/download/ FLAC Frontend http://cyberial.com/flacinstaller.asp

2014年7月10日 星期四

大兵日記-我在砲測的日子

退伍已過了四天,經過心情的沉澱後,我決定還是提筆(提鍵盤)紀錄這11個月的軍旅生涯。雖然這中間經歷過許多事情,有些牽涉到軍事機密,有些是多數人當兵會遇到的情形,不過屬於我自己的東西,還是依照習慣紀錄一下吧!


2013年5月27日 星期一

在Windows 7 64-bit環境下如何在點擊多個.m檔後使他們都開在同一個editor下?

很長的標題,很常見的問題,對一個對程式有某種程度龜毛的我來說卻是不得不解決的問題。這一切得從我心血來潮裝了 MATLAB R2013a 開始講起。

我本來用 R2011a 用得好好的,後來我發現它竟然沒有自動找出游標所在的變數名稱變成灰底的功能,這個功能的好處是當我要找程式中某個變數所有出現的位置時不需要用 CTRL + F,而只要將游標點在該變數上,從右邊slider bar就可以找到所有位置 (灰色線)。查了一下google發現是 R2011b 以後才有的功能,既然要重裝了乾脆一次裝到最新的版本,果然,R2013a 的介面跟以前截然不同外,還讓我遇到兩個問題:

  1. .m 檔沒有與 MATLAB 建立關聯性
  2. 1.的問題解決後,在檔案總管中依序點擊數個.m檔後,每個.m檔會各自開一個 MATLAB 出來執行。

2012年9月15日 星期六

久違了。年輕,熱血。

2012年9月14日,我看了人生第一場的首映電影,前一天凌晨才在博客來訂票,睡醒後寫信給客服尋問是否來得及在隔天就讓我拿到貨品,想不到客服真的回信並幫我處理好訂單。14日我起了個一早,本來已經打算耗上一天去等待,想不到吃完早餐不久就在窗口看到黑貓的貨車,二話不說馬上飛奔下樓,然後很淡定的從老媽手中接過貨品,再飛奔上樓瞬間拆解了它。