Audio UI
Moves every frequency of the sound by the same number of hertz. A pitch shift multiplies frequencies and keeps a note's harmonics in line; a frequency shift adds to them, so they stop lining up: a few hertz make a slow phasing, more make the sound metallic and strange. In Ring mode it multiplies the sound by a sine instead, leaving the sum and the difference of each frequency and the sine's, the bell of a ring modulator. It is a device: a state, a panel, an engine and tools, each its own file.
Installation
pnpm dlx shadcn@latest add @audio-ui/frequency-shifter
It installs the device's state, its engine and its panel to components/audio-ui/devices/frequency-shifter/. The demo above, which wires them to a loop, is @audio-ui/block-frequency-shifter.
Controls
Controls · 6
Panel
The panel draws what the device does to a 220 Hz note and its harmonics: the frequencies that go in, faint, and the ones that come out. frequencyShifterPartials(state) is what it draws.
import { FrequencyShifterPanel } from "@/components/audio-ui/devices/frequency-shifter/panel";
import { frequencyShifterDevice } from "@/components/audio-ui/devices/frequency-shifter/device";
const [state, setState] = useState(() => frequencyShifterDevice.defaults());
<FrequencyShifterPanel onValueChange={setState} value={state} />;Engine
Create it, connect it and update it as for any device: see The engine.
The shifter runs on the audio thread: the frequency shifter of @audio/effect-freqshift, a Hilbert filter that turns the sound into its analytic signal and turns it like a wheel, and the ring modulator of @audio/effect-ringmod, in an AudioWorklet loaded from a blob (FREQUENCY_SHIFTER_WORKLET is its source), 128 frames at a time. Each mixes the clean sound in itself, the shifter's delayed as long as its filter, so the mix never combs. The worklet plays both modes, one output each, and the mode fades one in and the other out. A worklet cannot import, so the device carries both kernels as published (FREQUENCY_SHIFTER_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.
The shift delays the sound by half its filter's length, which is the latency of the device: 32 samples at Mid. The ring has none.