Nodes/dotWaveform/Dotted Waveform Visualizer
ComfyUI Node

Dotted Waveform Visualizer

Turn Any Audio Into a Synced Dot Waveform Video — No Diffusion, No VRAM

By Saganaki22·Created about a year ago·Updated 5 months ago· 33
Dotted Waveform Visualizer
  • audio
  • images
  • audio
  • fps_output
width1280
height720
size6
spacing3
dot_color#00FFFF
background_color#000000
animation_style
max_height60
fps10
max_frames300
opacity_modeuniform
gradient_enabledfalse
gradient_stops[]
amplitude_boost1.0
advanced_modefalse
window_size2.0
preview_modefalse

You just generated the perfect TTS voiceover - and now you're staring at a silent black timeline wondering what to show while it plays. That's the hole this node fills. Dotted Waveform Visualizer is a small, deterministic utility from the dotWaveform pack that turns any audio file into an animated, dot-based waveform you can render straight to GIF or MP4. No diffusion models, no sampling, no VRAM pressure. Feed it audio, get back a frame sequence that dances in time with it.

It's the lightweight end of the audio-reactive spectrum, and the launch thread on r/StableDiffusion pitched it that way on purpose. The heavyweight alternative - RyanOnTheInside's audio-reactive node suite - can split tracks, read MIDI, and drive whole workflows off amplitude, but it's a much steeper learning curve. This one does one thing, visibly, and gets out of the way. If all you want is a clean waveform visual to pair with a voice clip, that's the reach-for.

How it works

The node takes a ComfyUI AUDIO object (a waveform tensor plus its sample rate), splits it into frames at your chosen fps, and measures each frame's RMS amplitude. For spectrum and bars it runs an FFT with a Hanning window and normalizes a handful of frequency bands - the music-equalizer look, bass left, treble right. Then it draws dots onto plain PIL canvases and concatenates the frames into one batched IMAGE tensor. The whole thing runs on CPU; your GPU never wakes up.

Seven animation styles ship: scrolling, breathing, radial, bars, wave, spectrum, and circular. Each maps that same amplitude data onto the canvas differently - radial expands rings outward, circular grows a ring of dots, breathing pulses everything uniformly. A real FFT drives the frequency-based ones; the rest are pure amplitude.

The inputs that matter

  • animation_style - the one you'll actually change between projects. Everything else is polish.
  • max_height - waveform height as a percentage of image height (5–150). Crank it for drama, drop it for a subtle bottom strip.
  • fps and max_frames - 10 fps / 300 frames is about 30 seconds of output. The max_frames cap exists precisely so a long podcast doesn't hang your session rendering thousands of frames (0 = unlimited). Set it.
  • size and spacing - dot diameter and gap. Smaller spacing = denser waveform.
  • dot_color / background_color - hex strings (#00FFFF on black by default).
  • window_size - scrolling only; how many seconds of timeline are visible at once.
  • opacity_mode - uniform, 3_levels, 5_levels, or 10_levels; more levels = smoother trails, at a small speed cost.
  • preview_mode - swaps in a sine-wave stand-in so you can tune colors and style before processing real audio. Use it.

The optional gradient_enabled / gradient_stops and amplitude_boost (0.5–5.0x) come from the v2 UI - a visual gradient editor and color picker live in the JS frontend, and advanced_mode gates the boost (defaults to 1.0 when off). Headless users get these as widget values, gradient_stops as a JSON string.

The outputs

Three of them, and all get used: images (the IMAGE batch), audio (your audio passed through - actually improved), and fps_output (a FLOAT).

That passthrough is the clever part. The node force-converts the audio to float32 and, if it's mono, duplicates it to stereo - because VideoHelperSuite's VHS_VideoCombine expects stereo. So the canonical workflow is: TTS node → this → VHS_VideoCombine, with fps_output wired into VideoCombine's frame rate. The example workflow in the repo is exactly that (the AnimateDiff filename prefix is a leftover from a prior life; no AnimateDiff involved).

Installing it

ComfyUI Manager, search "dotWaveform", install, restart. Or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/Saganaki22/ComfyUI-dotWaveform
pip install -r requirements.txt
# restart ComfyUI

No model downloads - it's pure code. The catch is the dependency list: torchaudio, librosa, and scipy on top of what ComfyUI already ships. librosa pulls in numba and is a chunky install, and here's the quirk: the node imports it but never actually calls it. Still a hard dependency - if it's missing, the node won't load - but effectively dead weight on the clock. Budget a few extra minutes for the first install.

Where people get burned

  • Long audio hangs - the default max_frames of 300 is your friend. Raise fps or forget the cap on a 20-minute file and you'll be waiting a while.
  • Console spam from VHS - the code has a whole fallback ladder for LazyAudioMap (VideoHelperSuite's lazy audio wrapper). It usually succeeds, but it's chatty; a wall of "Method 3 (dict key)…" prints is normal, not an error.
  • Don't expect beat-mapped parameter control - the top comment on the release thread was someone asking to drive other nodes off the amplitude. That isn't built in; for that level of reactivity you want RyanOnTheInside's suite instead.

For a fast, deterministic "voice clip gets a visual" node, this is a tidy pick - deliberately simple, with a growing bug-fix log (2.2.0) rather than a feature parade. It renders, passes audio through cleanly, and it's one of the few nodes you can add to a workflow without worrying about your GPU or your registry.

Categoryaudio/visualization

Inputs (18)

NameTypeDefaultDescription
audioAUDIOAudio file to create waveform visualization from
widthINT1280100–1920Output image width in pixels. Default 1280 (landscape HD). Max 1920 for Full HD.
heightINT720100–1920Output image height in pixels. Default 720 (landscape HD). Max 1920 for square/portrait.
sizeINT61–30Size of individual dots/bars in pixels. Larger size = bolder appearance. Range: 1-30px.
spacingINT31–40Distance between dot/bar centers. Smaller values = denser waveform. Range: 1-40px.
dot_colorSTRING#00FFFFHex color for waveform dots. Examples: #00FFFF (cyan), #FF0000 (red), #00FF00 (green), #FFFFFF (white)
background_colorSTRING#000000Hex color for background. Examples: #000000 (black), #FFFFFF (white), #333333 (dark gray)
animation_styleCOMBOChoose animation style. SCROLLING: Continuous waveform. BREATHING: Pulsing dots. RADIAL: Expanding rings. BARS: Frequency bars. WAVE: Sine wave patterns. SPECTRUM: FFT frequency analyzer. CIRCULAR: Rotating circle.
max_heightINT605–150Maximum waveform size as % of image height. Higher = taller waveforms. Affects all animation styles including radial radius.
fpsINT101–60Animation speed in frames per second. Higher FPS = smoother but larger file size. Range: 1-60 FPS.
max_framesINT3000–1000Frame limit to prevent hangs on long audio. 0 = unlimited. 300 frames ≈ 30 seconds at 10 FPS.
opacity_modeCOMBOuniformUNIFORM: All dots same brightness (fastest). 3_LEVELS: 0%/50%/100% opacity. 5_LEVELS: More variation. 10_LEVELS: Smoothest gradients (densest look).
gradient_enabledoptBOOLEANfalse
gradient_stopsoptSTRING[]
amplitude_boostoptFLOAT1.00.5–5
advanced_modeoptBOOLEANfalse
window_sizeoptFLOAT2.00.1–10SCROLLING ONLY: Time window in seconds. How much audio timeline visible at once. Smaller = more detailed, larger = more overview.
preview_modeoptBOOLEANfalseToggle ON for fast preview with sine wave pattern (no audio processing). Toggle OFF for normal audio-based animation.

Outputs (3)

NameTypeDescription
imagesIMAGEGenerated waveform animation frames as image sequence
audioAUDIOOriginal audio data passed through unchanged
fps_outputFLOATActual frames per second value used for the animation