Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module audio/foa-decoder

    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-ch source ─► splitter ─► W ──────────────────────────► rot[W] ─┐
    ├─► Y ─┬─ g[Y][Y] ─► rot[Y] ─┐ │
    ├─► Z ─┼─ g[Y][Z] ─► rot[Y] ├─ 3×3 gains │ decode gains ─► merger(2) ─► out
    └─► X ─┴─ g[Y][X] ─► rot[Y] ┘ (9 total) │
    … ┘

    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.

    FoaDecoder
    FoaAudio
    FOA_CHANNELS
    foaRotationForCamera