Decode once, render many
One native pass produces min, max and RMS per bucket. Bar count, zoom, metric and scale are cheap JS on top — no second decode.
Presets and every knob
waveformPresets.chat, .player and .editor are plain objects tuned for voice messages, scrubbers and precise views. Spread one, override anything.
Native and non-blocking
One C++ core on miniaudio for iOS and Android, on a background thread, with progress and AbortSignal cancellation. Works in Expo dev builds.
Correct by construction
Peaks are never dropped or drawn twice, RMS is frame-weighted, the scale stays stable when zooming. Tested against naive references under sanitizers.
Quick start
npm install react-native-audio-analyzer react-native-nitro-modules
import { useWaveform, waveformPresets } from 'react-native-audio-analyzer';
function VoiceMessage({ url }: { url: string }) {
const { bars } = useWaveform(url, { ...waveformPresets.chat, barCount: 40 });
return <Bars values={bars ?? []} />; // 40 numbers, 0…1
}