立体音響を動的に生成する

この記事は[AmusementCreators Advent Calendar 2018](https://adventar.org/calendars/3442) 13日目の記事です。
LT用に作成したスライドを流用してますがご了承ください。


ゲームにおいて、グラフィックは年々進化しているのに、
音に関してはあまり目立った進化はなかったように思えます。

しかし近年、VRの普及もあり新たな技術が注目されています。立体音響です。
有名なゲームだとPUBGが立体音響を導入しましたね。
[こちらの動画](https://www.youtube.com/watch?v=Le22UALj6A4)では、銃弾の音が立体的になった様子を確認できます。
今回は、そんな立体音響を自力で実装する方法を紹介したいと思います。

#立体音響とは？

![スライド5.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/69efe669-42c8-3874-04ae-e91bfab7f517.png)

##立体音響を実現する楽な方法
![スライド6.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/69cb9884-eb37-ef24-c124-61629ef9a54b.png)
家庭用にも5.1ch 7.1ch 対応スピーカが売られていますが、高いです。

#普通のイヤホンやヘッドホンでも立体音響したい！
高価な機器がなくても、ステレオイヤホンやヘッドフォンだけで、立体音響をシミュレートできます。

まずは、人間がどのように音の位置を感じているのか見てみましょう。
![スライド8.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/6e040f97-c3d2-81e0-d7db-d5223a080ed8.png)
## 音を立体的に録音する
![スライド9.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/6eda0bec-a61e-19b0-7eb7-9addafc2c239.png)
Youtubeやニコニコに投稿されている、耳かき音声や、添い寝音声は殆どの場合、ダミーヘッドマイクを使っています。
##ゲームなどで立体音響を使う
![スライド10.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/62011aad-ccba-15ea-62b1-7b8deaf0b5cb.png)
ゲームで立体音響を使う場合、ダーミーヘッドは現実的ではありません。なぜなら、すべての効果音について、360°全方向の音を予め録音する必要があるからです。
プログラムで音を再生するときに、聞こえる角度を指定するだけで音声を加工し、立体音響に変換してくれれば便利です。

# 音を立体的にする
## インパルス応答とは
大ホールを想像してください。
音を発生させると大きく響くと思います。
響くというのは、発生した音がホールの様々な方向の壁に反射し、時間差で耳に届くことで起こる現象です。
![スライド12.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/2c03835f-65b7-9e5f-aced-b4892ef80e3a.png)
インパルス応答とは、パルス波を発生させ、その波がどのように変化して帰ってくるかを記録したものです。
例えば、大ホールでパルス波を発生させ、反響する音を記録しておけば、そのデータをもとに大ホールの音響環境をシミュレーションすることが可能です。

![スライド16.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/e5263cb8-4fef-865b-9b0c-99c67d555616.png)


立体音響においても、インパルス応答は利用できます。
発生したパルス波がどのように変化して耳に届くのか、360°ダーミーヘッドを使い記録しておけば、そのデータをもとに音を変換することができます。
そのように記録したインパルス応答は`頭部伝達関数、HRTF(Head Related Transfer Function)` といいます。
HRTFは国内外を問わず、データベースが公開されているため、そのデータを利用することができます。

ただし、インパルス応答の畳込みは、計算量が莫大になります。
例えばサンプリングレートを`44100Hz` として、1秒の入力信号に、1秒のインパルス応答を畳み込むと
`44100 x 44100 = 1944810000`回もの積和演算が必要になります。
![スクリーンショット (7).png](https://qiita-image-store.s3.amazonaws.com/0/89220/673362bd-f579-2446-16f8-026b3ad5440f.png)
そこでフーリエ変換を用い、周波数領域で畳み込むことで、計算量を
減らすことができます。
![スライド15.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/0345447a-6191-2cff-a89c-48b6398f8fb7.png)

#立体音響を手軽に試せるソフトを作ってみた
![スクリーンショット (8).png](https://qiita-image-store.s3.amazonaws.com/0/89220/6102e6da-c9f9-7d85-65f3-93d456653628.png)
リアルタイムに立体音響を生成できるソフトを開発しました。
コードは [HRTFSimulator](https://github.com/SIY1121/HRTFSimulator) で確認できます。

以下、簡単にですが解説します。

## 処理の流れ
アプリを開発するにあたって、参考にした図を以下に示します。
>
![overlap-save-method.jpg](https://qiita-image-store.s3.amazonaws.com/0/89220/608ad2fa-af22-7d9b-c427-1a2aa8964dd8.jpeg)
http://www.ari-web.com/service/soft/reverb-4.htm

長い入力信号にインパルス応答を適用するには、Overlap-Add法とOverlap-Save法があります。
上の図は、Overlap-Save法です。

###1.インパルス応答を準備する
HRTFデータベースを利用させていただきます。
データベースによって配布形式が異なりますが、どの場合もプログラム内で、FloatArrayにできれば問題ありません。
使用されているデータ形式には以下のようなものがあります。

- `.wav` 一般的な音声ファイル形式
- `.txt` テキストファイルになっているもの
- `.sofa` HRTFを格納するために作られたデータ形式
- `.mat` Matlab用のデータ形式

一番扱いやすいのは`.wav`や`.txt`です。
`.sofa`のフォーマットに関しては、情報がほとんど無く、C/C++で扱うためのライブラリが存在しているようだ、ということしか確認できませんでした。
`.mat`はMatlabを購入していなければ使えません。

`.txt`や`.wav`で配布されているデータベースを載せておきます。

- [マサチューセッツ工科大学のデータベース](http://sound.media.mit.edu/resources/KEMAR.html)
- [名古屋大学のデータベース](http://www.sp.m.is.nagoya-u.ac.jp/HRTF/index-j.html)

ダウンロードすると角度や高度別のインパルス応答データが確認できると思います。
例えば音声を右斜め45°から聞こえてくるように変換したい場合、右斜め45°のインパルス応答を選びます。同じ角度でもインパルス応答はLRの２種類があるため両方準備します。
次にFFTを行うためにインパルス応答の長さを2のべき乗に調節します。調整後の長さをNとします。
調節した上で、さらに前半を同じ長さでゼロ埋めし、長さを2Nにします。
###2.入力信号を準備する
入力信号がステレオの場合、モノラルに変換しておきます。
そこから2N個のサンプルを取っておきます。
`Overlap-Save法`の場合、取った2Nサンプルの内、後半のNサンプルのみが完全にフィルターを掛けた状態になります。
ですので、N点ずらしながら畳み込むことで、すべてのサンプルを畳み込むことができます。
###3.周波数領域で畳み込む
インパルス応答と入力信号をFFTに掛け、畳み込み(複素乗算)を行います
###4.時間領域に戻す
逆FFTによってもとに戻します。この時、出力された信号の後半部分は円状畳込み結果になるため、破棄します。
前半部分が完成品なので、再生したり、保存したりします。

#もっと手軽に立体音響する
最後にもっと手軽に立体音響を実装できるライブラリを紹介します。[ResonanceAudio](https://developers.google.com/resonance-audio/) です。
![スライド20.PNG](https://qiita-image-store.s3.amazonaws.com/0/89220/0c143ccb-6ca0-063c-ff52-32eeee8cd929.png)
以下のプラットフォーム上で開発している人は、こちらも使ってみるべきだと思います。

- Unity
- Unreal
- FMOD
- Wwise
- Web
- Digital Audio Workstation (DAW)
- Android
- iOS

#おわりに
とてもざっくりとですが、立体音響の動的生成法についてお話しました。
VRも普及している現在、立体音響はとてもおもしろいテーマだと思うので、
みなさんも実装してみてはいかがでしょうか？