はじめに
Metaが開発したSoundSpacesを用いて音響シミュレーションを行いました。SoundSpacesは、音響インパルス応答生成に関する論文で近年よく使われています123。インパルス応答とは、ある位置の音源から発せられる瞬間的な音(インパルス)を、別位置のマイクで記録したものです。インパルス応答は空間の音響特性(反響、吸収、残響時間など)を反映しており、これを任意の音声信号と畳み込む(重ね合わせる)ことで、その空間内で音がどのように聞こえるかをシミュレーションできます。
現状では、SoundSpacesに関連する日本語記事がほとんど見当たらなかったため、シミュレーション実行方法に関する知見を共有します。
本記事では、シミュレーション環境(部屋形状、材料特性(音の吸収率、散乱率など))を自由に設定することに取り組みました。シミュレーションのコードは、GitHubリポジトリ内に見つけたチュートリアルを元に実装しました。
また、途中で遭遇した材料特性指定に関する現状の不具合についても、Issuesの情報を中心に調査しました。
目次
1. ソフトウェアバージョン
- Ubuntu 20.04.5 LTS
- Python 3.9.19
- Blender 4.3.2.0
SoundSpacesのインストール 手順に従い、minicondaを使って環境構築を行いました。
2. シミュレーション環境
SoundSpacesは、habitat-simというMetaが開発した3Dシミュレータ上で動作しています。シミュレーション実行のためには、シミュレーション環境を表す3Dモデルデータが必要です。
BlenderやUnity等で3Dモデルを自作することも可能ですが、公式にシミュレーション環境データセットがいくつか公開されており、それを用いてシミュレーションを実行することもできます。
本記事では、SoundSpacesチュートリアルで使用されていたMatterport3D (MP3D) datasetと、簡単に自作した3Dモデル(立方体の部屋)でシミュレーションを行いました。
2.1 Matterport3D (MP3D) dataset
Matterport3D (MP3D) datasetには、以下のファイルが含まれます。
-
.glb
:部屋形状を表す3Dモデル -
semantic.ply
:部屋の構成部品(机、壁など)を区別するために、頂点ごとに色分けされたメッシュファイル(材料特性の指定に使用) -
.house
:semantic.ply
で区別される各構成部品にインスタンス名、IDを割り当てるテキストファイル(材料特性の指定に使用) -
.navmesh
:音源、マイク配置可能場所に制約を与えるファイル -
mp3d.scene_dataset_config.json
:上記ファイルのパスや設定をまとめたファイル -
mp3d_material_config.json
:各インスタンス名に材料特性を設定するファイル
上記のファイルの内、必須なのは.glb
だけです。
材料特性の指定をする場合、semantic.ply
、.house
、mp3d.scene_dataset_config.json
、mp3d_material_config.json
が必要になります。
また、今回は .navmesh
を使用せずにシミュレーションを行いました。
本記事では、下のような.glb
、semantic.ply
の環境でシミュレーションを行いました(見やすいように少し回転させています)。
本記事で使用する環境は動作確認用のサンプル環境であり、habitat-simの環境構築後、DATASETS.mdの手順に従えばダウンロードできます。ただし、mp3d_material_config.json
はSoundSpacesのINSTALLATION.mdに従ってダウンロードしてください。
また、すべてのMP3D datasetをダウンロードするには、利用規約の同意書に署名して、メールでやり取りする必要があります。
2.2 自作3Dモデル
Blenderで10 m×10 mの正方形を組み合わせて、立方体の部屋を簡単に自作しました。.glb
ファイルとして保存してシミュレーションに用いました。
Google Driveにアップロードしたので、自由にダウンロードできます。
3. デフォルトの材料特性でのシミュレーション
材料特性を指定しない場合、シミュレーション環境ファイルは.glb
のみ用意すれば実行できます。
3.1 MP3D dataset
基本的にはチュートリアルと同様の流れで実装しています4。細かいパラメータ指定はSoundSpaces2.mdを参照してください。
音源(emitter)位置と音響センサー(listener)位置の指定部分だけ簡単に説明します。以下のコードで音源位置と音響センサー位置を指定しています。
- 音源位置
audio_sensor.setAudioSourceTransform(座標)
- 音響センサー位置
-
new_state.position = 座標
(エージェントの位置) -
audio_sensor_spec.position = 座標
(エージェントを原点としたローカル座標での音響センサー位置)
-
つまり、特にエージェントを回転させない場合、new_state.position + audio_sensor_spec.position
が音響センサー位置となります。
import os
import quaternion
import habitat_sim.sim
import numpy as np
from scipy.io import wavfile
import librosa.display
import matplotlib.pyplot as plt
# シミュレータの基本設定
backend_cfg = habitat_sim.SimulatorConfiguration()
backend_cfg.scene_id = "data/scene_datasets/mp3d_example/17DRP5sb8fy/17DRP5sb8fy.glb" # 部屋形状を表す3Dモデルの指定
backend_cfg.load_semantic_mesh = False # セマンティック情報の読み込みを無効化
backend_cfg.enable_physics = False # 物理シミュレーションを無効化
agent_config = habitat_sim.AgentConfiguration()
cfg = habitat_sim.Configuration(backend_cfg, [agent_config])
sim = habitat_sim.Simulator(cfg) # シミュレータの初期化
# 音響センサー(listener)の設定
audio_sensor_spec = habitat_sim.AudioSensorSpec()
audio_sensor_spec.uuid = "audio_sensor" # センサーの識別子
audio_sensor_spec.enableMaterials = False # 材料特性を指定しない(デフォルト材料特性)
audio_sensor_spec.channelLayout.type = habitat_sim.sensor.RLRAudioPropagationChannelLayoutType.Mono # モノラル音声
audio_sensor_spec.channelLayout.channelCount = 1 # チャンネル数を1に設定(モノラル)
audio_sensor_spec.position = [0.0, 1.5, 0.0] # エージェントに対するセンサーの相対位置(高さ1.5m)
audio_sensor_spec.acousticsConfig.sampleRate = 48000 # サンプリングレート(48 kHz)
audio_sensor_spec.acousticsConfig.indirect = True # 間接音(反射や残響)の有効化
sim.add_sensor(audio_sensor_spec) # シミュレータに音響センサーを追加
# 音源(emitter)の設定
audio_sensor = sim.get_agent(0)._sensors["audio_sensor"]
source_pos = [0.5, 0.0, 0.5] # 音源の位置(地面上の座標)
audio_sensor.setAudioSourceTransform(source_pos + np.array([0, 1.5, 0])) # 音源の高さを1.5mに設定
# エージェントの設定
agent = sim.get_agent(0)
new_state = sim.get_agent(0).get_state() # 現在のエージェント状態を取得
new_state.position = np.array(source_pos + np.array([2, 0, 0])) # エージェントの位置を音源から2m離れた場所に設定
new_state.sensor_states = {} # センサー状態を初期化
agent.set_state(new_state, True) # 新しいエージェント状態(位置)を適用
# インパルス応答(IR)を計算
ir = np.array(sim.get_sensor_observations()["audio_sensor"])
# 音源がリスナーから直接見えるか(遮蔽がないか)を確認
print("The direct sound is present:", audio_sensor.sourceIsVisible())
# IRの波形をプロットして保存
plt.figure(figsize=(6, 4))
librosa.display.waveshow(ir, sr=48000)
plt.title("Waveform of IR (default materials)")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.tight_layout()
plt.savefig("outputs/ir_default_material_mp3d.png")
上記コードを実行すると、以下のようなインパルス応答(IR)が得られます。
ちなみに、17DRP5sb8fy.glb
は以下のようになっているため、y軸方向が高さ方向になっています。
3.2 自作3Dモデル
MP3D datasetでのシミュレーションと同じ条件で、.glb
のみ自作3Dモデルに変更して実行しました。得られたIR波形は以下のようになりました。
MP3D datasetより単純な部屋形状であるため、より時間が短く、反響の影響が少ない波形となっています。
4. 材料特性を指定したシミュレーション
4.1 MP3D dataset
3.1 MP3D datasetのコードに材料特性の指定部分を追加で実装しました。
import os
import quaternion
import habitat_sim.sim
import numpy as np
from scipy.io import wavfile
import librosa.display
import matplotlib.pyplot as plt
# シミュレータの基本設定
backend_cfg = habitat_sim.SimulatorConfiguration()
backend_cfg.scene_id = "data/scene_datasets/mp3d_example/17DRP5sb8fy/17DRP5sb8fy.glb" # 部屋形状を表す3Dモデルの指定
backend_cfg.scene_dataset_config_file = "data/scene_datasets/mp3d_example/mp3d.scene_dataset_config.json" # セマンティック情報の設定ファイルを指定
backend_cfg.load_semantic_mesh = True # セマンティック情報の読み込みを有効化
backend_cfg.enable_physics = False # 物理シミュレーションを無効化
agent_config = habitat_sim.AgentConfiguration()
cfg = habitat_sim.Configuration(backend_cfg, [agent_config])
sim = habitat_sim.Simulator(cfg) # シミュレータの初期化
# 音響センサー(listener)の設定
audio_sensor_spec = habitat_sim.AudioSensorSpec()
audio_sensor_spec.uuid = "audio_sensor" # センサーの識別子
audio_sensor_spec.enableMaterials = True # 材料特性を指定する
audio_sensor_spec.channelLayout.type = habitat_sim.sensor.RLRAudioPropagationChannelLayoutType.Mono # モノラル音声
audio_sensor_spec.channelLayout.channelCount = 1 # チャンネル数を1に設定
audio_sensor_spec.position = [0.0, 1.5, 0.0] # エージェントから見たセンサーの相対位置(高さ1.5m)
audio_sensor_spec.acousticsConfig.sampleRate = 48000 # サンプリングレート(48 kHz)
audio_sensor_spec.acousticsConfig.indirect = True # 間接音(反射や残響)の有効化
sim.add_sensor(audio_sensor_spec) # シミュレータに音響センサーを追加
# 材料特性の設定
audio_sensor = sim.get_agent(0)._sensors["audio_sensor"]
audio_sensor.setAudioMaterialsJSON("data/mp3d_material_config.json") # 材料特性を記述したJSONファイルをロード
# 音源(emitter)の設定
source_pos = [0.5, 0.0, 0.5] # 音源の位置(地面上の座標)
audio_sensor.setAudioSourceTransform(source_pos + np.array([0, 1.5, 0])) # 音源の高さを1.5mに調整
# エージェントの設定
agent = sim.get_agent(0)
new_state = sim.get_agent(0).get_state() # 現在のエージェント状態を取得
new_state.position = np.array(source_pos + np.array([2, 0, 0])) # エージェントを音源から2m離れた位置に移動
new_state.sensor_states = {} # センサー状態を初期化
agent.set_state(new_state, True) # 新しいエージェント状態(位置)を適用
# インパルス応答(IR)の取得
ir = np.array(sim.get_sensor_observations()["audio_sensor"])
# 音源がリスナーから直接見えるか(遮蔽がないか)を確認
print("The direct sound is present:", audio_sensor.sourceIsVisible())
# IRの波形をプロットして保存
plt.figure(figsize=(6, 4))
librosa.display.waveshow(ir, sr=48000)
plt.title("Waveform of IR (specified materials)")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.tight_layout()
plt.savefig("outputs/ir_material_mp3d.png")
上記コードを実行すると、以下のようなインパルス応答(IR)が得られます。
デフォルト材料特性での結果と一緒に並べると微妙に異なっており、材料特性によって変化したことがわかります。
材料特性を指定しているmp3d_material_config.jsonは以下のようになっています(一部抜粋)。
{"materials":
[
{
"name": "Default",
"absorption": [20.0, 0.10000000149011612, 20000.0, 0.10000000149011612],
"scattering": [20.0, 0.5, 20000.0, 0.5],
"transmission": [20.0, 0.0, 20000.0, 0.0],
"labels": ["default"],
"damping": [22.27947998046875, 1.1595274046483084e-10, 27.647445678710938, 1.7855866785154717e-10, 34.30875778198242, 2.7496721566322435e-10, 42.57503890991211, 4.234294304072961e-10, 52.832969665527344, 6.520501361073627e-10, 65.56243896484375, 1.0041096842883235e-09, 81.35887908935547, 1.5462540137178848e-09, 100.9613265991211, 2.3811186355970904e-09, 125.2867431640625, 3.6667489045072443e-09, 155.47299194335938, 5.646519696256291e-09, 192.93234252929688, 8.695229425370599e-09, 239.4170684814453, 1.3390017095105122e-08, 297.1015930175781, 2.0619632223883855e-08, 368.6846618652344, 3.175273022293368e-08, 457.5147705078125, 4.8896882987037316e-08, 567.7471923828125, 7.529756373969576e-08, 704.5390625, 1.1595275850595499e-07, 874.288818359375, 1.7855860789950384e-07, 1084.938232421875, 2.749672489699151e-07, 1346.341064453125, 4.234294976868114e-07, 1670.724853515625, 6.520498345707892e-07, 2073.265869140625, 1.0041092082246905e-06, 2572.79443359375, 1.546254907225375e-06, 3192.6767578125, 2.381117610639194e-06, 3961.915771484375, 3.666750899355975e-06, 4916.4892578125, 5.64652327739168e-06, 6101.05517578125, 8.695225915289484e-06, 7571.03466796875, 1.3390024832915515e-05, 9395.1796875, 2.0619641873054206e-05, 11658.830078125, 3.175271558575332e-05, 14467.8916015625, 4.889691263088025e-05, 17953.748046875, 7.529760478064418e-05],
"density": 998.6546630859375,
"speed": 1483.9610595703125
},
{
"name": "Acoustic Tile",
"absorption": [125.0, 0.5, 250.0, 0.699999988079071, 500.0, 0.6000000238418579, 1000.0, 0.699999988079071, 2000.0, 0.699999988079071, 4000.0, 0.5],
"scattering": [125.0, 0.10000000149011612, 250.0, 0.15000000596046448, 500.0, 0.20000000298023224, 1000.0, 0.20000000298023224, 2000.0, 0.25, 4000.0, 0.30000001192092896],
"transmission": [125.0, 0.05000000074505806, 250.0, 0.03999999910593033, 500.0, 0.029999999329447746, 1000.0, 0.019999999552965164, 2000.0, 0.004999999888241291, 4000.0, 0.0020000000949949026],
"labels": ["ceiling"],
"damping": [22.27947998046875, 1.1595274046483084e-10, 27.647445678710938, 1.7855866785154717e-10, 34.30875778198242, 2.7496721566322435e-10, 42.57503890991211, 4.234294304072961e-10, 52.832969665527344, 6.520501361073627e-10, 65.56243896484375, 1.0041096842883235e-09, 81.35887908935547, 1.5462540137178848e-09, 100.9613265991211, 2.3811186355970904e-09, 125.2867431640625, 3.6667489045072443e-09, 155.47299194335938, 5.646519696256291e-09, 192.93234252929688, 8.695229425370599e-09, 239.4170684814453, 1.3390017095105122e-08, 297.1015930175781, 2.0619632223883855e-08, 368.6846618652344, 3.175273022293368e-08, 457.5147705078125, 4.8896882987037316e-08, 567.7471923828125, 7.529756373969576e-08, 704.5390625, 1.1595275850595499e-07, 874.288818359375, 1.7855860789950384e-07, 1084.938232421875, 2.749672489699151e-07, 1346.341064453125, 4.234294976868114e-07, 1670.724853515625, 6.520498345707892e-07, 2073.265869140625, 1.0041092082246905e-06, 2572.79443359375, 1.546254907225375e-06, 3192.6767578125, 2.381117610639194e-06, 3961.915771484375, 3.666750899355975e-06, 4916.4892578125, 5.64652327739168e-06, 6101.05517578125, 8.695225915289484e-06, 7571.03466796875, 1.3390024832915515e-05, 9395.1796875, 2.0619641873054206e-05, 11658.830078125, 3.175271558575332e-05, 14467.8916015625, 4.889691263088025e-05, 17953.748046875, 7.529760478064418e-05],
"density": 998.6546630859375,
"speed": 1483.9610595703125
}
]
}
指定できる各材料特性について説明すると、以下のようになります。
-
absorption
:音の吸収率 -
scattering
:音の散乱率 -
transmission
:音の透過率 -
damping
:空間内の伝播に伴う音のエネルギー損失(dB/m) -
density
:密度(kg/m³) -
speed
:材料中の音速(m/s)
absorption
、scattering
、transmission
、damping
については周波数ごとに設定できるようになっています。
以下、SoundSpacesの論文より抜粋。
Every acoustic material has a list of candidate object categories to be mapped from. It also has a set of coefficients for absorption, scattering, and transmission in the following format: $$[f_1, c_1, f_2, c_2, \dots, f_n, c_n]$$ where $f_i$ is a frequency and $c_i$ is the coefficient for a certain acoustic phenomenon at frequency $f_i$. This allows modeling the frequency-dependent acoustic properties of different acoustic materials.
Users can specify the frequency-dependent damping coefficients for each material, expressed as dB per meter, in a similar format to the other material properties.
4.2 自作3Dモデル
結論から言うと、私が集めた情報では自作3Dモデルで材料特性を指定することはできませんでした。
2025年1月現在、自作3Dモデルに対して材料特性を指定するのは難しい、もしくは時間がかかると思われます。材料特性を指定した場合の不具合はCurrent open issuesとして把握されており、対処としては材料特性の指定をオフにすることが推奨されています。
以下に試行錯誤の過程を記します。
肝となるのは、MP3D datasetにおけるsemantic.ply
と.house
に対応するものの作成です。この2ファイルを作成できれば、後はパスやパラメータを記載した設定ファイル(json)を作成するだけです。
Habitat-Matterport 3D Research Dataset (HM3D)形式でのセマンティック情報作成
semantic.ply
と.house
を自作する方法を探していると、Issueに同様の試みをしている人がおり、開発者からのコメントがありました。
First, I suggest you follow the format of HM3D Semantics rather than MP3D and instead generate a .semantic.glb and a .semantic.txt file. Please review our arxiv report (https://arxiv.org/abs/2210.05633) for many details regarding this process and the file contents.
つまり、MP3D形式のsemantic.ply
と.house
ではなく、それに対応するHM3D形式のsemantic.glb
とsemantic.txt
を自作して使用することを勧める、と書かれていました。他のコメントを見ると、MP3D形式で作成するのは複雑で難しいとも書かれていたので、HM3D形式で自作を試みました。
作成方法はIssueに記載されている方法に従いました。
semantic.glb
は立方体の自作3Dモデルに対して、Blenderで各面に色付けすることで作成しました。色付け方法はYoutubeを参考にしました。
semantic.txt
は各面に付けた色の16進数カラーコードと、割り当てるインスタンス名、インスタンスID、リージョンIDを並べることで作成しました。リージョンIDは適当な数字を入れて大丈夫そうです。
semantic.glb
とsemantic.txt
を作成した後、シミュレーションを実行すると、以下のようなエラーが発生しました。
[17:32:16:011819]:[Assets] ResourceManager.cpp(2941)::joinSemanticHierarchy : Could not get the GenericSemanticMeshData
File: arvr/libraries/audio/AudioSDK/Research/Source/Wrapper/PropagationWrapper.cpp
Function: ovrResult PropagationWrapper::AddMeshVertices(const float *, ovra::Size), Line 926
Mesh vertices were NULL
[17:32:16:011864]:[Sensor] AudioSensor.cpp(394)::loadSemanticMesh : Couldn't add vertices to audio mesh, error: 2001
調査すると、同様のエラーが発生しているIssueがあり、開発者からのコメントでHM3D形式での材料特性指定に関して不具合があることを確認できました。
しかし、Gibson datasetの形式でも材料特性の指定ができるというコメントがあったため、Gibson datasetの調査を進めました。
Gibson datasetでのセマンティック情報作成
まず、MP3D形式でのsemantic.ply
と.house
がGibson datasetでどのように表現されているか確認するために、Gibson datasetの中身を確認しようとしました。
Gibson datasetでは、semantic.ply
と.scn
というファイルが代わりに使われており、それらのファイルを入手するには、.npz
ファイルをダウンロードした後、habitat-simのtools/gen_gibson_semantics.sh
で変換する必要があることがわかりました。
しかし、実際に変換を実行すると、以下のようなエラーが出て、semantic.ply
が作成できませんでした。
ESP_CHECK failed: esp::logging::LoggingContext: No current logging context.
中止
調査すると、同様のエラーが発生しているIssueが見つかり、解決されていなかったために断念しました。
tools/gen_gibson_semantics.sh
のスクリプト内に記載のパス
build/utils/datatool/datatool
が存在せず、build/utils/datatool/Datatool
だったことや、2025年1月に入ってからの修正でmainブランチからtools/gen_gibson_semantics.sh
が削除されたことを考慮すると、不具合が色々残っているのではないかと考えられます。
こうした経緯で、自作3Dモデルで材料特性を指定することを断念しました。
おわりに
SoundSpacesに関する情報が公式GitHubくらいしかなく、苦労した部分もありましたが、デフォルトの材料特性でシミュレーションを実行することができました。
また、材料特性指定に関する私の試み、及び現状の不具合についても、Issuesの情報を中心に可能な限りまとめました。
これらの情報が、SoundSpacesを使おうと思われている方のお役に立てれば幸いです。
(この記事は研究室インターンで取り組みました:https://kojima-r.github.io/kojima/)
-
Kun Su, Mingfei Chen, and Eli Shlizerman, INRAS: Implicit Neural Representation for Audio Scenes, NeurIPS, 2022. ↩
-
Andrew Luo, Yilun Du, Michael J. Tarr, Joshua B. Tenenbaum, Antonio Torralba, and Chuang Gan, Learning Neural Acoustic Fields, NeurIPS, 2022. ↩
-
Susan Liang, Chao Huang, Yapeng Tian, Anurag Kumar, and Chenliang Xu, Neural Acoustic Context Field: Rendering Realistic Room Impulse Response With Neural Fields, arXiv, 2023. ↩
-
Current open issuesに記載されている通り、quaternionより先にhabitat_simをimportすると、(少なくとも私の環境では)エラーが発生します。 ↩