--- name: audio-visualization description: Audio visualization patterns - spectrum bars, waveforms, bass-reactive effects metadata: tags: audio, visualization, spectrum, waveform, bass, music, audiogram, frequency --- # Audio Visualization in Remotion ## Prerequisites ```bash npx remotion add @remotion/media-utils ``` ## Loading Audio Data Use `useWindowedAudioData()` (https://www.remotion.dev/docs/use-windowed-audio-data) to load audio data: ```tsx import { useWindowedAudioData } from "@remotion/media-utils"; import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ src: staticFile("podcast.wav"), frame, fps, windowInSeconds: 30, }); ``` ## Spectrum Bar Visualization Use `visualizeAudio()` (https://www.remotion.dev/docs/visualize-audio) to get frequency data for bar charts: ```tsx import { useWindowedAudioData, visualizeAudio } from "@remotion/media-utils"; import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ src: staticFile("music.mp3"), frame, fps, windowInSeconds: 30, }); if (!audioData) { return null; } const frequencies = visualizeAudio({ fps, frame, audioData, numberOfSamples: 256, optimizeFor: "speed", dataOffsetInSeconds, }); return (
{frequencies.map((v, i) => (
))}
); ``` - `numberOfSamples` must be power of 2 (32, 64, 128, 256, 512, 1024) - Values range 0-1; left of array = bass, right = highs - Use `optimizeFor: "speed"` for Lambda or high sample counts **Important:** When passing `audioData` to child components, also pass the `frame` from the parent. Do not call `useCurrentFrame()` in each child - this causes discontinuous visualization when children are inside `` with offsets. ## Waveform Visualization Use `visualizeAudioWaveform()` (https://www.remotion.dev/docs/media-utils/visualize-audio-waveform) with `createSmoothSvgPath()` (https://www.remotion.dev/docs/media-utils/create-smooth-svg-path) for oscilloscope-style displays: ```tsx import { createSmoothSvgPath, useWindowedAudioData, visualizeAudioWaveform, } from "@remotion/media-utils"; import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; const frame = useCurrentFrame(); const { width, fps } = useVideoConfig(); const HEIGHT = 200; const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ src: staticFile("voice.wav"), frame, fps, windowInSeconds: 30, }); if (!audioData) { return null; } const waveform = visualizeAudioWaveform({ fps, frame, audioData, numberOfSamples: 256, windowInSeconds: 0.5, dataOffsetInSeconds, }); const path = createSmoothSvgPath({ points: waveform.map((y, i) => ({ x: (i / (waveform.length - 1)) * width, y: HEIGHT / 2 + (y * HEIGHT) / 2, })), }); return ( ); ``` ## Bass-Reactive Effects Extract low frequencies for beat-reactive animations: ```tsx const frequencies = visualizeAudio({ fps, frame, audioData, numberOfSamples: 128, optimizeFor: "speed", dataOffsetInSeconds, }); const lowFrequencies = frequencies.slice(0, 32); const bassIntensity = lowFrequencies.reduce((sum, v) => sum + v, 0) / lowFrequencies.length; const scale = 1 + bassIntensity * 0.5; const opacity = Math.min(0.6, bassIntensity * 0.8); ``` ## Volume-Based Waveform Use `getWaveformPortion()` (https://www.remotion.dev/docs/get-waveform-portion) when you need simplified volume data instead of frequency spectrum: ```tsx import { getWaveformPortion } from "@remotion/media-utils"; import { useCurrentFrame, useVideoConfig } from "remotion"; const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const currentTimeInSeconds = frame / fps; const waveform = getWaveformPortion({ audioData, startTimeInSeconds: currentTimeInSeconds, durationInSeconds: 5, numberOfSamples: 50, }); // Returns array of { index, amplitude } objects (amplitude: 0-1) waveform.map((bar) => (
)); ``` ## Postprocessing Low frequencies naturally dominate. Apply logarithmic scaling for visual balance: ```tsx const minDb = -100; const maxDb = -30; const scaled = frequencies.map((value) => { const db = 20 * Math.log10(value); return (db - minDb) / (maxDb - minDb); }); ```