Audio UI
A monophonic analog synth, for basses, leads and acid lines. An oscillator (a saw, a square of any width or a triangle), a square sub oscillator an octave down and noise are mixed into a resonant low-pass filter, which an envelope opens along with the level. It plays one note at a time: a note played while another is held glides to it. Start from one of its eight presets (Init Saw, Warm Pad, Acid Bass, Pluck, Brass, Sub Bass, Lead, Wind), 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/mono-synth
It installs the device's state, its engine and its panel to components/audio-ui/devices/mono-synth/. The demo above, which wires them to a loop, is @audio-ui/block-mono-synth.
Controls
Every number reads 0 to 10, as a panel's sliders do, and shows the value it sets in the unit the sound takes.
Controls · 18
Panel
The panel loads a preset from the menu in its title bar, beside the oscillator's wave and the range, lays the other controls out by what they do (oscillators, filter, envelope, pitch, output) and has a keyboard of two octaves that plays the synth. monoSynthPreset(name) gives a preset's whole state, and MONO_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 { MonoSynthPanel } from "@/components/audio-ui/devices/mono-synth/panel";
import { monoSynthDevice } from "@/components/audio-ui/devices/mono-synth/device";
const [state, setState] = useState(() => monoSynthDevice.defaults());
<MonoSynthPanel onValueChange={setState} value={state} />;Engine
Create it, connect it and update it as for any device: see The engine.
engine.noteOn({ frequency: 110, velocity: 0.8 }, { id: "a2" }); // the envelope opens
engine.noteOn({ frequency: 165 }, { id: "e3" }); // held: glides to it
engine.noteOff({ id: "e3" }); // glides back to A2, still held
engine.noteOff({ id: "a2" }); // the last one: fades over the releaseThe engine is the whole synth: give it every note, each with its own id, rather than one engine a note. The first note opens the amplifier and the filter along the envelope. A note played while one is held glides the pitch to it over the glide and leaves the envelope as it is; let go of it, and the pitch glides back to the note still held. Once every note is let go, both fall back over the release from where they had got to, so a short note never clicks. A noteOff with no id lets every note go. Notes take a time of the audio clock, { at, id }, for a host that schedules ahead, and the arrangement's engine gives a MIDI track's notes to the one engine. Every control moves with a ramp, a held note included. An agent plays the synth with the play tool.