Skip to main content

Chat bubbles and list rows

Voice messages show a few dozen bars, often many at once in a list. They need a fast analysis, little memory, and bars that follow the voice rather than the loudest click.

Presets​

import { StyleSheet, View } from 'react-native';
import { useWaveform, waveformPresets } from 'react-native-audio-analyzer';

export function VoiceMessageWaveform({ url }: { url: string }) {
const { bars } = useWaveform(url, { ...waveformPresets.chat, barCount: 40 });
return (
<View style={styles.row}>
{(bars ?? []).map((value, index) => (
<View key={index} style={[styles.bar, { height: Math.max(3, value * 32) }]} />
))}
</View>
);
}

const styles = StyleSheet.create({
row: { height: 32, flexDirection: 'row', alignItems: 'center', gap: 2 },
bar: { width: 3, borderRadius: 1.5, backgroundColor: '#5B4CF0' },
});
12 seconds of speech with waveformPresets.chat: phrases and pauses are easy to tell apart.
useWaveform(url, { ...waveformPresets.chat, barCount: 40 })

waveformPresets.chat is just an object:

{
analysis: { maxBuckets: 1_000 }, // ~12 KB of data, fast
metric: 'rms', // follows the voice
normalize: { scale: 'linear', percentile: 0.99 }, // ignore the loudest 1%
}
PresetFormaxBucketsmetricReference
chatvoice messages, list rows1 000rms99th percentile
playertrack overviews, scrubbers10 000rms99.5th percentile
editorprecise views, deep zoom100 000peakmaximum

Anything passed after the spread wins, so a preset is a starting point, not a mode:

useWaveform(url, { ...waveformPresets.chat, barCount: width / 5, metric: 'peak' });

barCount may be fractional; it is rounded down.

Why these settings​

The same message with other settings:

metric: 'peak' — bars follow the loudest sample, so speech looks denser and more uniform.
resample(peaks, 40, { metric: 'peak' })
scale: 'db' — quiet parts are lifted; good for quiet material, too flat for speech.
normalize(resample(peaks, 40), { scale: 'db', reference })
normalize: false — raw RMS levels of a normal recording use a fraction of the height.
resample(peaks, 40) // not normalized

See Metrics and scaling for the details.

Many rows​

Each useWaveform call analyzes its source once and keeps the result while mounted; a list of 50 voice messages with the chat preset holds about 600 KB of peaks. Downloads of the same URL are shared, and finished downloads are cached on disk, so scrolling back is fast. To keep results across remounts, store them with encodePeaks.