Mixer

A mixing console: tracks with pan, fader, meter, mute and solo into a master with a stereo meter, every meter reading the real signal of its channel.

Audio UI

A channel strip per track and a master, built from the Knob, Fader and Meter, and run on the Web Audio API alone: each strip is a few nodes, and each meter reads an AnalyserNode, not a number made up for the picture.

Installation

pnpm dlx shadcn@latest add @audio-ui/block-mixer

Signal path

Each channel is a chain of four nodes into the master bus:

input → fader (GainNode) → mute (GainNode) → panner (StereoPannerNode) → master
                                  └→ AnalyserNode → its meter
  • The fader is in dB, from silent at the bottom to +6 dB, and sets the node's gain as 10 ** (db / 20). It moves the gain with setTargetAtTime, so dragging it does not click.
  • Mute and solo go through their own gain, not through the fader, so un-muting returns to where the fader was. A track is audible when it is not muted and either it is soloed or nothing is: a muted track stays silent even if soloed.
  • The meter taps the channel after its fader and its mute, before the pan: it shows what reaches the mix.
  • The master's meter reads its two sides through a ChannelSplitterNode, ahead of the bus's safety limiter. The bus is the one every block shares (use-master-bus).

The analysers are never connected to ctx.destination, so reading a level plays nothing.

Meters

A meter takes a live source, so a channel costs no React render per frame. useAudioLevels makes one from the analysers of a channel:

import { Meter } from "@/components/audio-ui/meter";
import { useAudioLevels } from "@/hooks/use-audio-levels";

const levels = useAudioLevels(analysers); // memoize the array: a new one restarts sampling

<Meter aria-label="Drums level" peakMarks="hidden" source={levels} />;

The level is the RMS of the time-domain samples in dB. It rises at once and falls back at 30 dB a second, so a drum hit reads as a hit and does not flicker. Nothing is published while the signal is silent. The hooks a mixer plays through are in the Audio engine: Output for the master bus, Clock and time for the transport clock and Analysis for the levels.

Playing your own sources

The block plays a small loop of its own, so it sounds on first load. To mix your own tracks, connect each source to the input node of a channel instead of to the destination, and drop the loop. A channel's nodes are created once, with the shared context, and its fader, mute and pan are driven from state with setTargetAtTime.

Accessibility

Every control is a native input behind its own role: the pan is a slider named "Drums pan" and the volume "Drums volume", and mute and solo are toggle buttons, "Mute Drums" and "Solo Drums". A strip is a group with the track's name, so a screen reader reads "Drums, group" then each control, and tabbing goes pan, volume, mute, solo, then the next track. The faders and knobs take the arrow keys, Home and End.

More Shadcn Mixer components

Browse 1 production-ready audio/ui Mixer components for players, mixers, and synth interfaces. These examples use the headless primitives from @audio-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.

Browse all 1 Shadcn Mixer components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.

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