Generate a waveform image with FFmpeg
showwavespic draws the whole file into a single picture. The commands below produce a transparent PNG, a two-colour stereo version, a dark solid background and a spectrogram, each checked with ffprobe.
Verified with FFmpeg 9.0.1 on 26 August 2026. Search intent: ffmpeg waveform image.
ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1280x240:colors=#21B4CE" -frames:v 1 waveform.pngReads the audio, draws its amplitude over time into a 1280x240 image and writes one PNG. The background is transparent (the output pixel format is rgba), so the waveform can sit on any page.
Flags, explained
- showwavespic=s=1280x240
- Output size. Each column summarises the samples that fall into it, so width sets the time resolution.
- colors=#21B4CE
- Trace colour, hex or named. Several values separated by | are used per channel.
- split_channels=1
- Draw each channel in its own band instead of overlapping them.
- scale=sqrt
- Amplitude scale: lin (default), log, sqrt or cbrt. Non-linear scales make quiet audio visible.
- draw=full:filter=peak
- Fill the shape and use peak values per column rather than averages.
- -frames:v 1
- Write a single image. showwavespic emits one frame anyway; the flag makes the intent explicit.
- -filter_complex
- Required because the filter turns audio into video; -af cannot change the media type.
Variants
One colour per channel
ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1280x240:colors=#21B4CE|#E0489B:split_channels=1" -frames:v 1 waveform.pngsplit_channels stacks the left and right channels; colors takes a | separated list, one per channel.
Solid dark background
ffmpeg -i input.mp3 -filter_complex "color=c=#17181C:s=1280x240[bg];[0:a]showwavespic=s=1280x240:colors=#F2C93B[w];[bg][w]overlay=format=auto,format=rgb24" -frames:v 1 waveform.pngGenerates a flat colour canvas and overlays the waveform on it; format=rgb24 drops the alpha channel, which you need before saving as JPEG.
From a video, mono, square-root scale
ffmpeg -i input.mp4 -filter_complex "[0:a]aformat=channel_layouts=mono,showwavespic=s=1280x240:colors=white:scale=sqrt" -frames:v 1 waveform.pngWorks on the audio track of a video. Mixing to mono gives one trace; scale=sqrt lifts quiet passages so speech does not look flat.
Peaks instead of averages
ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1280x240:colors=#21B4CE:draw=full:filter=peak" -frames:v 1 waveform.pngfilter=peak keeps the loudest sample of each column, draw=full fills the shape. Closer to what audio editors show.
Spectrogram instead of a waveform
ffmpeg -i input.mp3 -filter_complex "showspectrumpic=s=1280x480:legend=0" -frames:v 1 spectrogram.pngFrequency over time as a heat map, 1280x480 rgb24. legend=0 removes the axis labels.
Pitfalls we hit
- The default background is transparent (rgba). Some viewers render that as black, and JPEG cannot store it: overlay on a colour and convert to rgb24 first.
- Steady tones draw as a flat band; the test tone at -16 dBFS filled a thin stripe. Real speech or music shows the envelope you expect.
- Linear scale hides quiet material. Podcasts normalised to -16 LUFS look small at scale=lin; use sqrt or log.
- Very long files are downsampled to the image width: a 2 h recording in 1280 columns averages about 5.6 s per pixel. Increase the width or trim the input.
- -af showwavespic fails because the filter outputs video; use -filter_complex or -lavfi.
How we verified it
Run with FFmpeg 9.0.1 on 26 August 2026 against a 12 s 48 kHz MP3 and a 12 s H.264/AAC video. Primary command: PNG 1280x240 rgba, 1,946 bytes. split_channels: 1280x240 rgba. Dark background variant: 1280x240 rgb24. Video input, mono, sqrt: 1280x240 rgba. draw=full:filter=peak: 1280x240 rgba. showspectrumpic: 1280x480 rgb24, 43,595 bytes. The same command without -frames:v 1 produced the same single PNG.
The same edit as a typed operation
generate_audio_waveform takes a width, a height and a colour, accepts audio or video input, and returns a transparent PNG through a signed URL. No filter graph to assemble and no pixel format to remember.
{
"inputs": [{ "id": "main", "url": "https://example.com/podcast.mp3" }],
"options": { "width": 1280, "height": 240, "color": "#C4FF4C" }
}FAQ
Is the waveform image transparent?
Yes by default: showwavespic writes rgba with a transparent background. Overlay it on a colour source and convert to rgb24 when you need an opaque image or a JPEG.
Can I draw the waveform of a video file?
Yes. Reference the audio stream with [0:a] in -filter_complex, as in the video variant; the picture is ignored.
Why does my waveform look flat?
Either the audio is quiet on a linear scale or it is a steady tone. Use scale=sqrt or scale=log, and check the file with ebur128 to see its actual level.
How do I get a spectrogram instead?
Replace showwavespic with showspectrumpic, which maps frequency over time to colour. The variant above renders a 1280x480 image without axis labels.
Related commands
- ffmpeg extract audioExtract audio from a video with FFmpegRead
- ffmpeg normalize audioNormalize audio loudness with FFmpegRead
- ffmpeg video to gifConvert a video to GIF with FFmpegRead