Audio UI
Spins the sound in a rotary speaker, the cabinet of an organ: the highs come from a horn and the lows from a drum, both turning, so the sound sweeps its pitch and its level past the microphones. Switch from Slow to Fast and the rotors wind up, the light horn first, the heavy drum after it. It is a device: a state, a panel, an engine and tools, each its own file.
Installation
pnpm dlx shadcn@latest add @audio-ui/rotary
It installs the device's state, its engine and its panel to components/audio-ui/devices/rotary/. The demo above, which wires them to a loop, is @audio-ui/block-rotary.
Controls
Controls · 8
Panel
The panel draws the drum's band, dashed, and the horn's, split at the crossover, over its speed and its knobs. rotaryBands(state) is what it draws.
import { RotaryPanel } from "@/components/audio-ui/devices/rotary/panel";
import { rotaryDevice } from "@/components/audio-ui/devices/rotary/device";
const [state, setState] = useState(() => rotaryDevice.defaults());
<RotaryPanel onValueChange={setState} value={state} />;Engine
Create it, connect it and update it as for any device: see The engine.
The cabinet runs on the audio thread: the rotary of @audio/effect-rotary in an AudioWorklet loaded from a blob (ROTARY_WORKLET is its source), 128 frames at a time. It splits the sound with a fourth-order Linkwitz-Riley crossover, which sums back to flat, then each rotor turns its band through a delay that sweeps its pitch and a gain that sweeps its level, heard by two microphones. The cabinet is mono: it takes both channels together and gives the two microphones. A worklet cannot import, so the device carries the rotary and the modules it is built from as published, the crossover of @audio/eq-crossover, the Butterworth design of digital-filter and the sections of @audio/biquad (ROTARY_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.