Lab

String machine

A string machine device: a violin, a viola, a cello and a bass register, a brightness filter, a slow bow and an ensemble, with eight presets, a panel with a keyboard, a Web Audio engine and tools for agents.

Audio UI

A string machine. Every key sounds four registers, a violin and a viola at its pitch, a cello an octave down and a bass two, each at its own level. The sum bows in slowly and lets go slowly, through a brightness filter, then an ensemble: three delay lines swayed by three slow oscillators a third of a turn apart, which thicken the sound as a section of players does. Start from one of its eight presets (Strings, Violins, Cellos, Full, Swell, Pizz, Dark, Choir), 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/string-machine

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

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 · 9

Panel

The panel loads a preset from the menu in its title bar, lays the other controls out by what they do (registers, tone, bow, output) and has a keyboard of two octaves that plays the machine. stringMachinePreset(name) gives a preset's whole state, and STRING_MACHINE_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 { StringMachinePanel } from "@/components/audio-ui/devices/string-machine/panel";
import { stringMachineDevice } from "@/components/audio-ui/devices/string-machine/device";

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

<StringMachinePanel 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 }); // bows a note in
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, through its own ensemble. 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 bows in over its attack and lets go over the release from where it had got to, so a short note never clicks; a harder key leans on the level a little, as a bow does. A note while one is held cuts it and bows anew, and a noteOff whose id is not the held note's lets nothing go. A register's level and the brightness move a held note. An agent plays the machine with the play tool.

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