A real-time audio visualizer that runs in the terminal. Built with Rust using cpal for audio capture and ratatui for rendering. A companion Swift binary handles system audio capture via ScreenCaptureKit, so you can visualize whatever’s playing on your Mac — Apple Music, Spotify, YouTube, anything.
Four visualization modes: spectrum bars with logarithmic frequency binning, a waveform plot, a zero-crossing-triggered oscilloscope, and a stereo mode that mirrors left and right channels above and below a center line. Press m to cycle through them.
The spectrum uses a dual-resolution FFT — 4096-point for bass below 200Hz (~11.7Hz bin spacing), 2048 samples zero-padded to 4096 for mids and highs (better time resolution). Logarithmic frequency binning gives more resolution in the bass, less in the treble. An equalizer curve compensates for natural 1/f roll-off so highs don’t disappear. Bars have gravity-based fall-off — they snap up instantly but fall with acceleration, giving a natural decay feel. An auto-sensitivity system with fast attack and slow multiplicative recovery normalizes the display so it uses the full height regardless of volume.
Features
- Spectrum — frequency bars with 1/8th-cell precision via Unicode block characters, color gradient interpolation, and gravity
- Waveform — amplitude plot drawn as line segments on a canvas
- Oscilloscope — zero-crossing triggered waveform for stable display
- Stereo — dual-channel bars growing up (left) and down (right) from center, with half-cell precision
![]() | ![]() |
![]() | ![]() |
- 7 themes — classic, fire, ocean, purple, matrix, synthwave, mono
- Settings menu — smoothing, monstercat envelope, noise gate, gradient mode, sensitivity — all persisted to
~/.config/termwave/config.toml - Sensitivity control — adjustable sensitivity percentage displayed in the title bar, useful for fine-tuning the display for different volume levels
- Device switching — swap between mic input and system audio at runtime
- Monstercat smoothing — connects bar tops in a smooth curve with exponential falloff
- Now playing — shows the currently playing Apple Music track in the status bar, polled every 3 seconds via AppleScript
- Bar customization — adjustable bar width (1–8 columns) and spacing (0–4 columns) via settings menu or CLI flags
Architecture
Two-process design. The Rust binary handles everything visual: CLI parsing, FFT analysis, smoothing, and terminal rendering at 60fps. The Swift binary (termwave-tap) only captures system audio — it uses ScreenCaptureKit to grab the system audio stream, mixes to mono, and writes raw f32 samples to stdout. The Rust side spawns it as a subprocess and reads from its stdout.
Audio data flows through shared ring buffers (Arc<Mutex<Vec<f32>>>) — one mono buffer for spectrum/wave/scope modes, plus a stereo pair for the stereo visualization. The render thread reads these each frame, runs the FFT, bins and smooths the results, and draws.
Key bindings
| Key | Action |
|---|---|
m | Cycle mode |
d | Select audio device |
t | Select color theme |
s | Settings menu |
Up / Down | Increase / decrease sensitivity |
Right / Left | Wider / narrower bars |
? | Help |
q / Esc | Quit |



