Spatial Audio¶
3D positional sound that pans as the source orbits you.
📄 Docs onlyTags: audio 3d spatial
An AudioPlayer3D is a sound with a place in the world. Each frame the engine
compares its world position with the AudioListener3D (the ear) and sets the
volume from the distance and the stereo pan from the direction, so moving
either node is all it takes to move the sound.
Here the listener is a child of the Camera3D, so the ear goes wherever the
camera looks from. The player is a child of a blue sphere, which is a child of
an Orbit pivot turned a little every frame, so the tone circles the yellow
marker at the origin: it sweeps between the left and right speakers, and swells
as the sphere passes close to the camera.
tone = AudioPlayer3D(AudioClip.tone(330.0, duration=2.0, volume=0.4),
loop=True, autoplay=True, max_distance=20.0, attenuation=2.0)
sphere.add_child(tone)
AudioClip.tone() generates the sound, so no audio file is needed.
max_distance is where the sound falls silent, and attenuation shapes the
fall-off on the way there: the level drops by 80 dB * (distance / max_distance) ** attenuation. The sphere comes within 5 units of the camera
(about -5 dB) and goes out to about 15 (about -48 dB).
Source¶
1# /// simvx
2# tags = ["audio", "3d", "spatial"]
3# [web]
4# width = 800
5# height = 600
6# responsive = true
7# disabled = true
8# reason = "Browser audio unlocks only on a user gesture and this scene starts its tone on load, so it would be silent."
9# ///
10"""Spatial Audio: 3D positional sound that pans as the source orbits you.
11
12An `AudioPlayer3D` is a sound with a place in the world. Each frame the engine
13compares its world position with the `AudioListener3D` (the ear) and sets the
14volume from the distance and the stereo pan from the direction, so moving
15either node is all it takes to move the sound.
16
17Here the listener is a child of the `Camera3D`, so the ear goes wherever the
18camera looks from. The player is a child of a blue sphere, which is a child of
19an `Orbit` pivot turned a little every frame, so the tone circles the yellow
20marker at the origin: it sweeps between the left and right speakers, and swells
21as the sphere passes close to the camera.
22
23```python
24tone = AudioPlayer3D(AudioClip.tone(330.0, duration=2.0, volume=0.4),
25 loop=True, autoplay=True, max_distance=20.0, attenuation=2.0)
26sphere.add_child(tone)
27```
28
29`AudioClip.tone()` generates the sound, so no audio file is needed.
30`max_distance` is where the sound falls silent, and `attenuation` shapes the
31fall-off on the way there: the level drops by `80 dB * (distance /
32max_distance) ** attenuation`. The sphere comes within 5 units of the camera
33(about -5 dB) and goes out to about 15 (about -48 dB).
34"""
35
36from simvx.core import (
37 AudioClip,
38 AudioListener3D,
39 AudioPlayer3D,
40 Camera3D,
41 DirectionalLight3D,
42 Material,
43 Mesh,
44 MeshInstance3D,
45 Node,
46 Node3D,
47)
48from simvx.graphics import App
49
50ORBIT_RADIUS = 6.0 # World units from the origin.
51ORBIT_SPEED = 0.6 # Radians per second.
52
53
54class SpatialAudio(Node):
55 def on_ready(self):
56 camera = self.add_child(Camera3D(position=(0, 4, 9), look_at=(0, 0, 0), fov=60.0))
57 camera.add_child(AudioListener3D())
58 self.add_child(DirectionalLight3D())
59
60 self.add_child(
61 MeshInstance3D(
62 name="OrbitCentre", mesh=Mesh.box(0.4), material=Material(colour=(0.9, 0.9, 0.2, 1.0), roughness=0.6)
63 )
64 )
65
66 self.orbit = self.add_child(Node3D(name="Orbit"))
67 sphere = self.orbit.add_child(
68 MeshInstance3D(
69 name="Source",
70 position=(ORBIT_RADIUS, 0, 0),
71 mesh=Mesh.sphere(0.5),
72 material=Material(colour=(0.2, 0.6, 1.0, 1.0), roughness=0.3),
73 )
74 )
75 sphere.add_child(
76 AudioPlayer3D(
77 AudioClip.tone(330.0, duration=2.0, volume=0.4),
78 name="Tone",
79 loop=True,
80 autoplay=True,
81 max_distance=20.0,
82 attenuation=2.0,
83 )
84 )
85
86 def on_update(self, dt: float):
87 self.orbit.rotate_y(ORBIT_SPEED * dt)
88
89
90if __name__ == "__main__":
91 App(title="Spatial Audio", width=800, height=600).run(SpatialAudio())