Audio UI
An eighties polyphonic synth. Four sources (a saw, a pulse of any width, a sub oscillator an octave down and noise) are mixed into a resonant low-pass filter, which an envelope opens along with the level, and a vibrato and a stereo chorus finish the sound. Start from one of its eight presets (Brass, Strings, Soft Pad, Pluck, Fat Bass, Organ, Sweep, Glass Lead), then shape 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/poly-synth
It installs the device's state, its engine and its panel to components/audio-ui/devices/poly-synth/. The demo above, which wires them to a loop, is @audio-ui/block-poly-synth.
Controls
Every control reads 0 to 10, as a panel's sliders do, and shows the value it sets in the unit the sound takes.
Controls · 17
Panel
The panel loads a preset from the menu in its title bar, beside the chorus switch, lays the other controls out by what they do (oscillators, filter, envelope, vibrato, output) and has a keyboard of two octaves that plays the synth. polySynthPreset(name) gives a preset's whole state, and POLY_SYNTH_PRESETS lists them. With activeNotes, the notes held now, such as on a MIDI keyboard, light up their keys. The panel sends notes out and does not make the sound, so it plays through any engine.
import { PolySynthPanel } from "@/components/audio-ui/devices/poly-synth/panel";
import { polySynthDevice } from "@/components/audio-ui/devices/poly-synth/device";
const [state, setState] = useState(() => polySynthDevice.defaults());
<PolySynthPanel onValueChange={setState} value={state} />;Engine
Create it, connect it and update it as for any device: see The engine.
engine.noteOn({ frequency: 261.63, velocity: 0.8 }); // a note now, or the held one glides to it
engine.noteOff(); // lets it go, over the release
// Scheduled ahead on the audio clock, by a host that plays notes from a song:
engine.noteOn({ frequency: 440 }, { at: time, id: "a4" });
engine.noteOff({ at: time + length, id: "a4" });An engine plays one voice. For chords, make as many as the notes you hold and give each note its own: the arrangement's engine does it for a MIDI track, and the block above keeps eight. A note rises over its attack, then settles at its sustain; the filter opens by the envelope amount on the same curves. Let go, both fall back over the release from where they had got to, so a short note never clicks. A noteOff whose id is not the held note's lets nothing go. Every control moves with a ramp, and a held note follows the ones that shape it. An agent plays the synth with the play tool.