Skip to content
VoiceAudio levelMenu

Audio level

A Web Audio level meter for a microphone stream or a media element: a perceptual level and log-spaced frequency bands for orbs, waveforms and visualizers.

Pick a state and the orb morphs into it. Simulated voices, or your microphone.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/use-chatcn-audio-level.json

Usage

tsx
import { useChatcnAudioLevel } from "@/hooks/use-chatcn-audio-level"
import { useChatcnMicrophone } from "@/hooks/use-chatcn-voice-devices"

const mic = useChatcnMicrophone()
const meter = useChatcnAudioLevel(mic.stream, { updateRate: 0 })

<button onClick={mic.start}>Use microphone</button>
<VoiceOrb state="listening" level={meter.getLevel} />

Pass a MediaStream (microphone, WebRTC remote track) or an <audio> or <video> element. getLevel and getBands are cheap enough to call every frame. The level state updates updateRate times a second for components that take a number; set it to 0 to skip re-renders entirely.

Bands

tsx
const output = useChatcnAudioLevel(audioRef.current, { updateRate: 0 })

<AudioVisualizer variant="bars" bands={output.getBands} />

Without a microphone

useChatcnSimulatedLevel(speaking) returns the same getters, driven by a speech model (syllables, gaps between words, a phrase contour), so demos and tests look like someone talking. useChatcnVoiceMock drives a whole scripted call.

Options

OptionDefaultNotes
updateRate20Hz for the level and bands state. 0 disables state
bands0Band count for the bands state. getBands(n) works regardless
floorDb, ceilingDb-60, -12dBFS mapped onto 0 and 1
attack, release30, 7Envelope rates per second: snappy rise, gentle fall
frequencyRange[80, 8000]Hz range of the bands, the speech range by default

Returns

ValueTypeNotes
levelnumberSmoothed level, throttled to updateRate
bandsnumber[]Throttled band levels when bands is set
getLevel() => numberCurrent level. One computation per frame however many readers
getBands(count) => Float32ArrayLog-spaced bands, lowest first
activebooleanA source is connected and the audio context runs
errorError | undefinedFor example a cross-origin media URL without CORS

Notes

  • One shared AudioContext serves every meter. Browsers may start it suspended; it resumes on the next pointer or key press, and when a metered element plays.
  • A media element can be routed through Web Audio only once. The hook caches that route per element and keeps the element audible.
  • useChatcnMicrophone stops every track on stop and unmount, so the browser's recording indicator goes away when it should. Its errors come with messages that say how to fix them.