First-order ambisonic (FOA) playback: a sound FIELD rather than a point
source, rotated against the camera so the field stays fixed to the world as
the visitor turns (SOUND_SPEC.md §6, Phase 4).
Built from plain Web Audio nodes, no library:
4-chsource ─► splitter ─► W ──────────────────────────► rot[W] ─┐ ├─► Y ─┬─ g[Y][Y] ─► rot[Y] ─┐ │ ├─► Z ─┼─ g[Y][Z] ─► rot[Y] ├─ 3×3gains │ decodegains ─► merger(2) ─► out └─► X ─┴─ g[Y][X] ─► rot[Y] ┘ (9total) │ … ┘
The rotation of a first-order field IS the 3×3 rotation of its dipole
components (X, Y, Z), so nine gain nodes do the whole job; the omni W passes
straight through. The stereo decode is a pair of first-order virtual
cardioids at ±60° (L = W + X·cos60 + Y·sin60, mirrored for R), which keeps
front sources centred, hard left/right at the sides, and the back softer.
Channel order and normalisation follow AmbiX (ACN order W, Y, Z, X,
SN3D), the interchange convention every current encoder writes. Axes: AmbiX
X = front, Y = left, Z = up. The bed is authored in the WORLD frame with
front = the viewer's −Z (what an identity camera looks at), left = −X,
up = +Y; FoaDecoder.setCameraQuaternion folds that mapping in, so a
source that was in front of an identity camera moves to the listener's
right after the camera yaws 90° to the left.
Why not Omnitone (the spec's named library): it decodes to BINAURAL only —
wrong on the kiosk's room speakers — fetches its HRIR set from a CDN at
runtime (an offline kiosk cannot), and has not been maintained for years.
The virtual-microphone decode here is speaker-agnostic and dependency-free;
a headphone HRTF decode can be added behind the same input/output pair.
First-order ambisonic (FOA) playback: a sound FIELD rather than a point source, rotated against the camera so the field stays fixed to the world as the visitor turns (
SOUND_SPEC.md§6, Phase 4).Built from plain Web Audio nodes, no library:
The rotation of a first-order field IS the 3×3 rotation of its dipole components (X, Y, Z), so nine gain nodes do the whole job; the omni W passes straight through. The stereo decode is a pair of first-order virtual cardioids at ±60° (
L = W + X·cos60 + Y·sin60, mirrored for R), which keeps front sources centred, hard left/right at the sides, and the back softer.Channel order and normalisation follow AmbiX (ACN order
W, Y, Z, X, SN3D), the interchange convention every current encoder writes. Axes: AmbiX X = front, Y = left, Z = up. The bed is authored in the WORLD frame with front = the viewer's −Z (what an identity camera looks at), left = −X, up = +Y; FoaDecoder.setCameraQuaternion folds that mapping in, so a source that was in front of an identity camera moves to the listener's right after the camera yaws 90° to the left.Why not Omnitone (the spec's named library): it decodes to BINAURAL only — wrong on the kiosk's room speakers — fetches its HRIR set from a CDN at runtime (an offline kiosk cannot), and has not been maintained for years. The virtual-microphone decode here is speaker-agnostic and dependency-free; a headphone HRTF decode can be added behind the same
input/outputpair.