Lab

Binaural Panner

A binaural panner device: a direction, a distance, a head's size and a mix, a panel with the head seen from above, a Web Audio engine and tools for agents.

Audio UI

Places a sound all around the head, for headphones. A pan only sets a level between two speakers; this one makes the cues the ear uses: the far ear hears the sound a fraction of a millisecond later, and darker, in the head's shadow. Drag the sound around the head, behind it, beside it, farther out. It is a device: a state, a panel, an engine and tools, each its own file.

Installation

pnpm dlx shadcn@latest add @audio-ui/binaural-panner

It installs the device's state, its engine and its panel to components/audio-ui/devices/binaural-panner/. The demo above, which wires them to a loop, is @audio-ui/block-binaural-panner.

Controls

Controls · 5

The cues are of direction around the head, not of height, and a sound behind sounds much like one in front: the model has no ears' folds to tell them apart.

Panel

The panel shows the head seen from above, in front up, and a handle for the sound: its angle is the direction and how far out it is the distance. binauralPoint(state) is where the handle sits, and binauralPlace(point) the direction and distance of a point.

import { BinauralPannerPanel } from "@/components/audio-ui/devices/binaural-panner/panel";
import { binauralPannerDevice } from "@/components/audio-ui/devices/binaural-panner/device";

const [state, setState] = useState(() => binauralPannerDevice.defaults());

<BinauralPannerPanel onValueChange={setState} value={state} />;

Engine

Create it, connect it and update it as for any device: see The engine.

The panner runs on the audio thread: the binaural panner of @audio/spatial-binaural, the structural model of Brown and Duda, in an AudioWorklet loaded from a blob (BINAURAL_PANNER_WORKLET is its source), 128 frames at a time. It folds the sound to mono, delays the far ear as a round head would, and shades it with a one-pole filter, smoothing a change of direction so it does not click. Its delay line is made for the largest head, so the head can change while it plays, and a direction is sent as the angle nearest the last, so a turn across the back goes the short way round. A worklet cannot import, so the device carries the kernel as published (BINAURAL_PANNER_KERNELS, in its kernels.ts). Until it is ready, and in a context with no worklets, the sound passes clean: ready resolves once it is in the graph.

Built by Ouest Labs, the source code is available on GitHub.
RSS